申请到 SSL 证书之后,还需要把所有 HTTP 流量强制跳转到 HTTPS,并配置 HSTS 头部,否则用户直接输入 http:// 还是会走明文通道。本文讲清 Nginx 中 301 跳转的写法、HSTS 配置以及如何排查混合内容问题。

本文要点

  • 用 Nginx return 301 强制 HTTP 跳转到 HTTPS
  • HSTS 头部的作用、写法与 preload 注意事项
  • 什么是混合内容,如何定位与修复
  • 验证跳转与安全头部是否生效

为什么仅有证书还不够

Let's Encrypt 证书只让 443 端口可以跑 HTTPS,但 80 端口的 HTTP 服务默认仍然存在。如果用户手动输入 http://example.com 或点击旧的 HTTP 链接,还是会走不加密的连接。必须明确配置 301 跳转,强制所有流量走 HTTPS。

Nginx 301 跳转配置

在 Nginx 配置中添加一个专门监听 80 端口的 server 块,把所有 HTTP 请求重定向到 HTTPS:

# HTTP → HTTPS 强制跳转
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    # 永久重定向到 HTTPS(301)
    return 301 https://$host$request_uri;
}

# HTTPS 主站配置
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name example.com www.example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    root  /var/www/example;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

301 vs 302

使用 301(永久重定向)而非 302(临时重定向)。301 会被浏览器缓存,下次直接走 HTTPS,减少一次 RTT;而且对 SEO 也更友好。

配置 HSTS

HSTS(HTTP Strict Transport Security)告诉浏览器:在 max-age 指定的时间内,对该域名的所有请求都直接走 HTTPS,不需要先发 HTTP 再重定向,彻底消除那次跳转的窗口期。

# 在 HTTPS server 块内的 location / 或 server 级别添加:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
参数含义建议值
max-age强制 HTTPS 的时长(秒)31536000(1 年)
includeSubDomains对所有子域名同样生效根据需要添加
preload申请加入浏览器内置 HSTS 列表谨慎使用,撤销成本极高

preload 慎用

加入 preload 意味着即使你删除 HSTS 头,主流浏览器也会在相当长时间内强制 HTTPS,撤销过程繁琐。正式启用 preload 前请确认所有子域名都有正常 SSL。

SSL 协议与加密套件优化

在 HTTPS 块内补充以下配置,禁用旧版不安全协议:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;

混合内容问题

什么是混合内容

HTTPS 页面中通过 HTTP 加载图片、JS、CSS 等资源,称为混合内容(Mixed Content)。浏览器会警告甚至拦截,导致样式丢失或脚本不执行。

如何定位

  1. 打开浏览器开发者工具(F12)
  2. 切换到 Console 标签,查找 Mixed Content 警告
  3. 或在 Network 标签中筛选 http:// 开头的资源

如何修复

  • 把页面中所有 HTTP 链接改为 HTTPS 或协议相对路径(//example.com/style.css
  • 在 Nginx 中添加 CSP 升级头:add_header Content-Security-Policy "upgrade-insecure-requests";

验证跳转与安全头

# 验证 301 跳转
curl -I http://example.com
# 应看到 HTTP/1.1 301 Moved Permanently 和 Location: https://...

# 验证 HTTPS 响应头
curl -I https://example.com
# 应看到 Strict-Transport-Security 头

推荐在线检测工具

访问 SSL Labs(ssllabs.com/ssltest) 输入域名,可得到详细的 SSL 配置评分报告,帮助发现弱协议、弱加密套件等问题。

小结

  • 80 端口 server 块用 return 301 https:// 做永久跳转
  • HTTPS 块内加 HSTS 头,让浏览器记住强制走 HTTPS
  • 禁用 TLS 1.0/1.1,只保留 1.2 和 1.3
  • 用 curl -I 和 SSL Labs 验证配置效果

常见问题

配置跳转后网站出现重定向循环怎么办?

通常是 Cloudflare 等 CDN 的 SSL 模式设置为「灵活」,导致 CDN→源站走 HTTP 又被跳转。把 CDN 的 SSL 模式改为「完全」或「完全(严格)」即可解决。

HSTS 设置后能取消吗?

可以删除响应头,但浏览器需等待 max-age 过期才会停止强制 HTTPS。若设置了 preload,还需要向各浏览器提交移除申请,周期较长。

return 301 和 rewrite 哪个更好?

推荐 return 301,写法简洁、性能更好,Nginx 不需要执行正则匹配就能直接返回响应。