0x01 前言

我博客使用wordpress作为基础并使用Newspaper这个主题(Newspaper),主要记录我实验性的技术文档,但因为图片和内容比较大,对加载速度造成了一定的影响。

所以在春节假期,我特意针对CDN、nginx、apache与PHP等中间件进行小小的改造。主要改造的内容如下:

  1. 优化腾讯CDN的配置;
  2. 腾讯CDN使用Let’s Encrypt数字证书替代trust asia的数字证书;
  3. 优化nginx配置文件,启用nignx缓存;
  4. 关闭博客评论;
  5. 禁用wordpress jetpack插件;
  6. 优化mod_pagespeed;
  7. 优化PHP-FPM配置;

今天对nginx的配置文件做个记录,方便日后复查。

0x02 SSL配置

SSL的配置没有特别需要说明的地方,具体的配置内容如下:

各个指令的简介如下:

  • ssl:启用SSL;
  • ssl_certificate:PEM格式数字证书的路径;
  • ssl_certificate_key:数字证书所对应的KEY的所在路径;
  • ssl_buffer_size:发送缓冲区,我也没找到较优的数值,这里使用默认的16k;
  • ssl_ciphers:加密算法,建议在Mozilla(Modern compatibility)网站中寻找相关内容;
  • ssl_prefer_server_ciphers:服务端加密算法优先;
  • ssl_protocols:加密协议;
  • ssl_session_cache:会话缓存,使用builtin会增加内存碎片,需要注意;
  • ssl_session_timeout:用户会话缓存失效时间,对安全性有高要求的站点需要降低该值;
  • ssl_stapling:启用OCSP(rfc4366#section-3.6)可减少用户验证证书的时间;
  • ssl_session_tickets:为复用会话创建或加载ticket key;
  • add_header(Strict-Transport-Security):为主域与子域启用HSTS,缓存时间为1年;
  • add_header(Public-Key-Pins):启用HPKP,指定可信的数字证书颁发机构。

0x03 安全与其他

为了监控nginx 的健康状态,我有启用stub_status,这个肯定是不允许普通访客访问的,那么配置如下:

我通过zabbix监控nginx,所以只允许本机进行连接,而其他IP一律返还403。

然后是modsecurity,在需要启用的location中添加以下内容即可开启:

也可以放置在server块中,对整个server有效。

因为我的站点是wordpress,所有上传的图片及文件都存放在uploads这个文件夹里,也就是说,这个文件夹里不会包含可执行文件,那么在这里做些限制:

禁止访问uploads与files这些目录里的php文件,一律返还403。

另外还可能会有些隐藏文件,例如:.htaccess或MacOS的.DS_Store等文件,我也不希望让别人访问,所以在这里也做些限制:

禁止一切以字符“.”开头的文件被访问,一律返还403。

最后是一些静态文件,因为我服务器的架构为LNMPA,在nginx后面是apache,所以访问没有被nginx缓存的文件都需要走proxy到apache。因此静态文件主需要允许GET这种HTTP方式即可,以此提高安全性:

在实际应用中我发现modsecurity在连接数较高的情况下会导致nginx负载居高不下,经过测试发现是因为CRS规则中存在大量的正则匹配规则所导致的。所以针对静态文件,我关闭了modsecurity。

为了精简响应header,我还在server块中增加以下内容:

精简的同时还可以提高安全性,如果需要隐藏某些敏感的响应头,则可以使用这个指令。

最后还有一个sub_filter:

其实我站点在协议为HTTP,而SSL是在nginx中加入的,这样可以减少前后端的握手次数,也方便日后的拓展。

但这里有个问题,因为wordpress的缘故,当使用HTTP协议,所有的链接都是HTTP的,这时候我需要通过nginx的sub_filter模块将其替换为https。

不过这部分内容在日后会交由apache完成,nginx只做SSL加密、缓存与防火墙的工作。

0x04 301跳转

我的站点启用HSTS,强制使用HTTPS协议,所以需要将80端口进入的访客通过301响应引导至HTTPS协议:

以上配置文件中包含一段判断语句,这是因为zabbix agent需要访问http端口,而其他IP的访客一律引导至HTTPS协议。同时我的博客禁止一些恶意的UA访问,在这里也启用了modsecurity进行防护。

另外我的站点使用一级域名作为主域名,还需要将通过www这个二级域名进入的访客通过同样的方法引导至一级域名:

其实这个server块可以与ngx.hk这个server块合并的,但我倾向于尽可能减少判断语句,除非是无法避免的,所以我将这部分也单独提取出来。

0x05 缓存相关

nginx在默认情况下,会根据源服务器的header判断是否应该缓存,而我在wordpress中使用了wp super cache这款插件,所以apache返还的header中有以下内容:

意思是缓存有效期为3秒!这肯定不科学的。

另外还有set-cookie这个header,因为每次的cookie都不同,也会导致nginx缓存命中率低下,总是MISS。

所以需要通过以下指令忽略会导致nginx缓存失败的header:

然后是缓存的配置:

  • proxy_cache:指定缓存zone;
  • proxy_cache_valid:设定不同响应码的缓存时间;
  • proxy_cache_use_stale:当源服务器返还错误时,使用旧的缓存放还给访客。

针对不同的页面,还需要设定不同的缓存过期时间:

最后这个部分比较重要,因为启用proxy_ignore_headers后会导致需要cookie的功能无法使用,影响最大的就是后台功能了,此外还有评论等动态功能。这时候需要使用proxy_pass_header这个指令:

对于一些文件,可以这样设置:

但就算这样,后台功能也会有影响,我们可以使用proxy_cache_bypass与proxy_no_cache这两个指令。

首先设定默认变量:

然后判断cookie是否包含“wordpress_logged_in_”字符,如果是,则修改变量的值:

以上内容主要是判断cookie中是否包含wordpress_logged_in_字符,因为这段cookie只在用户成功登入后才有,所以可以以此为依据确认用户已登入,然后将proxy_cache_bypass与proxy_no_cache两者设为1,也就是on。

这两个指令会使nginx bypass缓存的设定,且不使用proxy缓存。这部分内容我放置在root路径的location块中:

0x06 完整配置

还有一些指令的简介如下:

  • listen:监听443端口并启用http2;
  • gzip:因为gzip与modsecurity不太兼容,所以禁用了modsecurity;
  • proxy_redirect:某些情况下,apache会返还301,而header中的地址为http,需要替换为https。

完成配置修改并重新加载nginx后,header的内容是这样的:

因为我的站点使用CDN加载所有静态资源,所以资源的加载情况是这样的:

可以看到因为没有使用gzip,所以整个页面加载时间用了将近5秒,大小为223kb。但从我服务器中加载的内容也只有页面源码,所以影响还不算太大。

0x07 结语

关闭gzip也确实是无奈,因为要使用modsecurity。另外这个配置文件可以大大地降低后台的加载时间,毕竟静态文件都从缓存获取了: