把Apache换成Nginx笔记

其实想把Apache换成Nginx已经很多年了,只是一直懒得弄,也可能是因为上了年纪的关系,有点得过且过的意思。当然更主要的原因是没有压 力,目前我的所有应用在Apache下都跑得挺好,对Apache的配置也比较熟悉。但是Nginx 10倍的性能优势始终在那里,这是一个挡不住的诱惑。

上周与令狐和帮主小聚的时候顺手在手机的Ubuntu里装了个Nginx,但是 Ubuntu 9.04带的那个版本实在太老了,也就没有再弄。后来因为换手机把那个Ubuntu搞掉了,还没重装,这两天就在工作机的Ubuntu 12.04上来装了个配置一下。后来还正式部署到了一台Debian服务器上。顺便做点笔记。

安装

在Ubuntu 12.04下是简单。

apt-get install nginx php5-cgi php5-cli php5-fpm php-doc

不过在Debian 6下就麻烦一些,因为apt里没有php5-fpm,只能源码安装,或者使用这个源:

#在 sources.list 里加入以下源
sudo echo "deb http://php53.dotdeb.org stable all" >> /etc/apt/sources.list
#或者:deb http://packages.dotdeb.org stable all
#如有必要还可以再加上:deb-src http://packages.dotdeb.org stable all
#加入key
wget http://www.dotdeb.org/dotdeb.gpg
cat dotdeb.gpg | sudo apt-key add -
rm dotdeb.gpg
sudo apt-get update
sudo apt-get install php5-fpm

初步配置

首先关闭Apapche的自启动,可以用 sysv-rc-conf 来配置。

然后配置php-fpm,主要修改这几个文件:

/etc/php5/fpm/php.ini
/etc/php5/fpm/php-fpm.conf
/etc/php5/fpm/pool.d/www.conf

第一个为与php有关的配置,这里要有这一句:

cgi.fix_pathinfo = 0;

原因见nginx默认配置文件中的注释说明。

第二个为fpm有关的配置,通常没什么要改的。

最后一个为与web有关的配置,可以在这里修改fpm的监听端口号什么的。

基本的nginx配置

主要的配置文件是这些:

/etc/nginx/nginx.conf
/etc/nginx/conf.d/*.conf
/etc/nginx/sites-enabled/*

基本上不需要修改nginx.conf,所有跟全站http相关的配置都可以放在conf.d/*.conf里,各虚拟主机的配置则放在sites-enabled/*里即可。

参考全站公共配置内容:

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" "$http_x_forwarded_for"';

charset utf-8;

这里有一点需要注意的是:charset设置并不能保证输出一定是utf-8。对于静态文件来说一般没问题,但是对于动态内容来说(比 如来自PHP或Python WSGI),即使返回内容的确是用utf-8编码,但是没有在HTTP响应头里指定编码方式的话,nginx会默认为 ISO-8859-1 ,即使这里指定了utf-8也没用,结果就是导致在FireFox等浏览里器显示乱码(部分浏览器会识别网页中的meta,不一定按照HTTP响应头的指 定编码方式)。

解决方案有两个:一是治标的办法——在nginx配置里加入一个ISO-8859-1到utf-8的 charset_map(内容为空即可,当然这样的话碰到真正的ISO-8859-1内容时会乱码)。另一个当然是治本的——在动态内容里增加HTTP响 应头内容,指定编码方式。

参考虚拟主机配置:

server {
	listen   80; ## listen for ipv4; this line is default and implied
	server_name yoursite.com www.yoursite.com;
root /home/username/www;
index index.html index.htm index.php;

     error_log   /var/log/nginx/yoursite.error.log warn;      access_log  /var/log/nginx/yoursite.access.log main;

        location = /favicon.ico {                 log_not_found off;                 access_log off;         }

        location = /robots.txt {                 allow all;                 log_not_found off;                 access_log off;         }

        location / {                 # This is cool because no php is touched for static content.                 # include the "?$args" part so non-default permalinks doesn't break when using query string                 try_files $uri $uri/ /index.php?$args;         }           location ~ .php$ {                 #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini          fastcgi_pass   127.0.0.1:9000;         fastcgi_index  index.php;         fastcgi_param  SCRIPT_FILENAME  /home/username/www$fastcgi_script_name;         include        fastcgi_params;               fastcgi_intercept_errors on;         }           location ~* .(js|css|png|jpg|jpeg|gif|ico)$ {                 expires max;                 log_not_found off;         }

location ~ /\.ht {
	deny all;
}

}

此配置根据nginx官方的wordpress配置修改而来。注意其中的SCRIPT_FILENAME一行,此行缺少会导致PHP页面显示空白,但HTTP响应为没有错误的200,此行错误则会导致html显示正常,但php显示404找不到。

配置完成后启动nginx和php5-fpm。

sudo /etc/init.d/php5-fpm start
sudo /etc/init.d/nginx start

停止的方式类似:

sudo /etc/init.d/php5-fpm stop
sudo /etc/init.d/nginx stop

SSL配置

这个配置倒很简单,跟Apache基本一样。证书生成的部分就不说了,都是用openssl搞的。不过nginx默认是用.crt/.key文件,apache还可以用.pem文件,实际上可以手工把.pem文件拆成.crt/.key。

基本配置如下:

server {
    listen   443; ## listen for ipv4
server_name yoursite.com;

ssl  on; 
ssl_certificate  /etc/nginx/ssl/nginx.crt;
ssl_certificate_key  /etc/nginx/ssl/nginx.key;

ssl_session_timeout  5m; 

ssl_protocols  SSLv3 TLSv1;
ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP;
ssl_prefer_server_ciphers   on; 

     error_log   /var/log/nginx/yoursite.error.log warn;      access_log  /var/log/nginx/yoursite.access.log main;

其它配置与 http 相同

location /webalizer {
    root /home/username/www;
    index index.html
    autoindex off;
}

}

另外要注意的是:php5-fpm那边是不知道nginx这边是否使用https的,所以用 $_SERVER['HTTPS'] 将取得空串,需要这样设置一下:

location ~ \.php$ {
                fastcgi_pass   127.0.0.1:9000;
                fastcgi_index  index.php;
                fastcgi_param  SCRIPT_FILENAME  /home/username/www$fastcgi_script_name;
# 注意这句
                fastcgi_param HTTPS on;
            include        fastcgi_params;
            fastcgi_intercept_errors on;
    }</pre>

gevent-WSGI配置

以web.py为例。首先需要修改web.py的代码以使用gevent-WSGI(虽然这只是个参考实现,但性能还是很不错的)。

if __name__ == "__main__":
    from gevent import socket
    from gevent import monkey
    monkey.patch_all()
    from gevent.wsgi import WSGIServer
    import pwd 
sys.stdout = sys.stderr

SOCK = &quot;/var/www/sockets/webpy.sock&quot;
pe = pwd.getpwnam(&#39;www-data&#39;)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
    os.remove(SOCK)
except OSError:
    pass
sock.bind(SOCK)
os.chown(SOCK, pe.pw_uid, pe.pw_gid)
os.chmod(SOCK, 0770)
sock.listen(256)
WSGIServer(sock, app.wsgifunc()).serve_forever()</pre>

改完即可启动监听相应的socket。

python /home/username/webpy/start-gevent.py 2>> /var/log/nginx/webpy.log &

其次是修改nginx,将相应的请求转发到web.py+gevent-WSGI的监听socket。

参考配置:

location /webpy {
        try_files $uri @webpy;
    }
location @webpy {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_pass http://unix:/var/www/sockets/webpy.sock;
}

location /webpy/static {
    root /var/www;
    autoindex off;
}

搞定收工。

推送到[go4pro.org]