nginx全站https强制跳转时,需通过map或location+allow/deny放行内网ip段(如172.16.0.0/12、192.168.0.0/16)对特定路径的http访问,其余流量统一301跳转;443端口须完整配置ssl证书、tls协议及反向代理,确保https服务正常。

当全站开启 HTTPS 强制跳转后,某些内部系统、测试终端或运维工具仍需通过 HTTP 访问特定路径(如人机验证回调接口、监控探针、内网调试页),而这些请求往往来自固定 IP 段(如 172.16.0.0/12 或 192.168.0.0/16)。Nginx 默认的全局 301 跳转规则无法区分来源 IP,直接导致这些合法 HTTP 请求被强制重定向,引发业务异常。解决关键在于:在 80 端口 server 块中,**先匹配并放行指定 IP 段,再对其他所有流量执行 HTTPS 跳转**。
基于 $remote_addr 的条件判断跳转
Nginx 不支持 if 嵌套或复杂逻辑,但可通过多个 location + map 指令或更稳妥的 if + return 组合 实现精准控制。推荐使用以下结构(放在 listen 80 的 server 块顶部):
- 定义一个变量标识是否跳转,初始设为 1(需跳转)
- 用 if 判断 $remote_addr 是否属于白名单网段,命中则设该变量为 0
- 在最后统一判断变量值,为 1 时执行 301 跳转
示例配置:
map $remote_addr $skip_https_redirect {
default 1;
~^172\.16\. 0;
~^192\.168\. 0;
~^10\. 0;
}
<p>server {
listen 80;
server_name example.com;</p><pre class="brush:php;toolbar:false;">if ($skip_https_redirect = 1) {
return 301 https://$host$request_uri;
}
# 后续 location 可正常处理白名单 IP 的 HTTP 请求
location /verify/ {
proxy_pass http://backend_verify;
# 允许内网直接调用人机验证服务
}}
用 location ^~ 配合 allow/deny 实现路径级豁免
若只需对某几个路径(如 /captcha/、/healthz)开放 HTTP 访问,且仅限内网 IP,可结合 location ^~ 前缀匹配与访问控制指令:
- ^~ 表示前缀匹配且不进入正则匹配阶段,优先级高、性能好
- 在该 location 内明确允许指定网段,拒绝其余所有 IP
- 不写 rewrite 或 return,即保留原始 HTTP 协议
配置片段:
server {
listen 80;
server_name example.com;
<pre class="brush:php;toolbar:false;"># 专供内网健康检查和验证回调的 HTTP 接口
location ^~ /healthz/ {
allow 172.16.0.0/12;
allow 192.168.0.0/16;
deny all;
proxy_pass http://monitor_backend;
}
location ^~ /captcha/ {
allow 172.16.0.0/12;
deny all;
proxy_pass http://captcha_service;
}
# 其他所有未匹配路径,全部 301 到 HTTPS
return 301 https://$host$request_uri;}
注意 SSL 证书与 443 端口的配套配置
即使部分路径允许 HTTP 访问,HTTPS 服务本身仍需正常启用。确保 443 端口 server 块完整配置了证书、协议和 cipher,并与 80 端口保持一致的 server_name:
- ssl_certificate 和 ssl_certificate_key 路径必须正确,权限为 600
- 建议启用 ssl_prefer_server_ciphers 和 TLSv1.2+ 协议
- 避免在 443 块中重复写 return 或 rewrite,防止循环或冲突
典型 HTTPS server 示例:
server {
listen 443 ssl http2;
server_name example.com;
<pre class="brush:php;toolbar:false;">ssl_certificate /etc/nginx/ssl/example.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
location / {
proxy_pass http://web_backend;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
}}
验证与调试要点
上线前务必逐项验证,避免误阻断或跳转失效:
- 用 curl -I http://example.com/healthz -x "" --local-port 192.168.10.5 测试内网 IP 是否返回 200
- 用外网 IP 访问同一路径,确认返回 403(deny all 生效)
- 用非白名单 IP 访问首页,确认返回 301 且 Location 头为 https://
- 执行 nginx -t 检查语法,再 nginx -s reload 生效配置
- 查看 error.log 中有无 “client denied by rule” 或重写失败日志
不复杂但容易忽略。











