Nginx 四层代理 stream
前面章节的 http 块工作在七层,能读懂 URL、Host、Cookie 并做缓存改写;而 MySQL、Redis、DNS 这类协议 Nginx 无法解析内容,只能做四层代理把 TCP/UDP 流量原样转发。stream 模块就是干这个的。
stream 与 http 的区别
| 对比项 | http 模块 | stream 模块 |
|---|---|---|
| 工作层次 | 七层(应用层) | 四层(传输层) |
| 能看到的 | URL、Host、Header、Cookie | 只有 IP 与端口 |
| 典型用途 | 网站、API 反向代理 | 数据库、缓存、消息队列、DNS 转发 |
| 配置位置 | http { } 块 | stream { } 块(与 http 平级的顶层块) |
stream 默认不编译,需要 --with-stream,可用 nginx -V 确认:
nginx -V 2>&1 | grep -o 'with-stream'
# 输出:with-stream (无输出则需重新编译)
TCP 转发与四层负载均衡
把本机 3306 转发到内网 MySQL,或对一组后端做 TCP 轮询:
stream {
upstream mysql_pool {
server 10.0.0.11:3306;
server 10.0.0.12:3306;
}
server {
listen 3306; # 对外监听端口
proxy_pass mysql_pool; # 转发到 upstream 组(四层负载均衡)
proxy_timeout 30s; # 两次读写之间的超时
}
server {
listen 6380;
proxy_pass 127.0.0.1:6379; # 简单转发到本机 Redis
}
}
mysql -h 网关IP -P 3306 -u app -p # 客户端像连数据库一样连 Nginx
redis-cli -h 网关IP -p 6380 ping # 输出:PONG
SSL 透传
后端是 HTTPS/TLS 服务时,可以让 Nginx 不解密、原样转发密文,证书在后端维护,转发开销最小:
stream {
server {
listen 443;
proxy_pass 10.0.1.2:443; # 密文透传,Nginx 不参与 TLS 握手
}
}
若想在一台机器上按域名把 443 分流到不同后端,可编译 --with-stream_ssl_preread_module,用 SNI 路由(简提):
stream {
map $ssl_preread_server_name $backend {
a.example.com 10.0.1.2:443;
b.example.com 10.0.1.3:443;
}
server {
listen 443;
proxy_pass $backend; # 按 SNI 域名选择后端
ssl_preread on;
}
}
UDP 转发
给监听加 udp 参数即可转发 UDP,典型场景是内网 DNS 网关:
stream {
server {
listen 53 udp reuseport; # reuseport 提升多 worker 收包性能
proxy_pass 223.5.5.5:53; # 转发到公共 DNS
}
}
nslookup www.example.com 网关IP # 通过 Nginx 出口查 DNS
小结
stream 是与 http 平级的顶层配置块:编译带 --with-stream 后,在 stream {} 里 listen 端口 + proxy_pass 目标即可完成 MySQL/Redis 等 TCP 转发、UDP 转发与 SSL 透传。记住"能读懂 URL 用 http、只认端口用 stream"即可选型无忧。