wordpress的webserver从apache切换到nginx


就个人经验来说,从apache切换到nginx上不是很难,关键是你需要分析好现有apache配置的内容,剩下的就是在nginx中对应配置就行。以本人的apache配置为例:

  1. 关闭服务器版本显示
  2. 单独的用户
  3. worker&event
  4. 与PHP的整合
  5. init.d脚本(个人是编译安装的)
  6. gzip
  7. expires(图片等过期时间设置)
  8. 虚拟主机
  9. wordpress的permlink
  10. 二级域名的重定向(错误的配置)

最后一个是我对apache虚拟主机配置不完全理解导致的一个失误,nginx上当然不会把错误照搬过来,但是nginx上需要做以前的链接兼容(这么快就有历史包袱了……)。

在做完功能分析之后,个人建议在虚拟机中搭建一套类似环境练手。除非你现有的apache是个实验环境,临时关个一两天没啥问题,否则还是老老实实做模拟练习。

即使是模拟练习也不要奢望一次成功,个人认为类似敏捷中的快速反馈——是逐个迁移功能的方式比较好。而且迁移的功能尽量按照难度由低到高的顺序排序,特别是在功能列表很长时,因为这样实施起来更有信心。

安装nginx的过程这里就不展开了,一搜一大把,官方wiki的在这里,我这里也有一个。

服务器版本显示

基于安全考虑,建议不显示服务器的版本。apache上配置如下:

ServerTokens Prod;

nginx上配置如下:

http {
  server_tokens off;
}

注意nginx的配置末尾是有分号的,和apache不一样。其次nginx的server_tokens上下文为http,server,location,而apache的可以配置在顶层。
顺便说一句,nginx和apache一样也有指令文档,nginx的在这里

单独的用户

apache使用unixd_module限制用户,配置如下:

LoadModule unixd_module modules/mod_unixd.so
<IfModule unixd_module>
  User apache
  Group apache
</IfModule>

nginx的指令如下:

user www-data www-data;

nginx的用户默认值为nobody。

worker和event

apache有多种选择,个人选择mpm_event,指令数据是ab渐进出来的。

<IfModule mpm_event_module>
  StartServers 2
  MinSpareThreads 1
  MaxSpareThreads 4
  ThreadsPerChild 4
  MaxRequestWorkers 4
  MaxConnectionsPerChild 1000
</IfModule>

nginx因为模型不一样,所以配置角度不一样,主要配置项是worker_processes,工作进程数:

worker_processes  1;  

events {
    use                 epoll;
    worker_connections  1024;
}

虽然apache和nginx模型不一样,但都可以用ab做压力测试,重点是保证内存使用量在合理范围内。

与PHP的整合

apache的网上一搜索一大把,我实际使用的:

LoadModule dir_module modules/mod_dir.so
<IfModule dir_module>
  DirectoryIndex index.html index.php
</IfModule>

LoadModule php5_module modules/libphp5.so
<FilesMatch \.php$>
  SetHandler application/x-httpd-php
</FilesMatch>

nginx与php的连接方式个人选择php-fpm,并且使用unix socket文件而不是socket方式:

http {
    server {
        location ~ \.php$ {           
            fastcgi_pass   unix:/var/run/php-fpm.sock;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }
    }
}

注意php-fpm需要单独启动。其次默认的fastcgi_param配置值是/scripts$fastcgi_script_name,个人测试时没法用,会报File not found,需要修改成$document_root$fastcgi_script_name。

测试时建议写个带phpinfo的简单index.php。

<?php
  phpinfo();
?>

如果你看到熟悉的phpinfo界面说明nginx和php整合OK了。

init.d脚本

apache的话用apachectl就行,nginx需要另外找。个人选择的是nginx的wiki上的针对ubuntu的脚本,使用时注意要修改脚本中程序位置,配置位置和PID位置:

#------------------------------------------------------------------------------
#                               Consts
#------------------------------------------------------------------------------
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# change to /usr/local/nginx/sbin/nginx
DAEMON=/usr/local/sbin/nginx
 
PS="nginx"
PIDNAME="nginx"				#lets you do $PS-slave
PIDFILE=$PIDNAME.pid                    #pid file

# change to /usr/local/nginx/logs
PIDSPATH=/var/run
 
DESCRIPTION="Nginx Server..."
 
RUNAS=root                              #user to run as
 
SCRIPT_OK=0                             #ala error codes
SCRIPT_ERROR=1                          #ala error codes
TRUE=1                                  #boolean
FALSE=0                                 #boolean
 
lockfile=/var/lock/subsys/nginx

# default is OK
NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf"

nginx配置中pid位置用pid指令指定:

user              www-data www-data;
worker_processes  1;

pid /var/run/nginx.pid;

events {
    use                 epoll;
    worker_connections  1024;
}

给init.d脚本取个名字,比如nginx,放到/etc/init.d中,确保可执行(chmod +x),最后执行update-rc.d nginx defaults加入启动列表。

接下来你就可以通过service nginx start启动nginx,service nginx stop关停nginx了。顺便说一句,没有init.d脚本时,使用nginx启动,nginx -s stop停止和nginx -s reload重启。

php-fpm实际上也需要一个init.d脚本。这里就不展开,详细的可以看这里

gzip

apache下使用deflate模块:

LoadModule deflate_module modules/mod_deflate.so
<IfModule deflate_module>
  AddOutputFilterByType DEFLATE text/html
  AddOutputFilterByType DEFLATE text/plain
  AddOutputFilterByType DEFLATE text/xml
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE text/javascript

  BrowserMatch ^Mozilla/4 gzip-only-text/html
  BrowserMatch ^Mozilla/4\.0[678] no-gzip
  BrowserMatch \bMSIE !no-gzip !gzip-only-text/html 
</IfModule>

nginx的配置(和apache不完全对应,注意content-type):

gzip            on; 
gzip_min_length 1k; 
gzip_comp_level 2;
gzip_types      text/plain text/javascript application/x-javascript text/css;

各参数详细含义请参考这里

gzip的检查方法有很多,个人使用firebug对比前后content-length。

expires

apache下使用expires模块:

LoadModule expires_module modules/mod_expires.so
<IfModule expires_module>
  ExpiresActive on
  ExpiresByType image/jpeg "access plus 1 month"
  ExpiresByType image/png "access plus 1 month"
  ExpiresByType image/gif "access plus 1 month"
</IfModule>

nginx下expires指令:

location ~ \.(gif|jpg|jpeg|png|bmp)$ {
    expires 15d;
}

一个是按照content-type,另外是按照扩展名,一般来说不会有问题。

个人检查expires的方法是用firebug查看图片的响应头。

虚拟主机

虚拟主机是apache的词,nginx只有server block。

比如下面这段虚拟主机配置:

<VirtualHost *:80>
  ServerName foo.bar
  ServerAlias www.foo.bar
  DocumentRoot /home/foo/public_html

  <Directory "/home/foo/public_html">
    Options Indexes
    AllowOverride FileInfo
    Require all granted
  </Directory>
</VirtualHost>

映射foo.bar, www.foo.bar到/home/foo/public_html目录。

nginx对应配置为:

http {
    server {
        server_name foo.bar www.foo.bar
        root        /home/foo/public_html;

        location / {
            index index.html index.html;
        }
    }
}

注意两者还是有些地方不对等的,比如apache的FileInfo代表允许.htaccess,nginx没有.htaccess,所以要用另外的方式支持相应的功能,比如.htaccess中的rewrite。大部分情况下,不同域名对应不同目录还是很容易转换的。

permanent link

permanent link是在wordpress中设置的,但是需要web服务器支持。apache的话需要开启.htaccess,注意上面虚拟主机中的FileInfo。nginx的话用另外一种方案:

http {
    server {
        location / { 
            index     index.html index.htm index.php;
            try_files $uri $uri/ /index.php?args;
        }   
    }
}

注意其中的try_files。

二级域名重定向

简单来说,我配置了blog.xnnyygn.in跳转到xnnyygn.in/blog,但是在配置nginx的时候,发现我对虚拟主机理解错了,二级域名可以直接映射到目录的。但是考虑到之前给的链接,我决定用nginx的rewrite做兼容。

http {
    server {
        location /blog/ {
            rewrite ^/blog/(.*)$ http://blog.xnnyygn.in/$1 permanent;
        }
    }
}

这里的rewrite很简单,只要懂正则表达式基本就能明白。我的要求是遇到/blog/下的请求,把后面的内容转发到/下,并且是永久的。

总结

上面介绍了从apache切换到nginx涉及到的常见问题。如果你是第一次配置nginx的话,建议从简单的配置点开始逐步平滑切换。遇到问题可以google。nginx作为一个出现有好几年并且并很多大公司使用的web服务器,相关教程,wiki和问题解答都很多,足以解决你遇到的大部分问题。


4 responses to “wordpress的webserver从apache切换到nginx”

    • 没有,觉得比较麻烦。而且个人认为多作者博客比多博客要好一些……

      • 我们现在是4个人拼VPS的,然后很多人都要用自己的wordpress。有童鞋需要两个wordpress,然后现在就有4个wordpress了。维护的时候,四个wordpress都要分别管理,看起来很麻烦。我前几天一直在尝试multi site,但是一直没成功过。。。

        • 具体有哪些问题?(这里回复嵌套太深了,twitter或者gmail回吧……)
          如果是调试multisite,建议搞个虚拟机自己练练手。这个博客我也是调试了一两个星期才上的。