「なぜVPN越しだとAPIがタイムアウトするのか?」――MTU/MSS調整の泥沼を脱出する技術
ネットワークエンジニアとして現場を歩いていると、若手から「VPNを通すと特定のWeb APIだけがレスポンスを返さない」「pingは通るのにcurlだと固まる」という相談を受けることがよくあります。
画面越しにパケットキャプチャを見せてもらうと、そこには決まって「断片化(Fragment)」の山か、あるいはブラックホール化したパケットの成れの果てが転がっています。今回は、VPN構築において避けては通れない「MTU(Maximum Transmission Unit)」と「MSS(Maximum Segment Size)」の深淵について、現場の知見を交えて解説しましょう。
—
1. なぜ「VPN」でパケットは溢れ出すのか
VPN(IPsecやSSL-VPN)の正体は、元のパケットを別のパケットの中に「包み込む(カプセル化)」技術です。
例えば、MTU 1500バイトのイーサネットフレームで運ばれてきたIPパケットが、IPsecトンネルに入るとどうなるか。IPsecのヘッダーやESP(Encapsulating Security Payload)のオーバーヘッドが加わることで、全体のサイズは1500バイトを優に超えてしまいます。
ここでルーターは二択を迫られます。
1. 断片化(Fragmentation): 巨大なパケットを2つに割る。
2. 破棄(Drop): 「DF(Don’t Fragment)」ビットが立っていれば、ルーターは「無理だ」と判断してパケットを捨てる。
最新のWeb APIやHTTPS通信において、TCPパケットにはほぼ間違いなく DF ビットがセットされています。これが、「VPN越しだと通信が止まる」最大の原因です。
—
2. MSS Clamping:現場を救う特効薬
断片化を物理的に防ぐために、我々が現場で採用するのは「MSS Clamping」という手法です。
TCPの3ウェイ・ハンドシェイク(SYNパケット)の時点で、両端のホストに「俺はこれ以上のサイズのデータは一度に受け取れないから、このサイズ以下にしてくれ」と交渉させる仕組みです。
設定例:CiscoルーターでのMSS Clamping
VPNトンネルインターフェース(Tunnel0)にて、以下の設定を投入するのが定石です。
! インターフェース設定モードにて
interface Tunnel0
! IPsecオーバーヘッドを考慮し、通常は1360〜1400バイト程度に設定
! 1500 - 40 (IP/TCP) - 60 (IPsec/ESP) ≒ 1400 と計算する
ip tcp adjust-mss 1360
この一行を入れるだけで、VPNを通過するTCP通信は、ルーターがSYNパケット内のMSS値を強制的に書き換えてくれます。これにより、ホスト側が自発的に小さなパケットを生成するようになり、断片化によるパケットロスが嘘のように消え去ります。
—
3. 実務で遭遇する「見えないパケットサイズ」の壁
APIの開発現場では、クライアント側の curl や Fetch API を使った検証中にこの問題にぶつかることがあります。以下のコマンドで、パケットサイズを意識したテストを行う習慣をつけましょう。
手順:パケットサイズを指定して疎通確認を行う
Linux環境であれば、ping コマンドで DF ビットを立てつつ、サイズを指定して送信できます。
# -M do: DFビットをセットする
# -s 1472: ペイロードサイズを1472にする(IPヘッダー20+ICMP8=1500)
# VPN越しにこれが通らない場合、MTU調整が必須です
ping -M do -s 1472 <ターゲットサーバーのIP>
もし、ping のサイズを少しずつ減らして 1400 くらいで通るようになったら、その差分がVPNのオーバーヘッドの正体です。
PythonによるAPIリクエスト時の注意
アプリケーション層で大きなJSONを投げたり、TLSハンドシェイクで証明書チェーンが大きくなったりすると、APIリクエスト自体が断片化のトリガーになることがあります。
import requests
# タイムアウトが頻発する場合、コネクションプールやヘッダーサイズを疑う
# MTU問題が疑われる環境では、あえて一度に送るデータ量を抑える設計も考慮する
try:
response = requests.post(
"https://api.example.com/data",
json={"big_payload": "..." * 1000},
timeout=5
)
except requests.exceptions.Timeout:
# 現場のTips: ここで「通信エラー」だけでなくMTU問題を疑い、
# tcpdumpでパケットを確認するフローを標準化すること
print("MTU問題の可能性あり:パケットキャプチャを確認せよ")
—
4. 最後に:エンジニアへのアドバイス
ネットワークは「魔術」ではありません。パケットは常に物理法則(MTUサイズ)に従って動いています。
- まずはキャプチャ:
tcpdump -ni any host <IP> -w capture.pcapで、通信がどこで止まっているかを見る。 - DFビットを確認:
WiresharkでIP Flags: 0x02 (Don't fragment)が立っているパケットが、VPNの入り口で再送を繰り返していないかを確認する。 - 設計段階で考慮: Web API設計において、巨大なリクエストボディを扱う場合は、VPN経由のクライアントの存在を考慮し、チャンク分けやページネーションを徹底する。
「VPNで遅い・つながらない」と言われたら、まずはMTUとMSSのバランスシートを頭の中で描いてみてください。これだけで、トラブルシューティングのスピードは劇的に向上します。
技術は現場で磨かれます。明日からの運用で、ぜひこの視点を活かしてみてください。
コメント