Nginx配置HTTPS踩坑全记录,差点把网站搞挂
上周给我的博客加HTTPS,本以为半小时搞定,结果折腾了一整个下午。写下来给同样折腾的人提个醒。
申请证书
我用的是Let's Encrypt,certbot一键申请嘛,能有什么问题?
问题出在我之前把80端口关了。certbot验证域名的时候需要通过80端口放一个验证文件,端口关了自然验证不过。报错信息还特别不明确,就说什么"connection refused",我一开始还以为是防火墙的问题。
开80端口之后证书申请很顺利。但这时候我犯了个蠢——没看certbot的输出就以为它会自动配置Nginx。实际上certbot只生成了证书文件,Nginx配置还是得自己改。
配置Nginx
改配置的时候我参考了一篇2022年的教程,里面推荐了这个配置:
server {
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
...
}
看着没问题对吧?我改完之后 nginx -t 测试通过,reload。然后网站就打不开了。
原因是我把原来的 listen 80 那个server块删了!以为有了443就不需要80了。但实际上很多用户访问的时候还是输入 http:// 开头的URL,80端口不监听的话这些请求直接被拒绝了。
正确的做法是保留80端口的server块,加一个301跳转到443:
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
这一步解决之后网站能通过HTTPS访问了,我松了口气。结果发现CSS全炸了。
混合内容问题
浏览器在你用HTTPS访问的时候,如果页面里有HTTP的资源(图片、脚本、CSS),它会拦截。这就是所谓的"混合内容"。
我博客里有一堆旧的图片链接还是 http:// 开头的……还有一个百度统计的JS也是http的。改起来倒是不难,但烦的是你要一个一个找。
后来发现一个技巧:在head里加 <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> 可以自动把HTTP请求升级为HTTPS。但这个只是临时方案,正经还是要改源文件里的链接。
HSTS
最后加上了HSTS头,告诉浏览器"以后都用HTTPS访问我":
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
但注意!加上这个之后如果你想回退到HTTP,浏览器在一年内都会强制用HTTPS访问。所以先小max-age试几天,确认没问题了再加大。
最终配置
我最后的Nginx配置大概长这样(简化版):
server {
listen 80;
server_name blog.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name blog.example.com;
ssl_certificate /etc/letsencrypt/live/blog.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/blog.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
add_header Strict-Transport-Security "max-age=31536000" always;
root /var/www/blog;
index index.html;
}
整个过程大概4个小时,其中3个半小时在排查问题。但弄完之后看着地址栏那个小锁头,还是挺有成就感的。
对了,别忘了设置证书自动续期!certbot renew --dry-run 跑一下确认cron任务正常就行。忘了这步的话3个月后证书过期,你就又得折腾一遍了……
还木有评论哦,快来抢沙发吧~