proxy_pass 中的静态 DNS 解析¶
Gixy 检查 ID:missing_resolver
检测 proxy_pass(及相关指令)配置,其中主机名仅在 nginx 启动时解析,可能导致请求被发送到过时的 IP 地址。
为什么这很重要¶
当您在 proxy_pass 中直接使用主机名时:
proxy_pass https://api.example.com;
Nginx 在启动时只解析一次 DNS 并永久缓存该 IP。如果 IP 更改(这在云负载均衡器、CDN 或故障转移场景中很常见),nginx 将继续向旧 IP 发送流量,直到重启。
这可能导致: - 当后端 IP 更改时服务中断 - 如果旧 IP 被分配给恶意行为者,则存在安全问题 - 使用基于 DNS 的负载均衡时负载均衡失败
智能检测:反向逻辑¶
此插件使用反向逻辑以获得最大覆盖范围和安全性:
我们不是尝试识别公共域(没有 Public Suffix List 是不可能的),而是识别什么是绝对内部的,并标记其他所有内容。
这种方法更好,因为:
- ✅ 无外部依赖 — 不需要 PSL、tldextract 或任何库
- ✅ 无硬编码的 TLD 列表会过时
- ✅ 新 TLD 自动标记 — .ai、.xyz、.whatever 都会被捕获
- ✅ 更安全 — 对于安全工具,误报比漏报更好
- ✅ 面向未来 — 适用于任何将来存在的域
🔥 云提供商检测(高严重级别)¶
自动检测 50 多种 IP 频繁更改的云提供商模式: - AWS:ELB、CloudFront、API Gateway、Elastic Beanstalk、Lambda URLs、S3、Amplify、Global Accelerator - Google Cloud:Cloud Run、Cloud Functions、App Engine、Firebase、Google APIs - Azure:App Service、API Management、CDN、Traffic Manager、Front Door、Static Web Apps - Cloudflare:Workers、Pages、R2 - CDN:Akamai、Fastly、CDN77、StackPath、KeyCDN、BunnyCDN - PaaS:Heroku、Vercel、Netlify、Railway、Render、Fly.io、Deno Deploy、Supabase、Neon、PlanetScale - Cloud:DigitalOcean、Linode、Vultr、Scaleway、Hetzner、UpCloud
🐳 容器编排感知¶
自动跳过内部服务发现模式:
- Kubernetes:.svc.cluster.local、.pod.cluster.local、.default.svc
- Docker:.docker.internal、.docker.localhost
- Consul:.service.consul、.node.consul、.query.consul
- HashiCorp:.vault、.nomad
- Mesos/Marathon:.marathon.mesos、.dcos
- Rancher:.rancher.internal
- AWS Internal:.ec2.internal、.compute.internal
- OpenStack:.novalocal、.openstacklocal
🎯 符合 RFC 的保留 TLD 检测¶
识别 RFC 2606/6761/6762/7686 保留 TLD:
- .test、.example、.invalid(RFC 2606)
- .localhost(RFC 6761)
- .local(RFC 6762 — mDNS/Bonjour)
- .onion(RFC 7686 — Tor)
🔍 Resolver 指令检查¶
检测当您使用变量但忘记配置 resolver 指令的情况:
# 没有 resolver 指令,这不会重新解析!
set $backend api.example.com;
proxy_pass http://$backend; # ← 插件会警告缺少 resolver
📦 Upstream 分析¶
检查 upstream 块中没有 resolve 参数的服务器:
upstream backend {
server api.example.com; # ← 没有 'resolve' = 静态 DNS
}
触发此检查的条件¶
| 模式 | 严重级别 | 示例 |
|---|---|---|
| 云提供商端点 | 高 | proxy_pass https://my-app.herokuapp.com; |
| 公共域主机名 | 中等 | proxy_pass https://api.example.com; |
| 没有 resolver 的变量 | 中等 | set $x host.com; proxy_pass http://$x; |
| 没有 resolve 的 Upstream | 中等 | upstream { server host.com; } |
不触发的情况(避免的误报)¶
- ✅ IP 地址(不需要 DNS 解析)
- ✅ Unix 套接字(
unix:/path/to/socket) - ✅ 内部域(
.internal、.local、.lan、.corp、.home等) - ✅ 单标签主机名(
proxy_pass http://backend;) - ✅ Kubernetes 服务(
.svc.cluster.local) - ✅ Consul 服务(
.service.consul) - ✅ Docker internal(
.docker.internal) - ✅ 带变量且配置了 resolver 的 URL
- ✅ 带
resolve参数的 upstream 服务器
示例¶
错误:云提供商端点(高严重级别)¶
# 严重:AWS ELB IP 经常变化!
location /api {
proxy_pass https://my-app-123456789.us-east-1.elb.amazonaws.com;
}
错误:静态主机名(中等严重级别)¶
# DNS 在启动时只解析一次
location /api {
proxy_pass https://api.example.com;
}
错误:没有 resolver 的变量¶
# 仅变量不能启用重新解析!
set $backend api.example.com;
proxy_pass http://$backend;
错误:没有 resolve 的 Upstream¶
upstream backend {
server api.example.com:8080; # 没有 resolve 参数
}
server {
location / {
proxy_pass http://backend;
}
}
正确:带 resolver 的变量¶
resolver 8.8.8.8 valid=30s;
server {
location /api {
set $backend api.example.com;
proxy_pass https://$backend;
}
}
正确:带 resolve 的 Upstream(nginx 1.27.3+)¶
resolver 8.8.8.8;
upstream backend {
server api.example.com:8080 resolve;
}
server {
location / {
proxy_pass http://backend;
}
}
正确:内部服务(自动跳过)¶
# Kubernetes 服务 — 插件知道这是内部的
proxy_pass http://api-service.default.svc.cluster.local;
检查的指令¶
此插件分析所有与代理相关的指令:
- proxy_pass
- fastcgi_pass
- uwsgi_pass
- scgi_pass
- grpc_pass
配置¶
在 .gixy.yml 中禁用此插件:
plugins:
missing_resolver: false