概述
一般来说,给站点申请了安全证书以后,都会希望访问者强制使用HTTPS来进行连接。HTTP强制跳转HTTPS通常有两种方法,一种是对整个域名使用正则表达式来进行rewrite重写,另外一种是通过301跳转来处理。Nginx官方并不推荐前者,其原文如下:
https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#taxing-rewrites
1 2 3 4 5 6
| # 不好的方法: rewrite ^/(.*)$ http://example.com/$1 permanent; # 好的方法: rewrite ^ http://example.com$request_uri? permanent; # 更好的方法: return 301 http://example.com$request_uri;
|
因此,对于HTTP强制跳转HTTPS的语句,应当写成:
1
| return 301 https://$server_name$request_uri;
|
默认配置
对于自己手动编译安装的Nginx,其默认配置文件nginx.conf
将80端口和443端口(默认被注释)的监听分别写进了两个server段中,这是一种非常符合生产环境的标准做法。因此,只需要将上述语句直接复制到80端口对应的server段中,同时将该段中的location配置全部复制到443端口对应的server段中即可。类似如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| server { listen 443 ssl; server_name yourname.com;
ssl_certificate /dir/xx.crt; ssl_certificate_key /dir/xx.key; ssl_dhparam /dir/dhparam.pem;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+EXP;
location / { root /your/wwwroot/; index index.html index.htm index.jsp index.do; } }
server { listen 80; server_name yourname.com; return 301 https://$server_name$request_uri; location / { root /your/wwwroot/; index index.html index.htm index.jsp index.do; } }
|
LNMP环境配置
如果你的LNMP环境使用的是流行的一键安装包,那么问题就来了。这个脚本生成的nginx.conf中没有443端口的server字段,因此在配置SSL证书的时候,有些人为了省事,可能会直接将443端口的监听一起写到server字段中,类似这种:
1 2 3 4 5 6 7 8 9 10 11 12 13
| server { listen 80; listen 443 ssl; ssl_certificate /dir/xx.crt; ssl_certificate_key /dir/xx.key; ssl_dhparam /dir/dhparam.pem; server_name www.yourname.com yourname.com;
index index.html index.htm index.php; root /your/wwwroot/; }
|
那么如果你直接使用return 301 https://$server_name$request_uri;
,由于443端口和80端口在同一个server段监听,就会产生内部无限循环。当用户访问时,就会出现“重定向次数过多(ERR_TOO_MANY_REDIRECTS)”的错误。
正确的方法,使用IF判定,只对HTTP连接进行重定向:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| server { listen 80; listen 443 ssl; ssl_certificate /dir/xx.crt; ssl_certificate_key /dir/xx.key; ssl_dhparam /dir/dhparam.pem; server_name www.yourname.com yourname.com; if ( $scheme = http ){ return 301 https://$server_name$request_uri; } index index.html index.htm index.php; root /your/wwwroot/; }
|
但Nginx官方并不推荐过多的IF判定(可参考:https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/ )。
因此最好还是像Nginx默认配置文件那样,将80端口和443端口的监听区分开,同时采用第一种跳转方法,这也是更符合生产环境的一种做法。