如何使用透明套接字设置 Nginx?

如何使用透明套接字设置 Nginx?

类似地Cloudflare 博客文章中,我尝试使用透明套接字设置 Nginx(使用IP_TRANSPARENT套接字选项)。我想通过这种方式来实现一个可以有效绑定到所有端口的反向 TCP 代理。

IP_TRANSPARENT选项是不受原生支持由 Nginx 监听,所以我尝试使用Systemd 套接字单元然后使用NGINX环境变量

套接字单元如下(不重要的行已被删除):

[Socket]
ListenStream=127.0.0.1:1234
Transparent=true

[Install]
WantedBy=sockets.target

我的Nginx服务单元如下(不重要的行已删除):

[Service]
# Configure Nginx to use the socket inherited from Systemd
Environment=NGINX=3;
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf

我的nginx.conf如下(不重要的行已被删除,upstream是我想要代理到的上游主机的主机名):

stream {
    server {
        proxy_pass upstream:443
        listen 127.0.0.1:1234;
    }
}

Nginx 在 GCP 计算实例上运行内部直通负载均衡器IP 地址为 10.11.12.13,因此我添加了以下 iptables 规则将流量重定向到透明套接字:

iptables -t mangle -I PREROUTING -d 10.11.12.13/32 -p tcp -j TPROXY --on-port=1234 --on-ip=127.0.0.1

正如所描述的这里,GCP 为负载均衡器安装了本地路由,因此无需自己执行此操作。换句话说,以下命令返回RTNETLINK answers: File exists

ip route add local 10.11.12.13/32 dev lo src 127.0.0.1

但是,以下 curl 命令挂起:

curl https://10.11.12.13

从 curl 的角度来看,TCP 连接已正确建立,但是在跟踪 Nginx 工作进程时,它似乎挂在系统accept4调用上。

tcpdump从 Nginx 正在运行的实例运行显示以下内容:

15.59.51.564902 IP [REDACTED].50028 > 10.11.12.13.443: Flags [S], seq 3519046460, win 65535, options [mss 1320,nop,wscale 6,nop,nop,TS val 3905128064 ecr 0,sackOK,eol], length 0
15.59.51.564973 IP 10.11.12.13.443 > [REDACTED].50028: Flags [S.], seq 2512605282, ack 3519046461, win 28400, options [mss 1420,nop,nop,sackOK,nop,wscale 7], length 0
15.59.51.601898 IP [REDACTED].50028 > 10.11.12.13.443: Flags [.], ack 1, win 4096, length 0
15.59.51.601898 IP [REDACTED].50028 > 10.11.12.13.443: Flags [P.], seq 1:370, ack 1, win 4096, length 369
15.59.51.601898 IP 10.11.12.13.443 > [REDACTED].50028: Flags [.], ack 370, win 231, length 0

据我了解,这意味着客户端正在发送数据,服务器正在确认数据,但随后客户端不再发送任何数据,大概是因为它期待服务器的响应,但服务器并未响应。因此,我怀疑 Nginx 只是忽略了客户端发送的数据。

我希望我已经提供了足够的背景信息来理解这个问题。我不太确定接下来该怎么做,或者我所尝试做的事情是否存在根本性错误。任何帮助都将不胜感激。

答案1

我找到了解决方案这里这需要在 Nginx 服务单元上设置以下选项:

[Service]
NonBlocking=true

据推测,Nginx 假定在创建监听套接字时设置了此选项,因此如果 Systemd 传递一个没有设置此选项的套接字,则无法读取数据。

相关内容