Proxmox VE上でOpenWrtを仮想ルーターとして運用する方法:VLANルーティングとネットワークの堅牢化

HomeLab tutorial - IT technology blog
HomeLab tutorial - IT technology blog

アプローチ比較:仮想ルーターのアーキテクチャ

火曜日の深夜2時15分、自宅のサーバーラック全体が突如沈黙しました。15台のセルフホストノードから監視アラートがスマートフォンへ一斉に届き、DNSクエリはタイムアウトし、Cephストレージのレプリケーションも停止しました。

さらに悪いことに、メインのファイアウォールVMがオフサイトバックアップのバースト処理中に6GBものRAMを消費し尽くし、カーネルパニックを引き起こしていました。暗闇の中で応答しないコンソールを見つめながら、私はルーティングトポロジ全体を根本から見直すことにしました。ホームラボのエッジで肥大化した仮想アプライアンスを動かすことは、障害発生時に初めて露呈する単一障害点(SPOF)を作り出すだけだったのです。

Proxmox VE内でネットワークルーティングを仮想化する場合、一般的に次の3つのアプローチから選択することになります:

  • 重量級FreeBSDファイアウォール(pfSense / OPNsense):ディープパケットインスペクションや大規模なステートテーブルを備えた高機能セキュリティスイートです。しかし、通常は少なくとも2基の専用vCPUと4GBのRAMを必要とします。高速なVLAN間ルーティング、DHCP、NATのみが必要な場合、これは不要なオーバーヘッドとなります。
  • 物理ハードウェアルーター(MikroTik / Ubiquiti EdgeRouter):ハイパーバイザーとエッジゲートウェイを明確に分離できます。サーバーの再起動時にも停止することはありません。その代償として、ポート構成が固定され、低価格モデルではCPUスループットが低く、実験的な設定でネットワークが壊れた際にスナップショットによる即座のロールバックができないという難点があります。
  • 軽量Linux仮想ルーター(KVM上のOpenWrt):不要なものを削ぎ落とし、最新のLinuxカーネル上で動作します。OpenWrtは約3秒で起動し、アイドル時のRAM消費量は70MB未満で、ProxmoxのLinuxブリッジと直接連携します。BSD特有のドライバの癖に悩まされることなく、標準的なLinux 802.1Q VLANフィルタリングを処理できます。

Proxmox上でOpenWrtを仮想化するメリットとデメリット

テストコンテナやストレージプールをホストする同一ハードウェア上にゲートウェイを配置することは、運用上のトレードオフを伴います。

メリット

  • 極めて小さなフットプリント:OpenWrtは1 vCPUと512MBのRAMで軽快に動作します。私のIntel N100ノードでは、ギガビットトラフィックのルーティング中でもアイドル時のCPU使用率はわずか0.3%にとどまります。
  • ネイティブLinuxブリッジVLAN:OpenWrtは標準でdot1qタギングに対応しています。Proxmoxのvlan-awareブリッジと組み合わせることで、上位スイッチのポートプロファイルを変更することなく、設定ファイルに数行記述するだけでIoT、ゲスト、信頼済みサブネットのトランキングが完了します。
  • 高速なスナップショットロールバック:ファイアウォールポリシーの誤設定でSSHアクセスを遮断されてしまった場合でも、ホストのCLIから直接10秒でProxmoxスナップショットを復元できます。
  • ワイヤースピードのVirtIOスループット:準仮想化VirtIOドライバにより、専用のPCIeパススルーを必要とせず、CPUオーバーヘッドを無視できるレベルに抑えながら、標準の1 Gbpsアップリンクで940 Mbps以上、10 Gbps仮想ブリッジで9.2 Gbps以上のスループットを安定して発揮します。

デメリット

  • ホスト再起動時のダウンタイム:Proxmoxホストに新しいPVEカーネルをインストールして再起動する際、マシンがPOSTを実行してVMが起動するまでの45〜90秒間、家庭内のインターネット接続が切断されます。
  • 管理アクセスのロックアウトトラップ:仮想OpenWrtインスタンス経由でのみルーティングされるサブネットにProxmox管理用IPを割り当てている場合、ファイアウォールルールのミスやブリッジの破損によってホスト自体のWeb GUIにアクセスできなくなるリスクがあります。

耐障害性に優れたホームラボ向け推奨構成

Proxmoxの管理IPへのアクセスを仮想ルーターインターフェースに依存させてはなりません。代わりに、基盤となるブリッジ上に独立した管理用アドレスを設定します。

以下は、マルチポートミニPCや1Uサーバーで使用しているアーキテクチャの基準構成です:

  • WANブリッジ(vmbr1):モデムまたはONTに接続された物理WAN NIC(例: enp2s0)に接続します。Proxmox側ではこのブリッジにIPアドレスやゲートウェイを設定せず、完全にアンナンバード(unnumbered)の状態にしておきます。
  • LAN・トランクブリッジ(vmbr0):物理LAN NIC(例: enp1s0)にbridge-vlan-aware yesを指定して接続します。このブリッジ上にProxmoxの静的ホストIP(192.168.1.2/24など)を直接割り当てることで、OpenWrtがシャットダウンしていてもホストへのアクセスを維持できます。
  • OpenWrt VMスペック:1 vCPU(AES-NI暗号化アクセラレーションのためタイプはhost)、512MB RAM、シリアルコンソール、VirtIO NIC、1GB仮想ディスク。

実装ガイド

ステップ1:Proxmox上でVLAN対応ブリッジを設定する

ProxmoxホストにSSH接続し、ネットワークインターフェース設定ファイルを編集します:

nano /etc/network/interfaces

WANインターフェース用と内部トランク用にそれぞれ専用ブリッジを設定します:

# 物理WANインターフェース(ホストIPなし)
auto enp2s0
iface enp2s0 inet manual

# OpenWrtにパススルーするWANブリッジ
auto vmbr1
iface vmbr1 inet manual
    bridge-ports enp2s0
    bridge-stp off
    bridge-fd 0

# 物理LANインターフェース
auto enp1s0
iface enp1s0 inet manual

# VLAN対応LANブリッジ(Proxmox管理用IPをここに配置)
auto vmbr0
iface vmbr0 inet static
    address 192.168.1.2/24
    gateway 192.168.1.1
    bridge-ports enp1s0
    bridge-stp off
    bridge-fd 0
    bridge-vlan-aware yes
    bridge-vids 2-4094

サーバーを再起動することなく設定を安全に反映します:

ifreload -a

ステップ2:OpenWrtイメージのダウンロードと展開

OpenWrtには標準的なISOインストーラーウィザードがありません。代わりに、公式のx86/64 ext4 UEFIイメージをProxmoxホスト上に直接取得します:

mkdir -p /root/openwrt-install && cd /root/openwrt-install

# 23.05.4 汎用x86/64 combined EFIイメージのダウンロード
wget https://downloads.openwrt.org/releases/23.05.4/targets/x86/64/openwrt-23.05.4-x86-64-generic-ext4-combined-efi.img.gz

# 生ディスクイメージの展開
gunzip openwrt-23.05.4-x86-64-generic-ext4-combined-efi.img.gz

ステップ3:仮想マシンの作成とディスク設定

Proxmoxのqm CLIツールを使用してVMを作成します。ここではVMID 100を割り当て、軽量なコンソールアクセスのために仮想シリアルポートを設定します:

qm create 100 --name OpenWrt-Router \
  --bios ovmf \
  --machine q35 \
  --cpu host \
  --cores 1 \
  --memory 512 \
  --serial0 socket \
  --net0 virtio,bridge=vmbr0,firewall=0 \
  --net1 virtio,bridge=vmbr1,firewall=0 \
  --ostype l26

ダウンロードしたイメージをストレージプール(例: local-lvm)にインポートし、デフォルトの120MBからディスクサイズを拡張します:

# ストレージプールにイメージをインポート
qm importdisk 100 openwrt-23.05.4-x86-64-generic-ext4-combined-efi.img local-lvm

# VirtIO SCSIコントローラーにディスクを接続
qm set 100 --scsihw virtio-scsi-single --scsi0 local-lvm:vm-100-disk-0

# UEFIブート変数用のEFIディスクを追加
qm set 100 --efidisk0 local-lvm:0,format=raw,efitype=4m,pre-enrolled-keys=0

# ブート順序を設定し、仮想ディスクを1GBに拡張
qm set 100 --boot order=scsi0
qm resize 100 scsi0 +880M

ステップ4:初期ネットワーク設定とLuCI Web管理画面の導入

VMを起動し、シリアルコンソールに直接接続します:

qm start 100
qm terminal 100

Enterキーを押してOpenWrtのrootプロンプトを開きます。この構成では、eth0がvmbr0(LAN)に、eth1がvmbr1(WAN)に接続されています。静的LANゲートウェイアドレスを設定します:

uci set network.lan.ipaddr='192.168.1.1'
uci set network.lan.netmask='255.255.255.0'
uci commit network
/etc/init.d/network restart

WANインターフェースがDHCP経由でIPアドレスを取得したら、SQMパッケージとCAKEキュースケジューラモジュールをインストールします:

opkg update
opkg install luci-app-sqm kmod-sched-cake

ステップ5:VLANセグメントとファイアウォールゾーンの設定

次に、信頼できないスマートデバイスをVLAN ID 20に分離します。Proxmoxで仮想ネットワークカードを追加するのではなく、OpenWrt内にタグ付きサブインターフェース(eth0.20)を直接アタッチします。

/etc/config/networkおよび/etc/config/dhcpで新しいインターフェースとDHCPスコープを定義します:

# VLAN 20上にIoTネットワークを設定
uci set network.iot=interface
uci set network.iot.proto='static'
uci set network.iot.device='eth0.20'
uci set network.iot.ipaddr='192.168.20.1'
uci set network.iot.netmask='255.255.255.0'

# DHCPプールを設定 (192.168.20.100 - 192.168.20.250)
uci set dhcp.iot=dhcp
uci set dhcp.iot.interface='iot'
uci set dhcp.iot.start='100'
uci set dhcp.iot.limit='150'
uci set dhcp.iot.leasetime='12h'

uci commit network
uci commit dhcp

/etc/config/firewallでIoTゾーンを厳格に制限します。以下のポリシーは、プライベートLANやハイパーバイザーサブネットへの接続を遮断しつつ、インターネットへのアウトバウンドアクセスのみを許可します:

# 制限付きIoTファイアウォールゾーンを作成
uci add firewall zone
uci set firewall.@zone[-1].name='iot'
uci set firewall.@zone[-1].network='iot'
uci set firewall.@zone[-1].input='REJECT'
uci set firewall.@zone[-1].output='ACCEPT'
uci set firewall.@zone[-1].forward='REJECT'

# IoTデバイスからWANへのアウトバウンドルーティングを許可
uci add firewall forwarding
uci set firewall.@forwarding[-1].src='iot'
uci set firewall.@forwarding[-1].dest='wan'

# ローカルDNSクエリを許可(ポート53)
uci add firewall rule
uci set firewall.@rule[-1].name='Allow-IoT-DNS'
uci set firewall.@rule[-1].src='iot'
uci set firewall.@rule[-1].proto='tcpudp'
uci set firewall.@rule[-1].dest_port='53'
uci set firewall.@rule[-1].target='ACCEPT'

# ローカルDHCPリクエストを許可(ポート67-68)
uci add firewall rule
uci set firewall.@rule[-1].name='Allow-IoT-DHCP'
uci set firewall.@rule[-1].src='iot'
uci set firewall.@rule[-1].proto='udp'
uci set firewall.@rule[-1].dest_port='67-68'
uci set firewall.@rule[-1].target='ACCEPT'

uci commit firewall
/etc/init.d/firewall restart

ステップ6:CAKE SQMによるバッファブロートの解消

アップリンク帯域を使い果たすと、大容量転送時に深刻なレイテンシのスパイクが発生します。典型的な1 Gbps / 50 Mbpsの回線環境では、キュー管理を行わない場合、高負荷時のping応答が15msから350ms以上にまで跳ね上がることがあります。

このバッファブロート(Bufferbloat)を解消するため、WANインターフェース(eth1)にCAKEシェーピングを適用します。帯域制限には、測定した実効速度の約90〜95%の値を指定します:

uci set sqm.eth1=queue
uci set sqm.eth1.interface='eth1'
uci set sqm.eth1.qdisc='cake'
uci set sqm.eth1.script='layer_cake.qos'
uci set sqm.eth1.enabled='1'
# 帯域幅をkbit/s単位で設定(例: 下り940 Mbps、上り48 Mbps)
uci set sqm.eth1.download='940000'
uci set sqm.eth1.upload='48000'
uci commit sqm
/etc/init.d/sqm restart

設定を適用したら、Waveform Bufferbloat Testなどのツールでテストを実施してください。アップロードが100%飽和している状態でも、pingジッターは通常200ms以上から3ms未満にまで激減します。これで、ホスト側のCPU消費電力換算で2W未満という極めて省リソースでありながら、スナップショット対応で強固に分離されたルーター環境が完成しました。

Share: