最稳妥方式是用独立80端口server块配合server_name精准匹配域名并return 301跳转;http与https配置必须物理分离,禁止在443块中用if判断scheme;推荐return 301 https://$host$request_uri;,避免写死域名或混用$host与$server_name。

直接用 server_name 配合独立的 80 端口 server 块实现跳转,是最稳妥、官方推荐的方式。关键不是“靠 server_name 判断协议”,而是让它精准匹配请求域名,再用 return 301 安全跳转。
必须用独立的 80 端口 server 块
HTTP 和 HTTPS 的配置必须物理分离。不能在监听 443 的 server 块里加 if ($scheme = http) { return 301 ... } —— Nginx 启动会直接报错拒绝加载。
- 专门开一个只监听
80的server,不配任何 SSL 指令 -
server_name必须和你 HTTPS 站点完全一致(支持空格分隔多个域名) - 这个块只做一件事:收到 HTTP 请求,立刻 301 跳转
正确写 return 语句,别用 rewrite 或 if
return 301 https://$host$request_uri; 是首选。它轻量、无正则开销、语义清晰,且能保留用户实际访问的 Host 和完整路径。
- 用
$host(来自请求头)比$server_name更贴近真实访问地址,尤其适合多域名或 CDN 场景 - 避免写死域名如
https://example.com,否则换域名或加子域时要改多处 - 严禁在
location内用if判断$scheme或$server_port,性能差且易出逻辑漏洞
多域名或防 IP 直连的安全处理
如果 server_name 设了多个域名(如 a.com b.com),但又担心用户用 IP 或非法 Host 头访问,导致 $host 不可信甚至为空,可加一层过滤:
- 显式限制跳转范围:
if ($host ~ ^(a\.com|b\.com)$) { return 301 https://$host$request_uri; } - 或单独定义一个默认
server块监听 80,server_name _;,里面写return 444;或return 403;,彻底屏蔽非预期访问 - 不建议混用
$host和$server_name在同一配置中,容易引发跳转目标异常(比如跳到https:///path)
完整可运行示例
以下配置可直接保存为 /etc/nginx/conf.d/your-site.conf,执行 nginx -t && nginx -s reload 生效:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /ssl/example.com.crt;
ssl_certificate_key /ssl/example.com.key;
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;
}
}











