跳转至

使用Nginx实现TCP反向代理

1. 手动编译

需要注意的是,使用 DockerHub 中的 Nginx 镜像是不用二次编译的。

# 下载1.9版本以上的nginx
wget http://nginx.org/download/nginx-1.10.3.tar.gz

# 安装依赖包
yum install -y gcc glibc gcc-c++ prce-devel openssl-devel pcre-devel
useradd -s /sbin/nologin nginx -M

# 加压目录
tar xf nginx-1.10.3.tar.gz & &  cd nginx-1.10.3

# 手动编译
./configure \
    --prefix=/usr/local/nginx-1.10.3 \
    --user=nginx \
    --group=nginx \
    --with-http_ssl_module \
    --with-http_stub_status_module \
    --with-stream

# 安装到系统上
make & &  make install

# 检查配置文件
/usr/local/nginx/sbin/nginx -t

2. TCP 转发

我们能很明显的发现,stream 模块的配置其实跟 http 模块很类似。
但实际上 stream 模块与 http 模块上完全是两套不同的处理流程。
用最简单的说法就是,http 模块是基于 Layer7 层的应用层处理流程,而 Stream 仅在 Layer4 层上对连接进行处理。

所以 stream 模块无法像 http 模块那样能区分 vhost 主机名,然而这 stream 模块在引入了 ssl 配置之后又能支持了。
而且 stream 模块还能引入 ssl/tls 来对 TCP 连接进行加密。
由于 TLS 标准内对 SNI 提供了支持,所以又能识别主机名了。
在理论上,stream 模块的端口转发效率实际上相比 http 模块的反向代理效率更高。

user  nginx;
worker_processes  1;

events {
    worker_connections  1024;
}

stream {
    # 全局配置
    preread_timeout        120s;
    proxy_connect_timeout  120s;
    proxy_protocol_timeout 120s;
    resolver_timeout       120s;
    proxy_timeout          120s;
    tcp_nodelay            on;

    # 设置日志格式
    log_format proxy '$remote_addr [$time_local] '
                  '$protocol $status $bytes_sent $bytes_received '
                  '$session_time "$upstream_addr" "$upstream_bytes_sent"'
                  '"$upstream_bytes_received" "$upstream_connect_time"';

    access_log /var/log/nginx/stream.access.log proxy;
    error_log  /var/log/nginx/stream.error.log error;

    upstream app_pg {
        hash $remote_addr consistent;
        server 192.168.100.60:5432;
        server 192.168.100.61:5432;
        server 192.168.100.62:5432;
    }

    server {
        # 不指定协议默认是TCP协议
        listen 127.0.0.1:5432 so_keepalive=on;
        proxy_pass app_pg;
    }

    server{
        # keepalive的可配置参数差不多有以下几个:keepidle,keepintvl,keepcnt
        # keepidle为连接保持时间;keepintvl为连接的间隔时间;keepcnt是连接的个数

        # 下示将idle超时设置为30分钟,探测间隔为系统默认值,并将探测计数设置为10个探测器
        # 实际配置的格式为:so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]
        listen *:3306 so_keepalive=30m::10;
        proxy_connect_timeout 10s;
        proxy_timeout 20s;
        proxy_buffer_size 512k;
        proxy_pass 192.168.100.60:8000;
    }
}
user  nginx;
worker_processes  1;

events {
    worker_connections  1024;
}

stream {
    upstream ssh {
            hash $remote_addr consistent;
            server 192.168.1.42:22 weight=5;
       }

    server {
        listen 2222;
        proxy_pass ssh;
       }
}

3. UDP 转发

以下的配置就是 UDP 转发的最简配置

user  nginx;
worker_processes  1;

events {
    worker_connections  1024;
}

stream {
    # 全局配置
    proxy_timeout 120s;
    tcp_nodelay on;

    # 设置日志格式
    log_format proxy '$remote_addr [$time_local] '
                 '$protocol $status $bytes_sent $bytes_received '
                 '$session_time "$upstream_addr" '
                 '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';

    access_log /var/log/nginx/stream.access.log proxy;
    error_log /var/log/nginx/stream.error.log error;

    # 配置dns负载均衡
    upstream dns_upstreams {
        server 1.1.1.1:53 weight=1;
        server 1.0.0.1:53 weight=1;        # weight负载均衡权重
        server 8.8.8.8:53 weight=1 backup; # backup标记为备用服务器
    }

    server{
        listen 53 udp;
        proxy_responses 1; # UDP协议专用;期望后端返回给客户端数据包的数量
        proxy_timeout 20s; # 超时时间
        proxy_pass dns_upstreams;
    }
}