結論
現象
WireGuard server で インターネットアクセスを受け、WireGuard clientに nginxリバースプロキシする構成で、POST通信だけが失敗しました
解決策
WireGuard のMTUを下げることで解決しました
適切なMTUはネットワーク環境毎に異なります。タイミングによって経路が変わりMTUも変わりうるというのが個人的なドハマりポイントでした
送信するネットワーク環境毎の適切なMTUを調べるには以下コマンドが有用です
ping -M do -s "MTUとして試したい数値" -c 3 "送信先サーバ"
イーサネットのMTUサイズを超えていたら “Message too long” が出ます
環境によっては serverのMTUを下げた方が良いケースもあるはずです
ただ、経路によってMTUは変わるため、何度か時間を変えて試す必要がありました
良い方法ある方教えて下さいませ
(原因は WireGuardのMTUであり、nginx, POST などは直接関係なかったのですが、ngrok的なことやりたい人は同じ現象でハマるケースあると思うので、googlability を考えて記載しています)
詳細
以下は備忘メモ
困ってググった人を拾うキーワードとなることを期待してるので、結論で満足した人は読まなくて良いです
やりたかったこと
ローカルサーバで動かしてるウェブアプリをVPN経由で公開したかったのです
そのために Wireguard でグローバルIPを持ったサーバとローカルサーバをトンネリングして、nginxでアクセスを振り分けました
グローバルサーバ | ローカルサーバ | |
WireGuard | Server | Client |
nginx | listen: Global IP:443 proxy: ローカルサーバ:8080 | listen: Local IP:8080 proxy: Rails Unicorn |
マシンなど | Sakura VPS ubuntu 22 | じゃんぱらで拾ったマシンに 良いGPUを足したヤツ ubuntu 22 |
ngrokで良さそうな内容だけど、ワイルドカードサブドメインを使いたかったのと、色んなローカルサーバを1台のnginxで一括管理したかったので、WireGuard + nginx かなという結論になりました
(とはいえ、ngrokは実際運用したこと無いので、ngrokで良いよ!とかあれば教えてください。&他に良い解決策ご存じの方はコメントくださいませ)
経緯
構成を組んでブラウザからアクセス。成功。「やったー!」と喜ぶのも束の間、フォームをPOSTしたらレスポンスが無く、暫くして504 Gateway Time-out
切り分け
ローカルサーバの nginx のログを見ても、1行もログがない
グローバルサーバの nginx のログを見るとタイムアウトが確認できた
2023/06/14 03:11:39 [error] 28001#28001: *623 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 10.200.200.1, server: *.example.com, request: "POST /path HTTP/1.1", upstream: "http://local-server:8080/path", host: "global-server", referrer: "https://global-server/path"
エラーの起こったPOSTリクエストをcURL化 (developer tool 便利です!)
cURLをコマンドラインから流して再現を確認
ヘッダーを色々いじって色々なパターンを試していると、リクエストヘッダー長が問題と分かりました
デバッグ
これは nginx 設定の問題に違いない!と考えて、nginx設定を色々いじる
ココらへんが怪しいかな……と思った所のサイズを安易に上げて設定しました
ココらへんを疑った
client_max_body_size
proxy_buffering
proxy_buffer_size
proxy_buffers, proxy_busy_buffers_size
large_client_header_buffers
proxy_redirect
proxy_max_temp_file_size ...
無意味でした
「仕方ない。ちゃんとやるか」と、 nginx のドキュメントをしっかり読み込みました。怪しいと思ってた部分は「そこが原因なら502じゃないよね」ということだけが分かりました
nginx エラーログに debug も出力して再度検証します。
すると、ローカルサーバの nginx に 気になる出力がありました
accept() not ready (11: Resource temporarily unavailable)
いかにもですのでググると神がいました
仰るとおりでWireGuard clientのMTUを1360にするとエラーは解決しました!
が、ネットワーク環境毎に適切なMTUは異なるので、誰かの調べた値を使うのではなく適切な値を調べて設定するべきですね (方法は冒頭に記載しました)
いずれ解消される?
WireGuardのTODOにリストアップされているので、いずれ PMTU で自動で最適なMTUにしたいとは考えているようですが……書き方的には難しそうですね
感想など
さらっと書きましたが、環境構築開始から数えると2日以上潰してしまいました……
雰囲気でネットワークをやってはイカンですね……
ただ、凹んではおらずでかなり前向きです
というのも Sakura VPS + WireGuard + nginx はかなりいい感じで、やりたいことがいい感じで出来てコスパがメチャ良いので元は取れるかなと考えております!!
「コンピューティングリソースどか食い」なウェブサービスが増えて来ているので、DIY ngrok 的な動きは今後さらに洗練されると思いますが、現時点ではこんなところで!