【解決】 WireGuard + Nginx での通信エラー


結論

現象
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でアクセスを振り分けました

グローバルサーバローカルサーバ
WireGuardServerClient
nginxlisten: 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)

いかにもですのでググると神がいました

https://www.snbforums.com/threads/ax86u-wireguard-blocking-https.82311/post-808902

仰るとおりでWireGuard clientのMTUを1360にするとエラーは解決しました!

が、ネットワーク環境毎に適切なMTUは異なるので、誰かの調べた値を使うのではなく適切な値を調べて設定するべきですね (方法は冒頭に記載しました)

いずれ解消される?

WireGuardのTODOにリストアップされているので、いずれ PMTU で自動で最適なMTUにしたいとは考えているようですが……書き方的には難しそうですね

https://www.wireguard.com/todo/

感想など

さらっと書きましたが、環境構築開始から数えると2日以上潰してしまいました……
雰囲気でネットワークをやってはイカンですね……

ただ、凹んではおらずでかなり前向きです
というのも Sakura VPS + WireGuard + nginx はかなりいい感じで、やりたいことがいい感じで出来てコスパがメチャ良いので元は取れるかなと考えております!!

「コンピューティングリソースどか食い」なウェブサービスが増えて来ているので、DIY ngrok 的な動きは今後さらに洗練されると思いますが、現時点ではこんなところで!


投稿者:

tojikomorin

仕事が固いマジメなシステムのお仕事ばかりなので、趣味でアホなプログラムを書いています。 固いのもアホなのも両方好きです。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です