IT

Nginx 配好 HTTPS 后,让 http 自动跳转 https 的完整做法

AI智能摘要

证书配好后,http 还得手动跳 https?其实给 80 端口单独加个 server 块,一条 return 301 就够了。这篇讲清楚标准写法、$host 和 $request_uri 怎么用、改完怎么 nginx -t 再 reload,以及 CDN 在前面时容易踩的坑。

证书配好、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,路径和参数都保留,配置也便于后续维护。

发表评论