熟悉Wordpress的都知道,在Apache主机并且apacahe开启allowoverride的情况下,Awordpress能够非常方便的设置其固定链接,不论wordpress是否安装下网站根目录或者二级目录下。这得益于apache具有“分布式文件管理系统”,也就是”.htaccess”这个文件,它能够非常方便的加入或者更改apache主机对当前目录的设置,包括伪静态(rewriteRule),访问权限等。当安装wordpress的时候,网站会自动在当前安装目录生成.htaccess文件,方便把网站的显示权限交给wordpress。在nginx下,一切就就没有这么方便了,nginx官方早有表态,不会支持这种分布式管理的方式,因为这样比较耗费资源。那么,在nginx主机下,怎么让wordpress和在apache主机上显示一样呢?其实主要就是伪静态的问题,我们先来看一下apache下的.htaccess文件:

1
2
3
4
5
6
7
8
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

  这里意思其实很简单,把对所有访问index.php的文件重定向到当前根,当访问其它文件或者目录时,如果都不存在,所有请求都重定向到index.php,这样一来,我们可以访问网站上的已经存在的文件或目录,对于实际不存在的文件则交给index.php来处理。当请求交到index.php时,如果请求的是文档的固定链接,则可以查询数据库,返回文章,如果不是,则可以用index.php来生成更加友好的404页面,而不是服务器自带的404页面。
那么在nginx下怎么去设置wordpressd的伪静态呢?其实在这之前,网上也能够查到很多答案,大致都是一样的结果,我摘录一下:

1
2
3
4
5
6
7
8
9
10
11
location / {
if (-f $request_filename/index.html){
rewrite (.*) $1/index.html break;
}
if (-f $request_filename/index.php){
rewrite (.*) $1/index.php;
}
if (!-f $request_filename){
rewrite (.*) /index.php;
}
}

  可以看到,这样设置起来实际上是非常麻烦的,特别是当在一个站点下有多个wordpress目录时,需要对每个目录都单独设置,特别容易出错。那么有没有其它的方法呢?前几天研究了nginx的try_files这个指令,发现它实现的功能和wordpress要求的刚好一致:判断请求是否为文件,是则返回,不是则继续判断是否为目录,是则返回,不是则交给index.php来处理。所以说,我们可以用这一行代码替换掉前面的多行代码:

1
try_files $uri $uri/ /index.php;

经过测试,所有wordpress功能运行正常!

  唯一有一点遗憾的是,由于nginx运行fastcgi的设置,所有以.php结尾的文件都会交给fastcgi去处理(不论存在不存在),所以如果访问主机上一个不存在的php页面,结果返回的是fastcgi生成404,而不是wordpress自己的404页面(第一种网上的解决方案也不能解决这个问题)。即使这样,这一行代码也远比网络上的方法简单明了,不容易出错,推荐使用。关于访问不存在php页面而让wordpress显示自定义404页面的问题,博主也会进一步关注和研究。

  关于wordpress在nginx中访问不存在php文件,不能显示wordpress自定义404错误页面的问题,已经找到了解决方案,在 location ~ .php$中,加入 try_files $uri /index.php 就行,告诉服务器,如果相应php文件不存在,则返回index.php. 最终我的server字段配置为:

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
listen 80;
server_name localhost;
root /wwwroot/;
try_files $uri $uri/ /index.php;
location ~ \.php$ {
try_files $uri /index.php;
fastcgi_pass unix:/tmp/php-fcgi.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}