王锐
王锐
发布于 2026-01-07 / 8 阅读
0
0

四层TCP中SNI域名转发(Nignx高阶配置)

这是一个非常经典的 Nginx 配置场景,通常用于在同一个 443 端口上混合处理 TCP 透传(L4)SSL 卸载(L7)

要实现这个功能,我们需要利用 Nginx 的 stream 模块配合 ngx_stream_ssl_preread_modulessl_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即可


评论