はじめに (対象読者・この記事でわかること)

この記事は、Ubuntu 20.04/22.04、Debian 11/12 などのDebian系ディストリビューションで「サーバーを運用中に突然デフォルトゲートウェイが書き換わり、通信が不通になる」という症状に見舞われた方、あるいはその予兆を感じている方向けです。

読み進めることで、以下のことがわかります。

  • ルーティングテーブルがなぜ「自動」で変更されるのか
  • netplansystemd-networkdNetworkManagerdhclient のどれが元凶なのかを特定する方法
  • 設定ファイルをどう修正すれば、再起動やDHCPリース更新後もデフォルトルートが固定されるのか

私自身、業務でマルチNIC構成のサーバーを構築した直後に「プライマリゲートウェイが突然消える」「想定外のNICがデフォルトゲートウェイになる」という現象に何度も遭遇し、原因調査に丸一日を費やした経験があります。この記事はその教訓をまとめたものです。

前提知識

  • ip route コマンドでルーティングテーブルを読める
  • /etc/netplan/*.yaml または /etc/network/interfaces で静的IPを設定した経験がある
  • systemctl status でサービスの状態を確認できる

なぜ「勝手にルーティングが変わる」のか

Debian系OSでは、複数のデーモンが同時にネットワーク設定を触るため、「最後に設定を書き込んだものが勝つ」状態になります。代表的な例を挙げると:

  1. netplansystemd-networkd 経由でLAN側NICにDHCPを有効にしている
  2. DHCPオファーにデフォルトゲートウェイ情報(option routers)が含まれている
  3. その情報が既存のデフォルトルートを上書きしてしまう

このとき、netplanのYAMLでdhcp4: trueとしているだけでgateway4を明示していないと、DHCPサーバーから届いたゲートウェイが優先されてしまうのです。

事象を再現・特定するまでの道のり

ステップ1:現在のルーティングと由来を確認する

まず、変更前の状態をメモルーティングテーブルと、どのデーモンがルートを注入したかを確認しましょう。

Bash
# ルーティングテーブル ip route show # 例: # default via 192.0.2.1 dev eno1 proto dhcp metric 100 # default via 198.51.100.1 dev eno2 proto static metric 200 # ルートの出所を確認 ip route get 8.8.8.8

proto dhcpとあるものはDHCPクライアントが付与したルート、proto staticnetplan/etc/network/interfacesで明示した静的ルートです。

ステップ2:ログを追って「誰が書き換えたか」を特定

Debian 11以降では、systemd-networkdまたはNetworkManagerのいずれかが実質的なネットワーク管理を行います。ログを絞り込みます。

Bash
# systemd-networkdのログ journalctl -u systemd-networkd -f # DHCPクライアントのログ(旧システム) journalctl -u dhclient -f # NetworkManagerのログ(DesktopやNM有効時) journalctl -u NetworkManager -f

GATEWAYdefault routeキーワードでgrepしてやると、次のようなメッセージが見つかります。

systemd-networkd[1234]: eno1: DHCP: Received gateway 192.0.2.1
systemd-networkd[1234]: eno1: Configuring default route with gateway 192.0.2.1

これで「DHCP応答がルートを上書きしている」ことが特定できます。

ステップ3:設定ファイルを修正してDHCPの上書きを回避

netplanを使っている場合、dhcp4-overridesuse-routes: falseを指定します。

Yaml
# /etc/netplan/01-netcfg.yaml network: version: 2 renderer: networkd ethernets: eno1: # LAN(DHCPクライアントとして動作) dhcp4: true dhcp4-overrides: use-routes: false # ← これがポイント eno2: # 外向け(静的ルート) addresses: [198.51.100.10/24] gateway4: 198.51.100.1 nameservers: addresses: [8.8.8.8, 1.1.1.1]

use-routes: falseにすると、DHCPサーバーからゲートウェイ情報が降ってきても無視します。これでeno2側の静的なデフォルトゲートウェイが常に優先されます。

ifupdown/etc/network/interfaces)を使っている場合は、dhcp-optionsで拒否できます。

allow-hotplug eno1
iface eno1 inet dhcp
    # DHCPでルートを受け取らない
    supersede routers 0.0.0.0

ステップ4:即時反映と永続化

変更後は以下で即座に反映させます。

Bash
sudo netplan apply # netplan利用時 # または sudo ifdown eno1 && sudo ifup eno1

そして再起動を一度行い、ip routeが変わらないことを確認しましょう。

ハマった点:metric値の競合

私の環境では、eno1側のDHCPルートがmetric 100eno2側の静的ルートがmetric 200だったため、DHCPルートの方が常に優先されていました。netplanで明示的にroutes:を書いてmetricを下げても、DHCP側が100のままでは意味がないので、DHCP側のルート注入を完全に無効化する方が確実です。

解決策まとめ

  • DHCPでルートを受け取りたくないNICではuse-routes: falseまたはsupersede routers 0.0.0.0
  • 複数NICでゲートウェイを使い分ける場合は、受け側と送り側を明確に分離してYAML/インターフェースを記述
  • 設定適用後は必ずrebootip routeで再現試験を行う

まとめ

本記事では、Debian系OSで「DHCP応答によってデフォルトゲートウェイが意図せず上書きされる」現象の調査手順と、それを防ぐためのnetplan/interfaces設定を紹介しました。

  • DHCPが配布するoption routersuse-routes: falseで無効化できる
  • systemd-networkdのログを追うことで、誰がルートを注入したかが一目でわかる
  • マルチNIC環境では、「どのNICで外向けゲートウェイを使うか」を明確に設計してから設定を書き始める

これで、再起動やDHCPリース更新後も「突然通信が途切れる」という恐怖から解放されます。

次回は、同じ問題をAnsibleで大規模サーバー群に一括適用する方法と、障害時に自動でルートを戻す仕組みを紹介する予定です。

参考資料

  • man systemd.network (dhcp选项の overrides セクション)
  • netplan.io Reference - dhcp4-overrides
  • Debian Wiki - NetworkConfiguration