デフォルトゲートウェイの枠を超えて
ほとんどの Linux サーバーは「出口は 1 つ」というポリシーで動作しています。パケットのルーティングテーブルに特定の宛先がない場合、カーネルはそれをデフォルトゲートウェイに送ります。これは基本的な構成ではうまく機能します。しかし、10Gbps の光回線とバックアップの LTE 回線を併用したり、特定の Docker コンテナを WireGuard トンネル経由で強制的に通信させようとしたりする場合、単一のゲートウェイは足かせとなります。「データベースのバックアップは低速な回線を使い、Web トラフィックは光回線を使用する」といったロジックが必要になります。
ポリシーベースルーティング (PBR) はこれを解決します。パケットの宛先のみに基づいてルーティングするのではなく、PBR では誰が送信しているか、あるいはどのプロトコルを使用しているかに基づいて決定を下せます。プロダクションのエッジ環境において、これは効率的なハイブリッドクラウドになるか、ネットワークの悪夢になるかの分かれ目となります。
PBR と標準ルーティングの違い
PBR を効果的に活用するには、宛先のみのロジックからルールベースの選択への転換を理解する必要があります。
標準の宛先ベースルーティング
これがデフォルトです。カーネルは宛先 IP を検査し、メインテーブル内で最も一致するプレフィックスを探してパケットを送り出します。送信元のアプリケーションは考慮されません. システムアップデートであれ、重要な API コールであれ、すべて同じ出口に並びます。シンプルですが柔軟性に欠けます。
ポリシーベースルーティング (PBR)
PBR は、テーブルの上に「ルール」レイヤー (ip rule) を追加します。カーネルはメインのルーティングテーブルを参照する前に、まずこれらのルールをチェックします。ルールはフィルターとして機能します。「このパケットの送信元が 192.168.1.50 の場合、メインテーブルを無視してテーブル 100 を使用する」といった具合です。テーブル 100 は独自のデフォルトゲートウェイを持つことができるため、1 台のマシン上に独立したルーティングレーンを事実上作成できます。
トレードオフ
制御には複雑さが伴います。導入前に以下の要素を考慮してください。
- 利点:
- コストの最適化: 1Gbps の低遅延回線をユーザー用に確保しつつ、500GB の夜間バックアップを安価で高遅延な 100Mbps 回線に移動できます。
- VPN の分離: システム全体のトラフィックをトンネルに漏らすことなく、特定のユーザーや名前空間のみを VPN (OpenVPN や Tailscale など) 経由でルーティングできます。
- 非対称ルーティングの解消: ISP B から入ってきたトラフィックが必ず ISP B から出ていくようにし、ファイアウォールが「ステート外」パケットをドロップするのを防ぎます。
- 欠点:
- 隠れたロジック: トラブルシューティングが難しくなります。ルールが優先されている場合、単純な
ip route showだけではパケットが失敗している理由を説明できません。 - メンテナンス: ローカルネットワークの変更に合わせて、カスタムテーブルを手動で同期させる必要があります。
- 隠れたロジック: トラブルシューティングが難しくなります。ルールが優先されている場合、単純な
シナリオ
このガイドでは、一般的なデュアルホーム構成を使用します。Ubuntu 22.04 または 24.04 で iproute2 を使用していることを想定しています。
構成:
- eth0 (メイン): 192.168.1.10 (ゲートウェイ: 192.168.1.1)
- eth1 (サブ/VPN): 10.0.0.5 (ゲートウェイ: 10.0.0.1)
目標:ローカル IP 192.168.1.100 からからのトラフィックを強制的に eth1 (10.0.0.1) 経由で送信し、システムの残りの部分は eth0 を使い続けるようにします。
実装手順
1. カスタムルーティングテーブルの定義
Linux では最大 252 個のカスタムテーブルを使用できます。ID 253 以上はシステム予約済みのため、使用しないでください。コマンドを読みやすくするために、/etc/iproute2/rt_tables に名前を登録します。
# テーブル定義を開く
sudo nano /etc/iproute2/rt_tables
# 新しいテーブルを追加
200 secondary_link
2. カスタムテーブルへのルート追加
secondary_link テーブルは現在空です。デフォルトルートとローカルネットワークへのルートを設定し、ローカル通信が ISP に送られないようにする必要があります。
# 新しいテーブルのゲートウェイを設定
sudo ip route add default via 10.0.0.1 dev eth1 table secondary_link
# 内部トラフィックが引き続き機能することを確認
sudo ip route add 192.168.1.0/24 dev eth0 table secondary_link
3. ルーティングルールの適用
ここで魔法が起こります。特定の IP からのトラフィックに対して secondary_link テーブルを適用するようカーネルに指示します。
# ルールを作成
sudo ip rule add from 192.168.1.100 table secondary_link
# ルールの優先順位を確認
ip rule show
出力には優先順位が表示されます。数字が小さいほど優先されます:
0: from all lookup local
32765: from 192.168.1.100 lookup secondary_link
32766: from all lookup main
32767: from all lookup default
4. 送信元 NAT (SNAT) の設定
eth1 が ISP または VPN の場合、そのゲートウェイはパケットが自身のサブネットに一致することを期待します。iptables を使用してトラフィックをマスカレードし、10.0.0.5 から送信されているように見せます。
# eth1 から送信されるトラフィックをマスカレード
sudo iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
5. 経路の検証
curl を特定のソース IP にバインドしてルーティングをテストします。結果を比較して、トラフィックが実際に代替経路を通っているか確認します。
# デフォルトルートの確認 (ISP A になるはず)
curl -s icanhazip.com
# PBR ルートの確認 (ISP B/VPN になるはず)
curl -s --interface 192.168.1.100 icanhazip.com
応用:サービスによるルーティング (FWMARK)
HTTPS トラフィック (ポート 443) をすべて高速な回線経由で送るなど、プロトコルに基づいてルーティングが必要な場合があります。これは ip rule だけでは不可能です。まず iptables を使ってパケットに「マーク」を付ける必要があります。
# 1. TCP 443 パケットに ID 「1」 のマークを付ける
sudo iptables -t mangle -A PREROUTING -p tcp --dport 443 -j MARK --set-mark 1
# 2. マーク 「1」 が付いたパケットをカスタムテーブルでルーティング
sudo ip rule add fwmark 1 table secondary_link
Netplan による設定の永続化
ip コマンドは揮発性であり、再起動すると消えてしまいます。Ubuntu では Netplan を使用して、これらのルールを永続化します。/etc/netplan/ 内の YAML 設定を更新してください:
network:
version: 2
ethernets:
eth1:
addresses: [10.0.0.5/24]
routes:
- to: default
via: 10.0.0.1
table: 200
routing-policy:
- from: 192.168.1.100
table: 200
sudo netplan apply を実行して設定を確定させます。
まとめ
ポリシーベースルーティングは、ネットワークにおける「出口は 1 つ」という硬直したモデルを打ち破ります。デバッグ作業に複雑さのレイヤーが加わりますが、マルチホームサーバーや VPN ゲートウェイ に提供される柔軟性は他に類を見ません。「ルールが先、テーブルが後」というフローさえ掴めば、任意の数のインターフェース間でトラフィックを精密に操ることができます。

