Port-Share がすべてのサイト訪問者を localhost に見せる理由
バックエンドが見ているのは転送のホップであり、ブラウザーではありません。送信元アドレスがどこで失われるかを確認し、どのコンポーネントがそれを保証できるかを決めてください。
アクセスログのどの行にも同じ loopback アドレスが表示されるのに、ページ自体は読み込まれ、証明書も正しく検証されています。到達不能という意味では何も壊れておらず、だからこそこの状態は何か月も続きます。壊れているのは帰属です。Web バックエンドは接続を転送したホップのアドレスを記録し、そのログを信じた後続の判断はすべて同じ誤った答えを受け継ぎました。
以下の確認はケーブルから内側へ進みます。目にしている値を説明する最初の確認で止めてください。後続の各手順は、それ以前の手順がすでに正しいことを前提にしています。どれもフロントエンドの設定を推測する必要はありません。
ログ行ではなく、二つの接続をたどる
Port-Share は一つの TCP リスナーで二つのプロトコルを多重化します。OpenVPN は受信接続の先頭バイトを調べ、自分のプロトコルに見えればその接続を保持し、それ以外はすべて第二の宛先へ渡します。その宛先は通常、同じホスト上の Web サーバーなので、Web サーバーが受け入れたソケットの相手は OpenVPN プロセスになります。
ss -ltnp 'sport = :443'
ss -tnp 'dport = :8080'
最初のコマンドは公開リスナーを誰が持っているかを示します。二つ目はバックエンドのポートに届く接続を示し、その相手アドレスがアクセスログに印字される値です。その相手が loopback なら、ログは正確であり、情報は一つ前の層で失われています。ログの項目名を変えたりクライアント IP モジュールを有効にしても、接続がそもそも運んでいなかったアドレスは戻りません。
これが他のすべてを決める確認です。バックエンドの相手がブラウザーのアドレスなら、ポート共有は問題ではなく、ログの形式が問題です。
トランスポート転送はヘッダー注入ではない
転送側はバイトを移動させるだけです。HTTP を解析しないため、リクエストとして読まないリクエストにヘッダーを挿入することはできず、手を触れずに通す TLS ストリームに何かを加えることもできません。プロキシヘッダーを期待するモジュールは、どのコンポーネントも生成していないものを待ち続けます。
元のアドレスを運べる仕組みは二つあり、どちらも両端での合意が必要です。PROXY プロトコルは接続の先頭に小さなヘッダーを付け加えるので、バックエンド側がそれを待つよう設定されていなければなりません。待つ設定のないバックエンドはそのバイトをリクエストの開始とみなし、紛らわしい形で失敗します。X-Forwarded-For のような信頼されたプロキシヘッダーは、HTTP を理解するプロキシがそれを設定し、どの相手がそれを主張してよいかをバックエンドに伝えている場合に機能します。
どちらも自動ではなく、どちらも既定で安全ではありません。入ってくる転送ヘッダーを何でも信じるバックエンドは、クライアントが自分のアドレスを選べるようにしてしまい、ログの不正確さをアクセス制御の回避に変えます。本番経路でどのヘッダーも信頼する前に、ステージングホストで一度だけ実演してください。
curl -sS -H 'X-Forwarded-For: 127.0.0.1' https://site.example.com/health
grep -F '127.0.0.1' /var/log/nginx/access.log | tail -n 3
任意の送信元マッピングディレクトリ
ポート共有には、その機能が実装されているプラットフォームで、元の送信元アドレスと転送接続の対応を記録する任意のディレクトリ引数があります。Web 側はそのマッピングを参照することが想定されています。ヘッダーではなく、リクエストに注入されるものでもありません。
この設計を知っておく価値があるのは、見た目には同じフロントエンド設定なのに、実アドレスを報告する配備とそうでない配備がある理由を説明するからです。違いは受け側にあり、通常はパッケージ版の Web サーバーの多くが既定で有効にしないモジュールやパッチの中にあります。お使いの Web サーバーのドキュメントで提供されている正確なフックを読み、モジュールが読み込まれていることを前提にせず確認してください。
この道を選ぶなら、二つの半分からなる統合として扱ってください。転送側が書くマッピングと、バックエンドが行う照会です。両方を検証し、ディレクトリが再起動をまたいで残り、多忙なリスナー上で無制限に増えないことを確認します。
どのコンポーネントがアドレスを保証するかを決める
設定を変える前に、クライアントアドレスを主張してよいコンポーネントと、それを信じてよいコンポーネントを名指ししてください。答えを一つ書き留めておけば、三つの層がそれぞれ別の情報源を信じるというよくあるずれを防げます。
ほとんどの要件は三つの設計で足ります。公開リスナーと Web リスナーを分けておくなら、Web サーバーは実際の相手を見ることになり、帰属の問題は存在しません。HTTP を理解するリバースプロキシを前に置き、そこでリクエストを終端または解析し、そのプロキシだけを信頼するバックエンドのために転送ヘッダーを設定させます。あるいはポート共有を保ち、ログにはホップが表示されると受け入れたうえで、アクセス規則をアドレスではなくアプリケーションの身元に対して書きます。
うまくいかないのは、転送された loopback アドレスを、リクエストがこのマシンで発生した証拠とみなすことです。その推論はまったく逆です。アドレスがあるのは、まさにローカルのコンポーネントが接続を作ったからです。そう書かれた規則は、リスナーに到達できる誰でも受け入れてしまいます。
ページではなく規則を試す
読み込まれるページは転送経路が機能していることを示すだけで、帰属については何も語りません。アドレスの利用者を試してください。アクセス規則、レート制限、監査記録、地理位置検索です。
curl -sS -o /dev/null -w '%{http_code}\n' https://site.example.com/
tail -n 5 /var/log/nginx/access.log
grep -c '' /var/log/nginx/access.log
許可された外部リクエストをフロントエンドとバックエンドの両方の記録と比較し、拒否すべき規則が今も拒否し、許可すべき規則が今も許可することを確認します。ログ行が正しいのに規則が依然として全員をローカル扱いするなら、その規則は修正した項目とは別の項目を読んでいます。
最後に帰属の連鎖を配備ノートに書き留めます。どのリスナー、どの転送、どのヘッダーまたはマッピング、そしてどのバックエンドがそれを信頼するよう設定されているか、です。次にログ行を読む人には四つすべてが必要であり、そのメモがないことが一年後に同じチケットが再び開く理由です。チャットのスレッドではなく、設定の隣に置いてください。