Nginx TCP代理白名单需在stream模块的server块内用allow/deny指令配置,支持IPv4/IPv6 CIDR,必须以deny all结尾;多服务需独立配置;高版本可用geo+if实现动态控制。

在 Nginx 的 TCP 代理(stream 模块)中配置白名单,核心是使用 stream_access_module 提供的 allow/deny 指令——它和 HTTP 层的同名指令语法一样,但属于不同模块,必须用在 stream { } 内的 server { } 块中,不能写在顶层或 upstream 里。
白名单规则必须写在 server 块内
stream 上下文不支持 HTTP 模块的访问控制,直接在 stream 块里写 allow 会报错 “unknown directive”。正确位置是每个监听服务的 server 块内部:
- 监听端口、设置 proxy_pass 后,紧接着写访问控制规则
- 每条
allow对应一个可信 IP 或网段(支持 IPv4 CIDR 和 IPv6) - 最后必须显式写
deny all;,否则未匹配的连接默认放行
典型 TCP 白名单配置示例
比如只允许内网访问数据库代理(3306 端口):
stream {
upstream backend_db {
server 192.168.5.10:3306;
}
server {
listen 3306;
proxy_pass backend_db;
allow 10.0.0.0/8;
allow 172.16.0.0/12;
allow 192.168.0.0/16;
allow 127.0.0.1;
deny all;
}
}
注意:规则按顺序匹配,第一条命中即生效;IPv6 示例如 allow 2001:db8::/32; 同样有效。
多 server 隔离配置,避免互相影响
一台 Nginx 可能代理多个 TCP 服务(如 Redis、MySQL、SMTP),每个 server 块要独立配白名单:
- Redis 服务(6379)可只放行运维网段
- MySQL 服务(3306)可只放行应用服务器网段
- 不能把所有
allow堆在一个 server 里,也不能跨 server 复用规则
进阶:用 geo + if 实现动态白名单(Nginx ≥ 1.19)
当 IP 列表较多或需定期更新时,推荐用 geo 预定义变量,再在 server 中判断:
stream {
geo $is_allowed {
default 0;
192.168.10.0/24 1;
2001:db8:1::/64 1;
}
server {
listen 22;
proxy_pass ssh_backend;
if ($is_allowed = 0) {
close;
}
}
}
注意:stream 中 if 不支持 return,只能用 close 主动断连;geo 必须定义在 stream 块顶层,不能放在 server 内。


















