因为工作上一直在用 nginx,对 nginx 配置的了解日益深入,而对 Apache httpd 配置的了解依然非常少以至于不知道如何添加一个虚拟主机的配置而不用修改大量已有配置,决定将自己本地的 Apache httpd 替换成 nginx。一开始这个 httpd 只是跑了一个 MediaWiki、一些静态文件和单独的 PHP 脚本,随着时间的流逝,后来陆续添加了 phpPgAdmin、RockMongo、PHP Xcache、into2html CGI 脚本等东西。于是配置起来似乎也不那么容易了。
首先第一点:这么多 PHP 的服务,我不想每一个 location 块里边一堆相同或者相似的 FastCGI 配置。于是把相关配置写到一个文件里去。(直到这时我才意识到 location 是可以嵌套使用的!)
index index.php index.html; location ~ (.+\.php\d?)($|/) { fastcgi_pass unix:/run/php-fpm/php-fpm.sock; fastcgi_index index.php; set $script $request_filename; if ($request_filename ~ ^(.+\.php\d?)(/.*)$){ set $script $1; set $pathinfo $2; } fastcgi_param PATH_INFO $pathinfo if_not_empty; fastcgi_param SCRIPT_FILENAME $script; include fastcgi_params; }
因为是嵌套的 location,所以得在外边也写一下index
,不然 nginx 会不知道的。
另一个问题是默认的 fastcgi.conf 里定义的SCRIPT_FILENAME
是$document_root$fastcgi_script_name
。但是我的 MediaWiki 使用了alias
而不是root
,于是$document_root
会访问错地方。网上似乎没人完全地解决或者绕过了这个问题,大概是因为他们的配置不会被包含到多个 location 里吧。后来使用$request_filename
这方案是我自己读了文档之后「发明」的。
另外,nginx 自定义的变量似乎是词法作用域,不能被 include 进来的配置访问到。大概因为 FastCGI 脚本路径是自己处理的,PATH_INFO
也得自己处理。
然后就可以这么用啦(这是我的 MediaWiki 配置):
location /w/ { alias /usr/share/webapps/mediawiki/; include php; } location /wiki { rewrite ^/wiki(/.*)?$ /w/index.php$1 last; }
以前的 Apache httpd 的配置是这样的:
Alias /w /usr/share/webapps/mediawiki RewriteEngine On RewriteRule ^/?wiki/(.*)$ /w/index.php/$1 [PT,L,QSA] RewriteRule ^/?wiki$ /w/index.php [PT,L,QSA] <Directory /usr/share/webapps/mediawiki> Options +FollowSymLinks AllowOverride All Require all granted </Directory>
另外一个被我写成单独的配置文件以便被 include 的限制只允许本地访问用的:
allow 127.0.0.1; allow ::1; deny all;
比 httpd 的好理解一些。
另一个问题是 CGI 脚本。nginx 是有两个方案的,fcgiwrap 或者 nginx-fcgi。前者是个二进制程序,在 Arch 和 Debian 源里都有。后者是个 Perl 脚本,已经难以下载到了(给的链接是我从互联网存档取得的)。
Arch 的 fcgiwrap 包提供了一个 systemd socket 文件,直接启动它就可以了。启动 .service 服务似乎会有问题。
$ sudo systemctl start fcgiwrap.socket
nginx 里就这么写就可以了:
fastcgi_pass unix:/run/fcgiwrap.sock; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REMOTE_USER $remote_user;
引用的时候就是这样子:
location /cgi-bin { root /srv/http; include fcgiwrap; }
经过测试,默认参数时 php-fpm 空闲时有三个 worker,高峰时会多一点,但是 Apache httpd 平时就有八个 worker,高峰时更多。每个 worker 对内存的占用是差不多的。至于响应速度,对于 MediaWiki nginx 稍慢 httpd 一点,但是服务启动后第一次访问会很多,而且 ab 测试时失败数少不少。更重要的是,systemd-analyze blame
表示 nginx + php-fpm 组合启动时间远远少于 Apache httpd(0.1 秒 vs 好几秒)!
PS: 谁能告诉我 systemd-analyze 怎么查看以前启动的时间信息呀?