透過ソケットを使用して Nginx を設定するにはどうすればよいですか?

透過ソケットを使用して Nginx を設定するにはどうすればよいですか?

同様にこれCloudflareのブログ記事によると、私は透過ソケット(IP_TRANSPARENTソケットオプション)。これを実行することで、すべてのポートに効果的にバインドするリバース TCP プロキシを実装します。

ソケットIP_TRANSPARENTオプションはネイティブサポートされていないNginxがリスニングのために使用しているため、ソケットを作成しようとしていますSystemd ソケットユニットそして、それをNginxプロセスに渡します。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システム コールでハングしているように見えます。

tcpdumpNginx が実行されているインスタンスから実行すると、次のように表示されます。

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 がこのオプションを設定せずにソケットを渡した場合、データを読み取ることができません。

関連情報