证书配好、443 能正常访问之后,下一步就是让所有 http 请求自动跳到 https,避免用户手动敲协议头。结论先说:最稳妥的做法是给 80 端口单独建一个 server 块,只做 301 跳转,业务配置全部留在 443 的 server 块里。不要图省事在同一个 server 里用 if 判断,容易踩坑。
一、先确认证书和 443 已经跑通
跳转是锦上添花,前提是 HTTPS 本身没问题。先确认 443 的 server 块能正常返回页面,证书链完整。可以用浏览器访问,也可以命令行验证:
curl -I https://your-domain.com
# 期望看到 HTTP/2 200 或 301/302,且无证书报错
openssl s_client -connect your-domain.com:443 -servername your-domain.com </dev/null 2>/dev/null | openssl x509 -noout -dates
如果这里就报证书错误,先解决证书路径、权限和证书链问题,再谈跳转。
二、标准写法:80 端口单独一个 server 块
在 nginx.conf 或站点配置文件里,保留原来的 443 server 块不动,另外加一个监听 80 的 server 块,只写 return 301。示例:
server {
listen 80;
listen [::]:80;
server_name your-domain.com www.your-domain.com;
# 所有 http 请求 301 到 https,保留原始路径和参数
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name your-domain.com www.your-domain.com;
ssl_certificate /etc/nginx/ssl/your-domain.com.pem;
ssl_certificate_key /etc/nginx/ssl/your-domain.com.key;
# 这里放你的 location、root、proxy_pass 等业务配置
root /var/www/html;
index index.html;
}
几个要点:
- 用
$host而不是写死域名,多域名或带 www 时更省事;$request_uri会带上路径和查询参数,跳转后不会丢页面。 - 用 301 而不是 302。301 是永久跳转,浏览器和搜索引擎会记住,对 SEO 更友好。
- 如果站点有多个域名,
server_name里都列上,或者用默认 server 兜底。
三、改完必须做的两件事:检查与重载
配置写完不要直接 restart,先 test 再 reload,避免把线上打挂:
nginx -t
# 输出 syntax is ok / test is successful 才继续
systemctl reload nginx
# 或 nginx -s reload
然后验证跳转是否生效,重点看状态码和 Location 头:
curl -I http://your-domain.com/some/path?a=1
# 期望:HTTP/1.1 301 Moved Permanently
# Location: https://your-domain.com/some/path?a=1
如果返回的是 200 而不是 301,说明 80 端口被别的 server 块或默认站点抢先匹配了,检查 server_name 是否重复、是否有 default_server 冲突。
四、几个常见坑
- CDN 或负载均衡在前面:如果流量先经过 CDN/ELB 再到 Nginx,跳转可能被前置层处理,或者 Nginx 看到的协议是 http 导致死循环。这种情况优先在 CDN 侧开“强制 HTTPS”,Nginx 里不要再对回源请求做跳转。
- 不要用 if 判断协议:
if ($scheme = http) { return 301 ... }虽然能跑,但在 server 级别容易和 rewrite 规则打架,独立 server 块更干净。 - HSTS 可选:确认全站 HTTPS 稳定后,可以在 443 块里加
add_header Strict-Transport-Security "max-age=31536000" always;,让浏览器以后直接走 https。但加了之后回退成本高,建议先观察一段时间。
按上面做完,http 访问会自动 301 到 https,路径和参数都保留,配置也便于后续维护。
