Jul 22

虽然 Fedora 作为服务器来用不是上佳的选择,不过拿来练手倒是上上之选。因为 Fedora 中的大多数 Web 服务除去安全性等方面需要多加注意之外,基本上属于即装即用型的。Fedora 上的 Web 服务器的搭建也有很多选择,而且都是一些非常成熟的组合。反正不能免俗,不妨选择最常用的 LAMP 组合作为 Web 服务器的基础。不过话说回来,物换星移,Fedora 19 以 MariaDB 替换了 MySQL,也算是必然趋势。尽管如此,这些对于普通用户的影响并不大,mysqld 还是那个 mysqld。 作为普通用户,这里主要介绍的是与 LAMP 服务器相关的一些应用。至于 LAMP 服务本身相关的网站开发、优化等内容,暂时没有时间也没有能力触及了。

下面主要的测试环境是 Fedora 19。其他环境中 Web 服务器安装大同小异,很容易自行调整。当然,在开始之前最好关掉 SELinux,具体来说

$ sudo nano -w /etc/sysconfig/selinux
SELINUX=disable

修改完之后需重启机器才能有效。为了免去重启机器,可执行

$ sudo setenforce 0

即可即时生效。

一、LAMP 的安装与测试

1. Apache 服务器的安装

Apache 是世界上非常流行的 Web 服务器软件之一,类似的还有lighttpd、Nginx、Tomcat 等。不过,Apache 功能强大,一直深受建站爱好者的喜爱。它的安装非常容易:

$ sudo yum install httpd

Apache 的配置文件位于 /etc/httpd 目录,其中 /etc/httpd/conf/httpd.conf 是其默认配置文件,默认虚拟主机的目录位于 /var/www/html,与 Apache 相关的 Web 应用的配置目录可能位于 /etc/httpd/conf.d/。下面启动 Apache 服务并让它随机器一起启动:

$ sudo service httpd start
$ sudo chkconfig httpd on

为了看看 Apache 有没有正常工作,先做一下本地测试。打开本地的网页浏览器,在地址栏输入 http://localhost。正常情况应该出现如下的页面:

2. MariaDB 数据库的安装

Linux 中的 SQL 数据库很多,例如 MariaDB(MySQL)、PostgreSQL、SQLite、Firebird 等。不过这里就只安装 MariaDB:

$ sudo yum install mariadb mariadb-server

MariaBD 服务的开启方法与 MySQL 一样:

$ sudo service mysqld start
$ sudo chkconfig mysqld on

实际上,MariaDB 的用法也与 MySQL 别无二致。例如,MariaDB 数据的默认账户是 root,它与 Linux 系统的 root 账户没有什么联系。通常,MariaDB 的默认账户是没有密码的,这对于数据库的管理来说是不安全的。给它设置一个密码,例如toor:

$ sudo mysqladmin -u root password toor

现在尝试在本地登录 MariaDB 数据库:

$ sudo mysql -u root -p

数据库一切正常。

3. 网页开发语言 PHP 的安装

网页开发语言众多,例如PHP、JSP、ASP等。不过在 Linux 下面,PHP 整合的相对好一些:

$ sudo yum install php

测试一下 PHP 是否正常工作?首先,在本地的 /var/www/html 目录新建如下的文件:

$ su -c 'echo > /var/www/html/info.php << EOF

<?php
    phpinfo();
?>
EOF'

接着,在本地浏览器的地址栏中输入 http://localhost/info.php。如果出现如下的页面,就说明 PHP 工作正常!

4. 整合Apache与PHP
 
具体的整合可能涉及到很多优化方面的内容,这里只谈非常常见的几点。
$ sudo nano -w /etc/httpd/conf/httpd.conf
先在
AddType application/x-gzip .gz .tgz
所在行的下面添加
AddType application/x-httpd-php .php .phtml
AddType applicatoin/x-httpd-php-source .phps
接着再将
   DirectoryIndex index.html
改为
    DirectoryIndex index.html index.htm index.php
修改完成后保存退出。
 
为了提升 PHP 安全性,可在 /etc/php.ini 中进行作如下设置
$ sudo nano -w /etc/php.ini
将下面这一行
disable_functions =
修改为:
disable_functions = phpinfo,passthru,exec,system,chroot,scandir,chgrp,chown,shell_exec,proc_open,proc_get_status,ini_alter,ini_alter,ini_restore,dl,pfsockopen,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server

5. 防火墙设置与 LAMP 的远程测试

Fedora 中默认防火墙的安全级别比较高,基本上关闭了所有的服务端口。为了让远程机器能够访问 LAMP 服务器,需要适当调整防火墙设置。Fedora 在程序菜单中提供了防火墙的图形界面工具,不过这里主要介绍防火墙的命令行设置方法。由于 iptables 的规则是有优先次序的,通常需要手动编辑 iptables 的配置文件 /etc/sysconfig/iptables。下面为了简单起见,直接清空防火墙的原先设置,完全重写了所有的 iptables 规则。因此,使用下面这些规则的时候要小心,例如与 SSH 相关的规则没有在里面。关于如何开启 SSH 端口,可自行查阅 iptables 规则的写法。

首先,停止所有的 iptables 服务:

$ sudo service iptables stop
清除所有的 iptables 规则表:
$ sudo iptables -F -t filter
$ sudo iptables -X
设定预设 iptables 规则:
$ sudo iptables -P INPUT DROP
$ sudo iptables -P OUTPUT ACCEPT
接受所有本地回环网络的数据:
$ sudo iptables -A INPUT -i lo -j ACCEPT
接受所有 Established 连接:
$ sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
设置 ICMP 服务(保证 
$ sudo iptables -A INPUT -p icmp -m limit --limit 1/s --limit-burst 10 -j ACCEPT
开启 Apache 服务的端口:
$ sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
开启 MariaDB 服务的端口:
$ sudo iptables -A INPUT -p tcp --dport 3306 -j ACCEPT
最后,保存所有 iptables 的规则并再次启动 iptables 服务
$ sudo service iptables save
$ sudo service iptables start

为了确认本地端口已经正常开启,请执行以下命令

$ netstat -nat

检查相应服务的端口是否被监听。如果一切正常的话,可以开始在远端主机测试 LAMP 服务器了。假设 LAMP 主机的 IP 地址为 ipaddr。首先测试 Apache 服务,打开网页浏览器,在地址栏输入 http://ipaddr 或者 http://ipaddr/info.php。如果出现图或中的页面,就说明 Apache 工作正常;接着测试 MariaDB 服务,请安装 MariaDB 的客户端,然后登录 MariaDB 主机进行测试:

$ sudo yum install mariadb
$ mysql -h http://ipaddr -u root -p
至此,LAMP 服务器的安装配置已经完成,后面将接着介绍它的应用。
Jul 20
我们知道 Gnu PG 是非常重要的加密工具,它可以帮助我们加密数据或者对使用的文件、文本进行签名以确保数据的真实性。Gnu PG 被广泛的应用于电子邮件传递、软件包打包等过程中。下面我们就来谈谈 Gnu PG 在 GIT 中的使用。
 
1、标签、提交等的签名
通常提交源码时,我们直接采用
$ git commit -m 'something added.'
对于这种提交方式,我们无法确认是否本人做了这些修改。为了防止这种情况发生,我们可以尝试
$ git commit -S <gpg-key-id> -m 'something added.' 
其中 <gpg-key-id> 就是用户的Gnu PG 的密匙ID。该命令执行时会提示用户输入该 <gpg-key-id> 的口令,随后对这次提交做了 GPG 签名,如此一来便可确信是本人做了这次递交。类似地情况也可运用到标签上来,例如
$ git tag v1.0 -s -u <gpg-key-id> -m 'tagged with important information.'
如果觉得每次手动指定 Gnu PG 密匙 ID 比较麻烦,可以通过下述方式自动指定
$ git config --global user.signingkey <gpg-key-id>
 
2、push/pull的口令缓存
我们在将版本库的修改同步到远程版本库时,通常需要输入账户与口令。如果版本库中有多次提交需要同步,那么账户、口令就需要输入多次。早期 GIT 版本库同步时,由于没有提供密码的缓存机制,为了免去重复输入账户名与口令,通常直接将密码明文的保存在.git/config文件之中。例如,
$ git remote add origin https://<username>:<password>@github.com/someone/repo
其中 <username> 与 <password> 就是账户与密码。很明显,以明文方式存储隐私信息是非常不可取的。因此新版的 GIT 中提供了新的办法,大体来说有两种:一、利用 git-credential;二、利用 ~/.netrc 或者 ~/.authinfo 等文件实现自动读取隐私信息。
 
credential 机制有点类似于 Gnu PG 代理,它能够缓存用户的密码,例如
$ git config --global credential.helper 'cache --timeout=3600'
如此设置之后,当我们输入完账户密码之后,GIT 就会缓存密码1个小时。实际上,credential 的机制还有好几个,有兴趣的朋友请自行阅读文档
$ man git-credential
 
另一方面,GIT 利用 ~/.netrc 等文件存取账户名与密码的方式与 ftp 的工作方式类似。例如,
$ cat ~/.netrc
machine github.com
  multilinetoken <hashnumber>
  login <username> password <password>
随后,我们便可以执行
$ git push origin master
此时 GIT 会自动读取 ~/.netrc 中账户信息将本地版本库修改同步远程端 GIT 服务器。这样一来,隐私信息的安全完全有赖于 ~/.netrc 文件权限了,通常,会对该文件的权限作如下设置
$ chmod 600 ~/.netrc
 
不过即使是这样,我们可能还是觉得安全性不够。例如用户登录电脑后有事需要离开一段时间,但没有及时开启密码屏保,这就难保 ~/.netrc 的信息不被泄漏。下面就来谈谈进一步的保密措施,那就是用 Gnu PG 加密 ~/.netrc 文件
$ gpg -o ~/.netrc.gpg -er <gpg-key-id> ~/.netrc
随后再对 GIT 做如下配置
$ git config --global credential.helper 'netrc -f ~/.netrc.gpg -d'
为了让 GIT 支持如上的修改,还需要开启 git-credential-netrc。在 Fedora 19 中,该文件位于 /usr/share/doc/git-<version>/contrib/credential/netrc 目录之中。需要将它置于 /usr/libexec/git-core 目录之下,并增加可执行权限
$ sudo cp /usr/share/doc/git-<version>/contrib/credential/netrc/git-credential-netrc /usr/libexec/git-core
$ sudo chmod +x /usr/libexec/git-core/git-credential-netrc
当然,用户也可以试试我的 Fedora 源中重新打包的 GIT。好了,现在再试试远程版本库的同步吧。
 
用 Gnu PG 加密 ~/.netrc 有个问题需要指出,那就是原先 ~/.netrc 的功能并不能被完全拓展到 ~/.netrc.gpg。换而言之,当我们执行 ftp 命令时,~/.netrc.gpg 并不能被解析。因此,我们需要适当分离 ~/.netrc 中内容以确保各个程序能够合理的工作。
 
3、版本库中文件的自动加密/解密
 
通常版本库中不太可能有什么隐私信息,不过随着很多人将 Linux 配置文件制成 GIT 版本库,隐私问题也就随之而来了。有些配置文件,例如 SSH 的私匙文件,再如 Emacs 的 GNUS 与 ERC 等,它们的密码有一部分只能以明文的方式保存的。如果将它们的配置发布到公开的 GIT 版本库中显然不是很合适。那么有没有办法将这些隐私文件以加密的形式保存到远程版本库,但本地工作目录中则仍以解密形式存在呢?答案仍是使用 GPG,主要是利用 GIT 的 filter 机制来配合 GPG 的使用。具体来说是这样的:
$ git config --local filter."gpg".smudge 'gpg -d --batch --no-tty -r <gpg-key-id>'
$ git config --local filter."gpg".clean 'clean = gpg -ea -q --batch --no-tty -r <gpg-key-id>'
$ git config --local diff."gpg".textconv decrypt
接着将需要将解密的文件名列表加入.gitattributes或者.git/info/attributes,例如
/path/to/id_rsa filter=gpg diff=gpg
/path/to/gnus.el filter=gpg diff=gpg
现在你可以尝试将id_rsa、gnus.el加入版本库了,当它们被加入到版本库时,GIT会利用 clean 所指定的方式进行加密。而当它被检出时,GIT 会调用 smudge 进行解密。需要注意的是,整个过程需要预先运行 gpg-agent。
 
用 GIT 管理配置文件的过程中,可能还会碰到一个特殊的文件需要加密,那就是 GIT 本身的配置文件。这个需求仍然与登录密码相关,最直接的例子就是 Github 的 token。很明显,直接加密整个 ~/.gitconfig 文件并不是很好的选择。这里提供一种方法,可以将需要加密的那部分配置分离出来。具体来说就是在 GIT 的配置文件中增加include部分,例如
$ git config --global include.path '~/.gitrepo'
并在 ~/.gitrepo 中加入与隐私相关的部分:
$ nano -w ~/.gitrepo
[github]
      username = <username>
      token = <hashnumber>
至于如何将 ~/.gitconfig、~/.gitrepo 纳入我们的配置文件版本库,这里就不多说。最后就是加密~/.gitrepo文件,这个非常简单。例如,~/.gitrepo 在版本库中的名字gitrepo,下面只需要再在.gitattributes中增加一行
/path/to/gitrepo filter=gpg diff=gpg

 

以上就是关于 GPG 与 GIT 的一些应用,希望对大家有用。
Jun 13

有时使用某个应用程序的时候,你需要非常频繁地使用你的 Gnu PG 密钥,这就意味着你需要多次输入密匙解密口令。相当多的应用程序支持将口令(密码)缓存起来方便用户使用。但是出于安全的目的,却不能让缓存的口令(密码)在多个程序之间交叉使用。不过,Gnu PG 提供了很安全的密码缓存方式,也即 Gnu PG 的代理 gpg-agent。通过它,多个应用程序可以共用 Gnu PG 密匙的解密口令。如果你在使用某个应用程序的时候输入了密匙解密口令,其他应用程序可以在一段时间内不用再请求输入口令也能解密 Gnu PG 密钥。下面就来谈谈如何设置 Gnu PG 的代理。

尽管我们不谈论 Gnu PG 公匙、密匙的生成与使用过程,但是使用 Gnu PG,第一步当然是安装它:
$ sudo yum install gnupg
通常,Gnu PG 程序本身就有代理功能。不过在图形界面下,Gnu PG 的代理功能需要用 pinentry 来开启,所以需要先在 Linux 中安装 pinentry 程序。
$ sudo yum install pinentry-gtk 
现在创建 gpg-agent 的配置文件:
$ cat > ~/.gnupg/gpg-agent.conf << EOF 

# PIN entry Program
#pinentry-program /usr/bin/pinentry-curses
#pinentry-program /usr/bin/pinentry-qt4
#pinentry-program /usr/bin/pinentry-kwallet
pinentry-program /usr/bin/pinentry-gtk-2
# Keyboard control
no-grab
# Cache timeout: 3 hours
default-cache-ttl 10800
#default-cache-ttl-ssh 10800

EOF
这个配置指明了 pinentry 程序、口令缓存的超时时间等等。接着激活 Gnu PG 的代理能力,这只要使用下面这一行即可
$ echo "gpg-agent" >> ~/.gnupg/gpg.conf
这一行告诉 Gnu PG 在需要密码时使用 gpg-agent,但前提是需要 gpg-agent 事先已经工作。运行 gpg-agent 的方法很简单:
$ eval $(gpg-agent --daemon)
停止 gpg-agent 的方法是:
$ pkill -u "$USER" gpg-agent
 
为了让 gpg-agent 的使用更加方便,我们自然希望它能够随机器启动而自动工作,这可通过在 /etc/profile.d/ 中作如下的配置来实现
$ sudo cat > /etc/profile.d/gpg-agent.sh << EOF

#!/bin/sh

envfile="${HOME}/.gnupg/gpg-agent.env"
if test -f "$envfile" && kill -0 $(grep GPG_AGENT_INFO “$envfile" |cut -d: -f 2) 2>/dev/null; then
     eval "$(cat :$envfile")"
else
     eval "$(gpg-agent --daemon --write-env-file "$envfile")"
fi
export GPG_AGENT_INFO # the env file does not contain the export statement

EOF

$ sudo chmod 755 /etc/profile.d/gpg-agent.sh
以上的设置使得每位登录 Linux 的用户自动启用 gpg-agent。一般而言,一个会话只允许开启一个 gpg-agent 进程。关于这一点,我们可以从上面的配置中可以看到。如果我们只希望为某个用户启用 gpg-agent,可在 ~/.xprofile、~/.xsession 或者 ~/.xinitrc 中添加下面这一行,这取决于我们使用的图形界面的启动方式,例如:
$ echo 'eval "$(gpg-agent --daemon)"' >> ~/.xprofile
如果用户不使用图形界面的话,也可以将上面这一行写入 ~/.bash_profile。通过前面这些设置便能自动启动 gpg-agent 了。关于 gpg-agent 的更多设置,请自行参看 gpg-agent 的手册页
$ man gpg-agent
 
实际上,从手册页中可以看到,gpg-agent 还可以作为 ssh-agent,这只需要在命令行 gpg-agent 中增加 --enable-ssh-support 选项即可。下面给出一个自动作为 ssh-agent 与 gpg-agent 的配置:
$ cat >> ~/.bash_profile << EOF

#!/bin/sh

# Start the GnuPG agent and enable OpenSSH agent emulation
gnupginf="${HOME}/.gpg-agent-info"

if pgrep -u "${USER}" gpg-agent >/dev/null 2>&1; then
    eval `cat $gnupginf`
    eval `cut -d= -f1 $gnupginf | xargs echo export`
else
    eval `gpg-agent -s --enable-ssh-support --daemon`
fi 

EOF
 
值得指出的是,Gnome 桌面自身提供的 Gnome-keyring 也整合了 gpg-agent 功能,这取决于 Gnome-keyring 包编译过程有没有开启 gpg-agent 选项。如果我们想禁用 Gnome-keyring 的 gpg-agent 功能,除去修改源码的编译选项之外,还可作如下操作来实现
$ cp /etc/xdg/autostart/gnome-keyring-gpg.desktop ~/.config/autostart/gnome-keyring-gpg.desktop
$ echo "X-GNOME-Autostart-enabled=false" >> ~/.config/autostart/gnome-keyring-gpg.desktop
实际上,上面的操作与如下的半图形化操作相同:
$ gnome-session-properties
在随后出现的图形框中勾选掉 gnome-keyring-gpg 功能。如果只是想临时禁用 Gnome-keyring,可执行
$ sudo pkill gnome-keyring

 

Mar 2

当系统的物理内存不够用的时候,就需要将物理内存中的一部分空间释放出来,以供当前运行的程序使用。那些被释放的空间可能来自一些很长时间没有什么操作的程序,这些被释放的空间被临时保存到 Swap 空间中,等到那些程序要运行时,再从 Swap 中恢复保存的数据到内存中。这样,系统总是在物理内存不够时,才进行 Swap 交换。这个是 Swap 交换分区的作用。

 
系统中交换分区的大小并不取决于物理内存的量,而是取决于系统中内存的负荷,所以在安装系统时要根据具体的业务来设置 Swap 的值。其实虚拟内存并不是等到物理内存用尽了才使用的,是否尽量的使用或不使用 Swap,在内核空间有一个参数控制:
# cat /proc/sys/vm/swappiness
60
表示默认的 swappiness 的值为60。换而言之,当 Swap 空间使用达到60%的时候,开始释放物理内存中的 cache/buffers。 swappiness=0 的时候表示最大限度使用物理内存,然后才是 Swap 空间; swappiness =100 的时候表示积极的使用 Swap 分区,并且把内存上的数据及时的搬运到 Swap 空间里面。
 
现在服务器的内存动不动就是上百 G,所以我们可以把这个参数值设置的低一些,让操作系统尽可能的使用物理内存,降低系统对 Swap 的使用,从而提高系统的性能。例如
# echo 10 > /proc/sys/vm/swappiness
或者
# sysctl vm.swappiness=10
vm.swappiness = 10
再来查看一下它的值:
# cat /proc/sys/vm/swappiness
10
这表明修改已经生效。但是如果我们重启了系统,它又会变成60。为了让我们的修改长久有效,可以修改配置文件/etc/sysctl.conf:
# echo 'vm.swappiness=10' >>/etc/sysctl.conf
为了让它即时生效,可执行:
# sysctl -p
重新载入配置文件。 
 
Red Hat(红帽官方)推荐交换分区的大小应当与系统物理内存的大小保持线性比例关系。不过在小于2GB物理内存的系统中,交换分区大小应该设置为内存大小的两倍,如果内存大小多于2GB,交换分区大小应该是物理内存大小加上2GB。其原因在于,系统中的物理内存越大, 对于内存的负荷可能也越大。但是,如果物理内存大小扩展到数百GB,这样做就没什么意义了。
 
最近,在Gentoo中编译webkit-gtk-1.10.2-r300,辛辛苦苦编译了几个小时,结果报错:
collect2: ld termiinated with signal 9 [Killed]
通过Google搜索,发现这是由于编译过程中机器的内存耗尽引起的。这就是说解决问题的办法是增加内存。不过加物理内存是远水,解不了近火。既然Linux中的交换分区也是内存的一部分,于是不妨尝试增加交换分区。 这又让我们想起了红帽官方对于交换分区的建议:Linux系统交换分区最适合的大小是物理内存的1-2倍。可是谁又会在分区的时候记得这些呢?不过由于Linux允许文件系统中存在多个交换分区或者交换分区文件,所以亡羊补牢、为时未晚。如果我们的磁盘空间还尚有空余没有划分,那么我们可以直接利用分区工具再分出一个交换分区。倘若你像我一样,所有空间都已经被划分完了,那么只剩一招了—使用交换分区文件。下面我们主要来说说如何利用交换分区文件扩大分区。
 
首先,需要制作交换分区文件。考虑到我的老机器已有的物理内存是1G、现有交换分区大小是500M。为了我们的编译过程顺利完成,不妨考虑交换分区文件的大小为1G。为此,执行下述命令:
$ sudo dd if=/dev/zero of=/var/tmp/swap bs=1k count=1024000
记录了1024000+0 的读入
记录了1024000+0 的写出
1048576000字节(1.0 GB)已复制,5.07655 秒,207 MB/秒

它将在/var/tmp路径创建一个名为swap、大小为1G的分区文件,该分区文件拥有1024000个扇区(block),每个扇区大小为1K。接着,再把这个分区文件格式化为交换分区格式:

$ sudo mkswap /var/tmp/swap

随后,将它挂载到文件系统:

$ sudo swapon /var/tmp/swap
如果想要确认交换分区是否挂载成功,可执行:
$ swapon -s 
Filename      Type      Size    Used  Priority
/dev/sda1     partition 511996  16192 −1
/var/tmp/swap file      1023996 0     −2
从显示结果来看,我们确实看到了文件格式交换分区被加载。如果还想要查看系统内存情况,只需执行:
$ free -m
       total       used free shared buffers cached
Mem:   995         935  60   0      6       551
-/+ buffers/cache: 376  618
Swap:  1499        15   1484
通过扩大swap区,可以正常将webkit-gtk-1.10.2-r300编译完。实际上,用top跟踪webkit-gtk-1.10.2-r300的编译过程,会发现整个编译过程所需要的内存大概在2G左右。而我们通过增加交换分区的大小,总获得了2.5G左右的内存空间。编译完之后,如果我们不再需要这一块交换分区文件,那么可以先卸载再删除它
$ sudo swapoff /var/tmp/swap
$ sudo rm -rf /var/tmp/swap
 
倘若我们仍希望交换分区文件为以后的编译提供便利,那么可以选择保留它。不过在使用它之前必须先挂载它,因为一旦重启,原先的挂载便会失效!若要让我们的交换分区文件随机器启动自动挂载,则可修改/etc/fstab文件,例如作如下设置:
$ cat /etc/fstab | grep -i swap
/dev/sda1     none swap sw       0 0
/var/tmp/swap swap swap defaults 0 0