某个 TCP 服务对外有多个域名提供相同的服务,且每个域名都是基于 TLS 的,需要通过 Nginx 对 TLS 进行卸载后转发到实际的上游服务,且上游服务必须使用客户端的源 IP,所以 Nginx 需要使用透明代理。分别需要对Nginx 和系统路由进行配置。
Nginx 配置
需要 Nginx 1.15.9 以上版本,简化配置如下所示,
stream {
upstream up_server {
server 192.168.1.3:8081;
}
# 通过 map 配置不同域名(SNI)使用不同的证书文件
# 证书为泛解析证书, 匹配泛解析域名
# 会降低性能
map $ssl_server_name $targetCert {
~*domain1.com$ /usr/local/cert/domain1.crt;
~*domain2.com$ /usr/local/cert/domain2.crt;
~*domain2.com$ /usr/local/cert/domain3.crt;
default /usr/local/cert/domain1.crt;
}
map $ssl_server_name $targetCertKey {
~*domain1.com$ /usr/local/cert/domain1.key;
~*domain2.com$ /usr/local/cert/domain2.key;
~*domain2.com$ /usr/local/cert/domain3.key;
default /usr/local/cert/domain1.key;
}
server {
listen 8080 ssl reuseport;
ssl_certificate $targetCert;
ssl_certificate_key $targetCertKey;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_tickets off;
proxy_pass up_server;
proxy_bind $remote_addr transparent; # 透明代理
}
}
Linux 系统路由配置
因为透明代理的源 IP 是实际客户的 IP,在实际服务接受处理完响应包返回时会返回给实际的客户 IP,所以需要配置将回包发到 Nginx 进行处理,这里的上游服务为本机服务,需进行如下配置。如上游在其他服务器上,可以查看参考资料中文章并进行对应配置。
# 新建一个 DIVERT 给包打标签
iptables -t mangle -N DIVERT;
iptables -t mangle -A DIVERT -j MARK --set-mark 1;
iptables -t mangle -A DIVERT -j ACCEPT;
# 把本机 TCP 服务的回包给 DIVERT 处理
iptables -t mangle -A OUTPUT -p tcp -m tcp --sport 8081 -j DIVERT
# 有标签的包去查名为 100 的路由表
ip rule add fwmark 1 lookup 100
# 100的路由表里就一条默认路由,把所有包都扔到lo网卡上去
ip route add local 0.0.0.0/0 dev lo table 100
F-Stack(FreeBSD) 路由配置
F-Stack(FreeBSD) 上游回包路由配置,
# upstream 为本机时
# 假设 f-stack-0 的 IP 为 192.168.1.3,将 upstream 往外发的所有出包都转发到 F-Stack Nginx 监听的 IP 和端口即可
# 因为转发到本机地址时目的端口会被忽略,可不设置端口
ff_ipfw add 100 fwd 192.168.1.3,8080 tcp from 192.168.1.2 8081 to any out
# upstream 为其他机器时
# 将 upstream 通过设置网关或者 IP 隧道(需额外进行隧道配置)等方式发过来的所有入包都转发到 F-Stack Nginx 监听的 IP 和端口即可
# 因为转发到本机地址时目的端口会被忽略,可不设置端口
ff_ipfw add 100 fwd 192.168.1.3 tcp from 192.168.1.2 8081 to any in via f-stack-0