从去年(2016年)秋季重新收拾这个网站开始,本着精益求精的想法,从结构上完成这个站点的优化。WordPress本身是为Apache而设计的,它有更新.htaccess的一系列方法,使得网站可以正常工作。但是如果使用了nginx作为服务器,.htaccess文件不起作用了,因而弯路是需要走一点的。

下面根据本站的情况进行配置的总结。
本站运行条件是:

腾讯云服务器
1核心 Xeon E5-26xx / 1GB DDR3 RAM
网络带宽 1Mbps / 本地盘
Ubuntu 16.04 amd64

打广告,我的企鹅云推荐码是:GIZZQP
首次购买企鹅云服务器输入享9折优惠哦~

WordPress的ReWrite规则

SEO的原则一般就是机器可读性强、文字语法合理。首先很多人搞SEO的第一步就是把WordPress自带的?p=123一类的固定链接换掉。这个时候,用Apache的孩子不会发现有什么异常。而用nginx的孩子回到自己的主页,正满心欢悦地想看看自己那有逼格的固定链接的时候,却被送了满屏幕的404 Not Found。这是为什么呢?

打开WordPress的.htaccess文件,内容是这样的:

# BEGIN WordPress

RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

# END WordPress

大概的意思,就是找不到请求uri的文件的时候,自动把path重写到index.php这一个入口。现在就以本文链接https://xzclip.cn/serverheld/note-for-this-website-1/为例子分析:

  1. 你请求uri为/serverheld/note-for-this-website-1/的文档;
  2. nginx理所当然地找不到文档;
  3. nginx向你扔出了一个404…

但是经过重写配置之后的情况是这样子的:

  1. 你请求uri为/serverheld/note-for-this-website-1/的文档;
  2. nginx理所当然地找不到文档again;
  3. nginx变机智了,重写uri到index.php,自己请求uri为index.php/serverheld/note-for-this-website-1/的文档;
  4. WordPress返回正常的内容给nginx,nginx将得到的内容作为/serverheld/note-for-this-website-1/的内容发送给你的浏览器。

由于使用WordPress的nginx用户已经很多了,所以说网上总结的重写方法有很多。对于经常流传的,会是这个版本:

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;
}

不过在进行WP-Super-Cache的配置时,这种简单粗暴的方法完全不能符合要求。而且WordPress官方现在给出了一套更加简洁的方案。[1]

修改site的配置文件中location /段为如下内容:

location / {
	try_files $uri $uri/ /index.php?$args;
}

rewrite /wp-admin$ $scheme://$host$uri/ permanent;

代码的意思是,当有一个uri被请求时,会先查找对应文件,再查找对应文件夹下index语句定义的索引页面,最后把请求交给index.php处理。最后的一句是用以解决进入了uri为/wp-admin(结尾不带/)的后台的时候,点击的所有设置链接无效的问题,建议未配置的萌新加上。

如果WordPress的安装目录不是根目录,应该按照如下修改:

location /path/to/wordpress/ {
	try_files $uri $uri/ /path/to/wordpress/index.php?$args;
}

rewrite /path/to/wordpress/wp-admin$ $scheme://$host$uri/ permanent;

回头一看,你有了一条逼格满满的……固定链接哈哈哈~

WP Super Cache重写模式配置

相信我和很多人,使用WP-Super-Cache是为了加快页面的提供速度,毕竟WordPress的效率确实很低。对于Apache用户,又双叒叕可以轻轻松松地用上各种很好用的功能,而对于nginx用户,又要走弯路了。虽然,还是能直接使用PHP缓存方法,但是nginx处理静态文件的能耐就被浪费了。不过,这个插件的作者考虑到有广大nginx用户的实际,给出了一个重写方法。[1]

set $cache_uri $request_uri;
#POST请求交由php处理
if ($request_method = POST) {
	set $cache_uri 'null cache';
}	
if ($query_string != "") {
	set $cache_uri 'null cache';
}   
#这些请求uri是不能缓存的
if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") {
		set $cache_uri 'null cache';
}   
#不要为已知用户提供缓存(如已登陆用户、评论过的用户)
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
	set $cache_uri 'null cache';
}

location / {
	#如果你是普通用户,用以下语句:
	try_files /wp-content/cache/supercache/$http_host/$cache_uri/index.html $uri $uri/ /index.php?$args;
	#如果你配置了纯https,用以下语句:
	#try_files /wp-content/cache/supercache/$http_host/$cache_uri/index-https.html $uri $uri/ /index.php?$args;
}

配置无误后,在运行nginx -t检查语法之后再进行nginx的重载即可。
搭载systemd的系统重载命令:systemctl reload nginx
之后在插件页面更新设置,配置好预缓存设定确定生成supercache文件即可。

enable-mod-rewrite-mode-in-wp-super-cache

等到预缓存完成,可以尝试将php-fpm的服务停止,然后用隐私模式浏览页面。此时如果仍正常,则mod_rewrite模式配置成功。

进阶 – 配置gzip压缩缓存与提供预压缩文件

在插件设置页面的“高级”选项卡中爽朗地选择“压缩页面以便让来访者更快浏览。 (推荐)”,更新设置。细心的孩子会发现,生成的supercache文件中都有一个带有.gz后缀的文件。这个时候需要利用一个nginx的特性。

在site配置文件或者nginx.conf添加如下内容:[2]

gzip on;
gzip_static on;

第一句话很好理解,打开gzip压缩,而第二句话,意思就是:
当客户端支持gzip压缩时,查找对应文件带.gz后缀的预压缩文件,直接提供给客户端。此时会自动把生成的预压缩文件提供,无需nginx再自行压缩,节约了CPU资源。

使用CDN/对象储存提供静态资源(动静态分离)

因为国外云服务器到国内速度很一般,或者国内云服务器的带宽小得可怜,往往打开带有大量元素的网页会非常缓慢。在网站业务推进之后,访问量变大时,体验就下去了。此时需要一些图床或对象储存解决静态资源的分发。

本文以腾讯云为例进行操作实例,其余平台自行参考。

配置静态元素站点

首先在www目录(Debian/Ubuntu是/var/www)建立静态内容文件夹,链接你需要静态加速的资源文件夹:

mkdir /var/www/static/
ln -s /var/www/path-to-your-wordpress/wp-includes /var/www/static/wp-includes
ln -s /var/www/path-to-your-wordpress/wp-content /var/www/static/wp-content
#...

随后编辑站点文件:

server {
	listen 80 default_server;
	listen [::]:80 default_server;
	server_name 你的静态站点域名;
	root /var/www/static;
	
	location / {
		try_files $uri $uri/ =404;
	}
	location ~* \.(js|css|png|jpg|jpeg|gif|ico|tiff|mp3|mp4)$ {
		expires 10d;
	}
	location ~* \.php$ {
		deny all;
	}
	location ~ /\.ht {
		deny all;
	}	
	location /wp-content/cache/ {
		deny all;
	}
}

随后检查语法、重载nginx。此时服务器已经准备就绪了,下一步在云服务的控制台上配置:

使用对象储存配置

对象储存可以用以储存一些静态文件,作为一种在网络上廉价提供文件的方法。对象储存使用云服务厂商的域名,所以说无需考虑备案的问题;通常对于小开发者,对象储存服务是会提供一定免费额度的,因此对象储存加速成本会很低。

  1. 新建一个Bucket
    cos-add-bucket
    点击创建Bucket,配置好自己对象储存的属性:
    cos-add-bucket-2
  2. 进入配置界面,设置回源。
    因为这是一个储存库,里面不一定有所需数据。当客户端请求一个文件时,如果储存库没有这个文件,将触发回源操作,对象储存库会自动拉取文件,并自动返回给客户端。
    cos-origin-pull
  3. 获取域名,通过cdn插件替换资源路径。
    本实例使用的是WP Super Cache的CDN功能。域名如下图:
    cos-domain
    此时应该在插件页填写设置:
    cdn-with-cos
  4. 保存设置,查看效果。
    第一次访问会进行回源,所以速度会比较慢。

使用CDN(内容分发网络)配置

使用内容分发网络可以实现更加灵活的缓存配置,而且因为节点数目多,因而可以获得更快的速度。但是,CDN一般都不是免费的。CDN要求绑定域名,所以说一方面,域名需要备案才可以使用;另一方面,CDN支持基于SNI的https。

换句人话说,你用了CDN的话,你的全局https站点小锁能保住,但是android2.3及以下、Windows xp及以下的用户将无法正常地访问了。不过,既然是支持全局https以响应Google、Apple和Mozilla,那就毫无畏惧地抛弃老系统用户吧!

  1. 老套路,新建CDN。
    cdn-add
  2. CDN必须有源站,配置回源。
    cdn-add-2
  3. 在域名解析按需配置cname记录
    cdn-cname
  4. (可选)配置https。
    cdn-https-config
    cdn-cert-config
  5. 填入CDN插件。
    此时注意,纯https网站可以使用//https://前缀
    自适应网站可以使用//后缀

进阶 – 跨站问题解决

由于CORS策略的存在,引用外部网站的资源这种跨域请求往往会被浏览器拦截,因而在对象储存或者CDN上需要配置Access-Control-Allow-Origin。其内容可以是一个站点,或者单纯通配符*以允许在任意网站上引用。[3]

进阶 – 被遗忘的一个js文件

点开浏览器开发者工具的小伙伴会发现,CDN插件替换路径往往不彻底。比如一个叫wp-emoji-release.min.js的文件。查看代码发现,那是写在一个style块的,采用了很多反斜杠用以反转移,因而只能修改代码解决。

方法如下,在主题functions.php文件中添加以下代码:

function filter_my_script_location( $script_url, $script_name ) {
	if ( 'concatemoji' == $script_name ) {
		$script_url = '//你的cdn地址/wp-includes/js/wp-emoji-release.min.js';
	}

	return $script_url;
}
add_filter( 'script_loader_src', 'filter_my_script_location', 10, 2 );

考完电路分析与电子线路基础,第二天还是那么虚。先写到这里吧,有空再补充。
alphaxz@SCUT

References

[1]. Nginx, WordPress Codex
[2]. Module ngx_http_gzip_static_module, Nginx
[3]. HTTP访问控制(CORS), Mozilla