nginx 反向代理一般都是7层代理,进行http/https 协议层的转发;说起4层代理,一般想到的都是lvs 和 haproxy 这些;目前nginx新版本已经支持 4层 (tcp,udp) 代理;
在Nginx1.9.0版本之前,TCP代理一般会使用Haproxy或Nginx的第三方包nginx_tcp_proxy_module。但Nginx在1.9.0版本之后加入了ngx_stream_proxy_modulea,它提供了TCP代理,只需在编译Nginx时加入----ngx_stream_proxy_module即可。
在1.9.13版本之后,Nginx加入了对UDP(UserDatagramProtocol)代理的支持,因此可以使用Nginx来代理DNS的UDP端口;
[root@network-test nginx-1.19.2]# ./configure --help
# --with-stream 开启tcp/udp 代理;一般是初次安装的时候使用;
# --with-stream=dynamic 动态开启tcp/udp;存量已安装的nginx 下动态支持
# 这次使用动态升级的方法,在原始参数后面添加 –with-stream=dynamic
./configure --prefix=/usr/local/nginx --add-module=../ngx_devel_kit --add-module=../set-misc-nginx-module --with-stream=dynamic
# make编译 ,切记不要install,执行install 会有覆盖的情况,可能会影响存量的业务或配置,需要注意
make
# 当前目录objs中会存在 编译好的 ngx_stream_module.so
ll objs/ngx_stream_module.so
# 将对于文件cp 到 存量已安装的目录
mkdir /usr/local/nginx/modules
cp objs/ngx_stream_module.so /usr/local/nginx/modules/
# 编辑 nginx.conf ; reload 或 重启服务
# load_module modules/ngx_stream_module.so;
[root@network-test nginx]# head -n 30 conf/nginx.conf | grep -v '^$'
load_module modules/ngx_stream_module.so;
#user nobody;
worker_processes 1;
error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
stream {
upstream tcp_backed {
hash $remote_addr consistent;
server 127.0.0.1:9090 weight=4 max_fails=3 fail_timeout=30s;
}
server {
listen 9999;
proxy_connect_timeout 1s;
proxy_timeout 3s;
proxy_pass tcp_backed;
}
}
TCP代理在stream指令块内进行声明,位于main内,和http指令块同级。
反向代理的upstream支持DNS域名(如ip_hash、socket)配置、权重即故障转移(如max_fails)配置。
当proxy_pass代理TCP时,没有http://前缀,注意配置时不要写错。
支持和HTTP一样的连接超时参数proxy_timeout、proxy_connect_timeout。
在实操这里时,需要提到一点是,一般4层代理是没有转发日志的;比如lvs ;nginx 这里使用tcp/udp 代理时是可以配置转发日志的;
配置方法:
在nginx.conf stream 中配置对应log_farmart;
stream {
log_format tcp_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 logs/tcp-access.log tcp_proxy ;
open_log_file_cache off;
#include /etc/nginx/conf.d/*.stream;
upstream tcp_backed {
hash $remote_addr consistent;
server 127.0.0.1:9090 weight=4 max_fails=3 fail_timeout=30s;
}
# proxy_bind $remote_addr transparent;
server {
listen 9999;
proxy_connect_timeout 1s;
proxy_timeout 3s;
proxy_pass tcp_backed;
}
}
配置经验
常见指令:
TCP代理还包含其他很多指令,下面将介绍一些常用的指令。
指令:proxy_bind
语法:proxy_bind address [transparent] | off;
默认值:无
环境:stream、server
含义:如果此配置为off,则表示请求将会使用系统自动分配的本地IP地址,即后端服务看不到用户的真实IP地址;
如果配置为“proxy_bind $remote_addr transparent;”,则后端服务可以看到用户的真实IP地址。
为了使参数生效,需要以超级用户权限运行Nginx的worker进程,并配置核心路由表以截获反向代理服务器的网络流量。
查看nginx upstream 服务的业务日志,在proxy_bind address off
的配置下,upstream 服务日志显示为 nginx 本地ip:
直接配置该参数后,抓包看的话,是可以看到向RS 转发的ip 从 nginx 本身的ip 变成了 client 真实ip;
不过在开启时,可能出现后端RS 无法正常响应的情况;需要以超级用户权限运行Nginx的worker进程,并配置核心路由表以截获反向代理服务器的网络流量。 代理服务器上需要配置iptables 以及对应路由表信息;上游服务器也要指向对应的网关;
这部分的配置,也找到了一些文档;不过部署的测试环境,一直没调通 o(╥﹏╥)o ;所以这部分暂时不细写;
指令:proxy_download_rate
语法:proxy_download_rate rate;
默认值:proxy_download_rate 0;
环境:stream、server
含义:设置后端服务器读取数据的速度。速度定义为字节每秒。
默认值为0,表示禁用限速。
限速设置的值对每个连接都有效。
指令:proxy_next_upstream
语法:proxy_next_upstream on | off;
默认值:proxy_next_upstream on;
环境:stream、server
含义:当无法与当前的后端服务器建立连接时,该指令用来确定是否将客户端连接传递给下一台后端服务器。这可能会受到尝试次数(proxy_next_upstream_tries)和时间(proxy_next_upstream_timeout)的影响。
指令:proxy_next_upstream_timeout
语法:proxy_next_upstream_timeout time;
默认值:proxy_next_upstream_timeout 0;
环境:stream、server
含义:设置传递连接到下一台后端服务器的时间。默认值为0,表示关闭这个限制。
指令:proxy_next_upstream_tries
语法:proxy_next_upstream_tries number;
默认值:proxy_next_upstream_tries 0;
环境:stream、server
含义:设置传递连接到下一台后端服务器的尝试次数。默认值为0,表示关闭这个限制。
指令:proxy_pass
语法:proxy_pass address;
默认值:无
环境:server
含义:设置被代理的服务器地址。地址可以是一个域名,也可以是IP地址加端口号。从Nginx1.11.3版本开始支持配置变量,如“proxy_pass $upstream;”。
指令:resolver
语法:resolver address ... [valid=time] [ipv6=on|off];
环境:stream、server含义:在进行DNS解析时,该指令用于对upstream中出现的域名进行IP地址解析,然后将请求代理到解析到的IP地址上;
Valid=time表示DNS解析后的缓存时间,使用缓存时间可以减少DNS解析的次数;
关于ipv6=on|off,如果设置为on,则表示在查询IPv4(Internet Protocol version 4,互联网协议版本4)无果后会继续查询IPv6(Internet Protocol Version 6,互联网协议版本6),如果不需要查找IPv6,可以配置为off,以缩短查找时间。
指令:resolver_timeout
语法:resolver_timeout time;
默认值:resolver_timeout 30s;
执行阶段:stream、server
含义:设置解析DNS的超时时间,如果超时,DNS会使用上一次解析到的IP地址。
指令:proxy_protocol_timeout
语法:proxy_protocol_timeout timeout;
默认值:proxy_protocol_timeout 30s;
环境:stream、server
含义:设置读取proxy协议头的时间。如果在所设置的时间内没有发送完整的报头,则关闭连接。
实战经验
1.指令nginx_tcp_proxy_module和ngx_stream_core_module都可以在TCP代理中使用。其中ngx_stream_core_module包含有关日志记录的一些常用变量,通过这些日志信息可以分析每个TCP请求的情况。
2.在做TCP代理时,Nginx代理节点服务器可能不止一台,可以使用DNS轮询或LVS(LinuxVirtualServer,Linux虚拟服务器)等功能对Nginx进行负载均衡。
3.Redis属于单核服务,所以在一台服务器上启动多个Redis实例是很正常的。如果多个Redis从库部署在同一台服务器上,可以通过TCP代理进行转发,否则会因为端口不一致,导致配置非常烦琐。
相关nginx 官网链接和参考资料:
https://docs.nginx.com/nginx/admin-guide/load-balancer/tcp-udp-load-balancer/
http://nginx.org/en/docs/stream/stream_processing.html
http://nginx.org/en/docs/stream/ngx_stream_log_module.html#open_log_file_cache
http://nginx.org/en/docs/stream/ngx_stream_core_module.html
http://nginx.org/en/docs/varindex.html
http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_bind
https://github.com/vislee/leevis.com/issues/142
http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_bind
https://www.nginx.com/blog/ip-transparency-direct-server-return-nginx-plus-transparent-proxy/
https://pengpengxp.github.io/archive/before-2018-11-10/2017-06-27-使用nginx的proxy_bind选项配置透明的反向代理.html#tproxy_sum