这是一个非常经典的 Nginx 配置场景,通常用于在同一个 443 端口上混合处理 TCP 透传(L4) 和 SSL 卸载(L7)
要实现这个功能,我们需要利用 Nginx 的 stream 模块配合 ngx_stream_ssl_preread_module。ssl_preread 允许 Nginx 在不解密 SSL/TLS 流量的情况下,读取客户端握手包(ClientHello)中的 SNI(Server Name Indication)信息,从而根据域名进行分流。
核心架构思路
1、Stream 层 (Layer 4): 监听 18443 端口。读取 SNI。
如果是
mail.hopo.dev,直接转发给后端10.44.0.11:10443(透传,不解密)。如果是其他域名,正常的https交互(转发给 本地回环接口,例如 127.0.0.1:443)。
2、HTTP 层 (Layer 7): 监听本地回环端口 (80、443)。
配置 SSL 证书,进行解密。
按照常规 HTTP 配置转发给后端应用。
一、docker快速部署nginx
services:
nginx:
image: nginx:1.25
container_name: nginx
networks:
- app-network
restart: unless-stopped
ports:
- "80:80" # 映射主机80端口到容器80端口(HTTP)
- "443:443" # 映射主机443端口到容器443端口(HTTPS)
- "18443:18443"
volumes:
- ./config/nginx:/config:ro
networks:
app-network:
name: nginx-frpc-network
通过上述配置快速部署带steam模块的nginx,其中18443设置为TCP监听的端口,80以及443分别为HTTP、HTTPS监听端口,
二、Steam模块配置TCP分流
编译/etc/nginx/nginx.conf文件做一下修改
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
# --- Stream 模块配置:负责 443 流量的分流 ---
[++++] stream {
[++++] map $ssl_preread_server_name $backend_name {
[++++] mail.hopo.dev mail_server; # 邮件流量,直接透传
[++++] default local_web_ssl; # 其他流量,转发给本机的 HTTP 模块解密
[++++] }
[++++]
[++++] upstream mail_server {
[++++] server 10.44.0.11:10443;
[++++] }
[++++]
[++++] upstream local_web_ssl {
[++++] server 127.0.0.1:443; # 内部转发端口,用于解密
[++++] }
[++++]
[++++] server {
[++++] listen 18443; # 接收来自 frp 转发的云服务器 443 流量
[++++] ssl_preread on; # 开启 SNI 预读
[++++] proxy_pass $backend_name;
[++++] proxy_connect_timeout 15s;
[++++] proxy_timeout 150s;
[++++] }
[++++] }
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
添加内容如上 [++++] 部分,为了尽可能减少修改配置,TCP层监听设置为监听18443端口,当解析出https流量中的域名信息后,再分析是否解密成http或直接转发https流量。
三、如何为容器添加 sites-enabled 路径解析
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
[++++] include /etc/nginx/sites-enabled/*;
}添加上述include /etc/nginx/sites-enabled/*;内容,重启nginx即可