大规模子域名http到https迁移核心是跳得准、稳、安全:须用return 301避免泛匹配误跳,统一部署通配符证书并启用sni与tls 1.2/1.3,强制hsts防止首次劫持,代理场景下通过x-forwarded-proto识别真实协议防死循环。

大规模子域名从 HTTP 平滑迁移到 HTTPS,核心不是“能不能跳”,而是“跳得准、跳得稳、跳得安全”。关键在于避免泛匹配误跳、证书管理不统一、HSTS 缺失导致降级、以及代理链中协议感知失效等问题。生产环境必须兼顾兼容性、可观测性和安全性。
一、泛域名 HTTP 跳转必须用 return 301,禁用 rewrite
面对 *.example.com 这类泛域名,rewrite 在高并发下有性能开销,且易因正则捕获异常导致跳转错误(如 https://example.com//path 多斜杠)。推荐使用轻量、语义明确的 return:
server { listen 80; server_name *.example.com; return 301 https://$http_host$request_uri; }-
$http_host保留原始 Host(含端口),比$host更可靠,尤其当用户显式访问http://sub.example.com:8080时也能正确跳转 - 不要在
server_name中混写具体域名和泛域名(如server_name a.example.com *.example.com),Nginx 会按最长匹配优先,可能使泛配置失效
二、HTTPS 配置必须支持通配符证书 + SNI,并启用 TLS 1.2/1.3
单 IP 托管上百子域名,靠为每个子域名单独申请证书不可行。应统一部署由权威 CA 签发的 *.example.com 泛域名证书,并确保:
- Nginx 启动时加载
ssl_certificate和ssl_certificate_key,路径权限设为600,属主为运行用户(如www-data) - 开启 SNI 支持(Nginx 1.15+ 默认开启),让客户端能根据 Host 名选择对应证书
- 强制 TLS 版本:
ssl_protocols TLSv1.2 TLSv1.3;,禁用 TLSv1.0/1.1 和 SSLv2/v3 - 加密套件聚焦前向保密:
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
三、必须添加 HSTS 响应头,防止首次访问被劫持
仅靠 301 跳转无法防御中间人攻击——攻击者可拦截首次 HTTP 请求并阻断重定向。必须在 HTTPS 的 server 块中加入 HSTS:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;-
includeSubDomains确保所有子域名继承策略 -
preload是加入浏览器 HSTS 预加载列表的前提,上线前需确认域名满足预加载要求(如无 HTTP 回退、全站 HTTPS、max-age ≥ 31536000) -
always参数保证 3xx/4xx/5xx 响应也携带该头,避免错误响应绕过安全策略
四、代理场景下需识别真实协议,避免死循环
若 Nginx 前有云 WAF、CDN 或 LB(如阿里云 SLB、AWS ALB),它们终止 HTTPS 后以 HTTP 转发到 Nginx,则 $scheme 永远是 http,直接跳转会无限循环。此时需依赖代理注入的 Header:
- 主流云厂商通常设置
X-Forwarded-Proto: https,Nginx 中用map提取真实协议: - map $http_x_forwarded_proto $real_scheme { default $scheme; https https; }
- 在跳转 server 中改用:
return 301 https://$http_host$request_uri;——但前提是已通过underscores_in_headers on;允许解析带下划线的 header 名 - 同时在 HTTPS server 中补全可信代理 IP 列表:
set_real_ip_from 10.0.0.0/8;(依实际填写),并启用real_ip_header X-Forwarded-For;











