1. はじめに
ゲームサーバのホスティング。
個人でもサービスを提供できるこのテーマに興味を抱く方は多いのではないでしょうか。
私もその一人でしたが、私の環境ではその実現に2つの課題が横たわっていました。
-
セキュリティの懸念
メインPCやスマホが接続される生活用のネットワークに、不特定多数がアクセスするサーバを置きたくない -
ISPの仕様
我が家で契約している「楽天ひかり(クロスパス/DS-Lite)」は高速だが、ポート開放ができない
これらの要件を満たすため、OpenWrtのPBRとDockerのmacvlanを駆使し「管理と公開を物理・論理レベルで完全分離」した自宅サーバ環境を構築しました。
本記事ではその、こだわりのネットワークの全貌を共有します。
2. 構成
単にサーバが動けば良いわけではありません。
目指すのは、用途に合わせて回線とネットワークを完全に使い分けるアーキテクチャです。
2-1. 目指す機能
-
生活エリア (LAN)
- 回線: IPoE (DS-Lite)。高速・低遅延
- 役割: メインPCでの作業用。サーバの負荷影響を受けない聖域
-
公開エリア (DMZ)
- 回線: PPPoE。グローバルIP占有
- 役割: サーバー公開用。ここだけを外部に晒す
これらを1台のルータ、1本のファイバ、1台の物理サーバで論理的に制御しきることが今回のゴールとなります。
2-2. ネットワーク構成図
| Zone | VLAN ID | Subnet | Gateway | 所属 |
|---|---|---|---|---|
| LAN | 1 | 192.168.1.0/24 |
IPoE (DS-Lite) | Host OS (管理用), Main PC |
| DMZ | 100 | 192.168.100.0/24 |
PPPoE | Docker Containers (公開用) |
3. OpenWrtの設定: 物理ポートの分離と第2のWAN
まずは物理層・データリンク層の設計です。
OpenWrtルータでVLANを切り、用途の異なる2つのWAN接続を確立します。
3-1. VLANによる物理ポートの分割
サーバーへ繋がるLANケーブルには「LAN用の通信」と「DMZ用の通信」の両方を流す必要があります。そこで、サーバ向けポートを Trunk (Tag VLAN) に設定します。
# 生活用ネットワーク (VLAN 1)
config switch_vlan
option device 'switch0'
option vlan '1'
option ports '6t 0 1t 2 3' # Port 1はTrunk(t)
option description 'lan'
# 公開用ネットワーク (VLAN 100)
config switch_vlan
option device 'switch0'
option ports '6t 1t' # Port 1はTrunk(t)
option vlan '100'
option description 'dmz'
3-2. IPoEとPPPoEのハイブリッド構成
デフォルトのIPoE接続に加え、サーバー用にPPPoE接続 (wanb) を追加します。
Tips:
NTTフレッツ網(NGN)の仕様上、IPoE(ネイティブ接続)はセッション数を消費しないため、PPPoEセッションと共存可能です。
3-3. 技適への配慮
OpenWrt化したルータで無線を吹くと電波法(技適)に抵触するリスクがあります。
config wifi-device 'radio0'
option disabled '1' # 無効化
OpenWrt側の無線機能は無効化し、Wi-Fiは別途ブリッジモードの市販ルータを使用します。
4. PBRによる「非対称ルーティング」の解決
ハイブリッド構成にすると、最大の壁「非対称ルーティング問題」に直面します。
4-1. 何が起きるのか?
- 外部から PPPoE 経由でサーバーにアクセスが来る
- サーバが返信パケットをルータに送る
- ルータは「デフォルトゲートウェイ」である IPoE から返信パケットを出そうとする
- 行きと帰りの経路が異なるため、通信不整合とみなされパケットが破棄される
4-2. 解決策: PBR (Policy Based Routing)
通常の「宛先」ではなく、「送信元」を見てルーティングを変える必要があります。
OpenWrtの pbr パッケージを導入し、以下のポリシーを適用しました。
config policy
option name 'dmz_to_pppoe'
# 送信元がDMZセグメント(192.168.100.x)なら
option src_addr '192.168.100.0/24'
# 強制的にPPPoEインターフェース(wanb)へ流す
option interface 'wanb'
# ただし、宛先がローカルネットワークの場合は除外
option dest_addr '!192.168.0.0/16'
これにより、送信元IPに基づいた専用のルーティングテーブルが参照され、戻りのパケットが正しいインターフェース(PPPoE)から送出されるようになります。
5. ファイアウォール設計とポート開放
セキュリティの要であるファイアウォールの設定です。
ここでは、「DMZを隔離して生活環境を守る」 設定と、「外部からのアクセスを特定の経路のみ許可する」 設定を行います。
5-1. DMZの隔離 (Security)
「公開サーバーが乗っ取られた場合」を想定し、DMZからLANへの通信を遮断します。
config zone
option name 'dmz'
option input 'ACCEPT'
option output 'ACCEPT'
option forward 'ACCEPT' # WANへは出られる
list network 'dmz'
# LAN -> DMZ は許可
config forwarding
option src 'lan'
option dest 'dmz'
# DMZ->LAN は Default Reject
この設定により、仮にゲームサーバに侵入されてもLANには到達できません。
5-2. サーバへの入り口を作る (Port Forwarding / DNAT)
次に、外部からのアクセスを受け入れる設定(ポート開放)を行います。
PPPoEインターフェース (wanb) から来た通信だけを許可します。
config redirect
option dest 'dmz'
option target 'DNAT'
option name 'minecraft'
option family 'ipv4'
list proto 'tcp'
option src 'wanb' # PPPoE側からの通信のみを対象にする
option src_dport '25565'
option dest_ip '192.168.100.101' # コンテナのIP (macvlan)
option dest_port '25565'
IPoE (wan) 側はポート開放できない仕様ですが、設定レベルでも明示的に src 'wanb' を指定することで、意図しない経路からのアクセスを防ぎ、管理を明確にしています。
5-3. 通信フローの完成 (往路と復路)
このポートフォワーディング設定(DNAT)と、第4章で設定したPBRを組み合わせることで、以下のような美しい通信フローが完成します。
-
往路 (Inbound):
外部 -> PPPoE (wanb) -> DNAT (Port Fwd) -> コンテナ (192.168.100.101) -
復路 (Outbound):
コンテナ -> PBR (src: 192.168.100.x) -> PPPoE (wanb) -> 外部
入口(DNAT)と出口(PBR)が噛み合うことで、非対称ルーティング問題を回避しつつ、サーバー公開を実現しています。
6. Ubuntu Serverの設定:管理とサービスの分離
物理サーバ側の設計です。ここでもセキュリティを考えてみます。
「ホストOS自体は安全なLAN側に置き、コンテナだけをDMZに置く」という構成にします。
6-1. NetplanでのVLAN選別
物理NICで受け取ったTrunk信号を、OS内で分解します。
network:
version: 2
renderer: networkd
ethernets:
enp3s0:
dhcp4: no # 物理NICにはIPを持たせない
dhcp6: no
vlans:
# 管理用 (LAN): ここにホストのIPを振る
vlan1:
id: 1
link: enp3s0
addresses:
- 192.168.1.20/24
routes:
- to: default
via: 192.168.1.1
nameservers:
addresses: [1.1.1.1, 1.0.0.1]
# 公開用 (DMZ): IPは振らず、Dockerにパススルーする
vlan100:
id: 100
link: enp3s0
dhcp4: no
dhcp6: no
これにより、SSHなどの管理操作は安全なLAN内からのみ可能となり、WANからはホストOSの姿が見えなくなります。
7. Docker (macvlan) の活用
最後に、アプリケーションをDMZに着地させます。
ここでは一般的な bridge ネットワークではなく、macvlan ドライバを採用しました。
7-1. なぜ macvlan なのか?
OpenWrt側でPBR(ソースIPベースのルーティング制御)を行うため、コンテナにはホストとは別の、独自のIPアドレスを持たせる必要があったからです。
7-2. ネットワーク作成
docker network create -d macvlan \
--subnet=192.168.100.0/24 \
--gateway=192.168.100.1 \
-o parent=vlan100 \
dmz-net
7-3. Docker Composeでデプロイ
コンテナにDMZ内の固定IP (192.168.100.101) を割り当てます。
ここでは、itzg/minecraft-serverを用いてminecraftサーバをデプロイしてみます。
services:
mc:
image: itzg/minecraft-server
container_name: mc
tty: true
stdin_open: true
environment:
EULA: "TRUE"
TYPE: "PAPER"
MEMORY: "4096M"
USE_AIKAR_FLAGS: "true"
TZ: "Asia/Tokyo"
OPS: |-
hogehoge
volumes:
- /home/hoge/mc/data:/data
networks:
dmz-net:
ipv4_address: 192.168.100.101
networks:
dmz-net:
external: true
これで全てのピースが埋まりました。
コンテナからの通信は 192.168.100.101 として発信され、OpenWrtのPBRルールに合致し、PPPoE経由でインターネットへ出ていきます。
8. 本環境の活用について
構築したこの環境は、単なるゲームサーバ置き場にとどまりません。
様々なユースケースがありそうですが、特に開発環境の構築とは相性がよさそうです。
8-1. 使い捨て開発環境
新しい言語やフレームワークを試したい時、メインPCの環境を汚さずに済みます。
-
docker-compose.ymlを書くだけで特定の言語環境がDMZ上に立ち上がり、VS CodeでRemote SSHなどすれば手元は快適なまま、実体は隔離された環境で開発できる - DockerイメージのPullやライブラリの大量ダウンロードなど回線を使う作業が発生しても、出口が物理的に分かれているためメインPCでの調べもの等に影響が出ない
9. まとめ
単純な動機から始まったプロジェクトでしたが、気づけばインフラの沼にどっぷり浸かっていました。今回の構築で得られた最大の価値は、エンタープライズでは高価な機器を用いて実装するような構成を、OSSを駆使して追加コストをかけずに再現した点でしょうか。
9-1. 学んだこと
-
制約は技術で越えろ
ISPの仕様やセキュリティ要件といった「制約」を、PBRやコンテナ技術の組み合わせで論理的に解決するのはパズル的な面白さがあり、困難な課題こそ成長の糧だと実感した -
Infrastructure as Code (IaC)
ルータの設定からコンテナ構成まで、全てをコード(Configファイル)として管理する快適さと、再現性の重要さを実感した -
「機能美」の追求
生活環境と公開環境を分離し、それぞれのパフォーマンスを最大化する構成は、我ながら美しいアーキテクチャを構築できた
9-2. 今後
今、手元には「生活環境と完全に切り離され」、「帯域も気にせず」、「何度壊してもすぐ直せる」自分だけの最強のサンドボックスがあります。正直ゲームサーバだけで終わらせるのはもったいないくらい、様々なユースケースが想像できます。
この環境をフル活用し、インフラからアプリまで、境界線なくテクノロジーで遊び倒そうと思います。
