最稳做法是用独立server块写return 301:80端口块仅含listen 80和return 301跳转,443端口块独立配SSL证书与业务逻辑,二者物理隔离、互不干扰,避免rewrite开销与if安全隐患。

直接在独立的 server 块里写 return 301,别用 rewrite,也别塞进 location 里——这是最稳、最安全、最不容易出错的做法。
为什么必须用独立 server 块监听 80 端口
Nginx 的 server 块按 listen 和 server_name 匹配请求,HTTP 跳转和 HTTPS 服务必须物理隔离。把跳转逻辑混进 HTTPS 的 server 块(比如加 listen 80 ssl)会导致配置解析失败或行为不可控。
-
listen 80的server块只处理明文 HTTP 请求,适合做跳转入口 -
listen 443 ssl的server块只处理加密 HTTPS 请求,专注业务响应 - 两个块互不干扰,reload 后各自生效,不会因匹配顺序或正则优先级引发冲突
return 301 比 rewrite 强在哪
rewrite 是正则引擎驱动,走 location 匹配、变量展开、重写循环,开销大、易出错;return 是立即响应,不进任何匹配流程,语义清晰、性能高、无副作用。
-
rewrite ^(.*)$ https://$host$1 permanent;→ 返回 302(漏permanent),或触发内部重定向循环 -
if ($scheme = http) { return 301 https://$host$request_uri; }→if在server上下文虽可用,但 Nginx 官方明确不推荐,且$host可被恶意构造(如 Host: evil.com),导致开放重定向 -
return 301 https://www.example.com$request_uri;→ 目标域名硬编码,不依赖用户输入,防劫持
如何防 $host 导致的开放重定向
只要用了 $host 或 $server_name 动态拼 URL,就存在被伪造 Host 头跳转到任意域名的风险。生产环境必须规避。
- 禁止直接写
return 301 https://$host$request_uri; - 若需多域名统一跳转,用
if+ 正则白名单:if ($host ~ ^(example\.com|www\.example\.com)$) { return 301 https://www.example.com$request_uri; } - 更推荐分拆
server块:为每个合法域名单独配一个listen 80块,里面写死目标地址 - 对非法 Host 或 IP 直连,设默认
server块返回return 444;(直接断连)或return 403;
404 页面也要跳转?得用命名 location 中转
error_page 404 不能直接跟 return,Nginx 不允许这种写法。强行写会报配置错误或静默失效。
- 错误写法:
error_page 404 return 301 https://example.com/;→ 语法不通过 - 正确写法:
error_page 404 = @notfound;,再定义location @notfound { return 301 https://example.com$request_uri; } - 注意
=符号不能省——它表示“内部重定向到该命名 location”,缺了就变成返回静态页 - 命名 location 里别用
rewrite,否则可能触发rewrite or internal redirection cycle日志报错
真正麻烦的不是写几行配置,而是搞清 Nginx 请求处理阶段:什么时候匹配 server,什么时候进 location,error_page 是怎么中转的。跳转逻辑一旦跑偏,日志里全是 302、497、500,查起来比重写还费劲。


















