把一台裸服务器变成能跑 HTTPS 的站点,配置本身并不复杂,真正容易出问题的是那些「看起来没问题」的细节。这篇记录完整的操作顺序,以及我在安卓端踩到的证书链坑。
一、准备证书
域名解析生效后,直接用 certbot 申请即可。它会同时改好 Nginx 配置并设置自动续期:
apt install -y certbot python3-certbot-nginx
certbot --nginx -d it365.wang -d www.it365.wang
# 验证自动续期是否就绪(不会真的续期)
certbot renew --dry-run要注意 certbot 写入的配置会覆盖你手工加的 location 块,所以顺序上建议 先让它改完、再手工调整。
二、反向代理配置
后端跑在 127.0.0.1:8080,前端由 Nginx 接管:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name it365.wang;
ssl_certificate /etc/letsencrypt/live/it365.wang/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/it365.wang/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}几个容易漏掉的响应头,建议一并补上:
| 响应头 | 作用 |
|---|---|
Strict-Transport-Security | 让浏览器记住只用 HTTPS 访问 |
X-Content-Type-Options | 阻止浏览器猜测 MIME 类型 |
X-Frame-Options | 避免站点被嵌入 iframe 钓鱼 |
2.1 强制跳转 HTTPS
单独监听 80 端口并做 301:
server {
listen 80;
server_name it365.wang www.it365.wang;
return 301 https://it365.wang$request_uri;
}不要用rewrite ... permanent来做这件事。它在某些location组合下会丢掉查询字符串,而return 301不会。
三、踩到的坑
- 证书链不全:只部署
cert.pem时桌面浏览器正常,但安卓与部分 App 内嵌 WebView 会直接握手失败。一定要用fullchain.pem。 - 漏掉
X-Forwarded-Proto:后端以为自己在跑 HTTP,把绝对地址拼成http://,于是出现混合内容告警。 - 只监听 IPv4:双栈机器上不写
listen [::]:443 ssl;就不会响应 IPv6 请求。
排查握手问题最快的办法是直接问 openssl:
openssl s_client -connect it365.wang:443 -servername it365.wang \
</dev/null 2>/dev/null | openssl x509 -noout -subject -issuer如果输出里只有一个证书、没有中间证书,基本就能确定是链不全。
四、小结
记住三点:先让工具改配置、再手工优化;证书用 fullchain;跳转用 return 而不是 rewrite。剩下的交给 certbot renew --dry-run 定期体检即可。