Ubuntu

Ubuntu20.04 UFWを使ってIPv6でサービス公開してみる

2025/05/31 全面改定

Ubuntu20.04 UFWを使ってルーターを作る」で構築したサーバーに、本記事の2ページ目に残した過去記事の通りの設定を加えていたのだが、もうすぐ4年が経とうとするこのタイミングで、手持ちの携帯端末からのIPv6接続でタイムアウトが発生した。

このサイト自体が更改のタイミングを迎えているので、このタイミングでルーターの設定を少し改善しようとしていて、OSのアップグレードと設定変更を加えたあたりで「設定の誤り」が顕在化したのではないかと思う。

CopilotさんとGeminiさんの力を借りて、きっちり設定し直そうじゃないの。



ここから広告
広告
広告ここまで


環境

環境は以下の通り。ルーターのOSは24.04にしてしまっているけれど、20.04でも問題なく動くと思う。

名称OSNICIPv4※IPv6※備考
CaRouter不明-192.168.0.12001:db8::1キャリアから貸与されたルーター
MyRouterUbuntu 24.04ens160
ens192
ppp0
192.168.0.11
192.168.9.1
203.0.113.88
2001:db8::11
fd01:db8::9:1
<利用不可>
WebSVUbuntu 20.04ens160
ens192
192.168.0.77
192.168.9.77
2001:db8::77
fd01:db8::9:77

※書き分けるためだけの架空アドレス

設計

実際には、全て同じ物理線に乗っているのだけれど、概念的にはこんな感じ。

<internet>      <internet>
IPv4 IPv6
│ │
┌─┴───────┴─┐
│PPPoE MyRouter │
│ Bridge 宛のみ通過│
│ CaRouter │
└─┬───────┬─┘
│ …─┼──────┬─────────┬─…
┌─┴───────┴─┐ ┌─┴─────┐ │
│ ppp0 ens160│ │ens160 │ <各種端末>
│ MyRouter │ │ WebSV │
│ ens192├──┤ens192 │
└───────────┘ └───────┘

  • インターネットからのパケットはMyRouterが受信。
    • IPv4ならppp0で受信。V6プラスのPPPoE接続ではIPv6が使えない。
    • IPv6ならens160で受信。CaRouterはMyRouter宛てパケットのみを通過させ、他は遮断する設定にしている。
  • MyRouterはWebSVに向けてNAT。
    • この時、IPv4・IPv6共にサービス公開専用のセグメントに転送(ens192)。
  • WebSVはコンテンツを生成して送信。
    • インターネットからの要求は、サービス公開専用のセグメントで送信(ens192)。
    • イントラネットからの要求は、ホームラボのセグメントで送信(ens160)。

サービス公開専用のセグメントを作ったことで管理は複雑化したが、代わりにインターネットに向けて安定的にサービスが提供できるようになった。
(セグメントを作る前はタイムアウトしたり、コンテンツの送信開始までに数秒かかったりする、とてもストレスフルな状況だった)

キャリアルーターの設定

キャリアから貸与されているルーターにログインし、公開したいIPv6アドレス宛のパケットを通過させるように設定する。

IPv6の基本的な思想は、デバイス同士が互いに直接通信することのようでだけれど、今回はルーターだけを公開して振り分ける。
IPv4と同じ方式(NAT)を採って、サーバーを直接インターネットに晒さないことで、少しでも安全にしたいという思い。

IPv6セキュリティのレベル

全部遮断する方向で設定。

設定項目設定値備考
IPv6ファイアウォール機能有効有効にすることで外部からのアクセスを遮断。
IPv6セキュリティのレベル高度ファイアウォールを有効にしてもフレッツ網内からのアクセスは可能。
高度に設定することで網内からのアクセスも遮断できる。

セキュリティレベルは一時期話題になっていたなぁ。
開けておいても攻撃のターゲットになる端末が見つかるはずはない、とか、5分ごとにIPアドレスが変わるから大丈夫、とか。確かにIPアドレスの範囲は広大。また、Windowsには「一時 IPv6 アドレス」があって、アクセス先で確かめると、それが記録されている。
だけれども、念のためガチガチの設定にしている。

IPv6パケットフィルタ設定(IPoE)

ここで、MyRouterへのパケットだけ通過させるようにフィルタを設定していく。

設定項目設定値備考
エントリ番号今回は1登録しているルール数、順番で変わる。
フィルタ種別許可
通信方向IPoE->LAN
プロトコル全て指定
TCPフラグプロトコルの指定により操作不可
送信元IPv6プレフィックス/プレフィックス長全て指定
宛先IPv6プレフィックス/プレフィックス長2001:db8::11 / 128今回は[RouterSV]のアドレスのみ開放。
送信元ポートプロトコルの指定により操作不可
宛先ポートプロトコルの指定により操作不可
ICMPv6タイププロトコルの指定により操作不可
ICMPv6コードプロトコルの指定により操作不可

エントリを追加したら、有効にチェックマークを付けて設定ボタンを押す。

ルーターの設定

仮想PCなので、仮想NICがボタン1つで追加できるから、NICを2つにしておく。

ネットワーク設定

IPv4だけを公開していた時とは大きく変わっている。

  • CaRouterからパケットを受け取るため、固定IPアドレスを追加している。
  • このサーバー自体がインターネットに接続する場合は、デフォルトゲートウェイとしてCaRouterを使うようにPBR(Policy Based Routing)を設定。
    ppp0接続が完了すると、優先度が高いデフォルトゲートウェイになるため。
  • ens192を追加し、サービス公開用セグメントのIPアドレスを手動で設定。

/etc/netplan/00-installer-config.yaml

network:
ethernets:
ens160:
addresses:
- 192.168.0.11/24
- 2001:db8::11/64
routes:
- to: default
via: 192.168.0.1
table: 100
- to: default
via: 2001:db8::1
routing-policy:
- from: 192.168.0.11/32
table: 100
nameservers:
addresses:
- 192.168.0.1
- 2001:db8::1
search:
- myhome.local
optional: true
ens192:
dhcp4: false
dhcp6: false
accept-ra: false
addresses:
- 192.168.9.1/24
- fd01:db8::9:1/64
optional: true
version: 2

※先日作ったルーターにIPv6の設定を追加している。

設定変更したら、以下のコマンドで反映させる。

$ sudo netplan apply

続いて、ppp0がオンラインであることのチェックをやめる。

$ sudo systemctl edit systemd-networkd-wait-online.servic
[Service]
ExecStart=
ExecStart=/lib/systemd/systemd-networkd-wait-online --ignore=ppp0

※空行も含めて書く必要があるとのこと。

問題なければ再起動して、設定前に自動構成されていたデフォルトルート等をきれいにしておくと良いように思う。

UFWによる転送設定(outbound)

ローカルからインターネットに出るための設定をしていく。

IP Masquerade

[WebSV]からインターネットにアクセスできるように、IP Masqueradeする。

/etc/ufw/before6.rules


# don't delete the 'COMMIT' line or these rules won't be processed
COMMIT

# NAT rules
*nat
:POSTROUTING ACCEPT [0:0]
-F
-A POSTROUTING -s fd01:db8::/64 -o ens160 -j MASQUERADE
COMMIT

※赤文字部分を追加。

POSTROUTINGの[0:0]指定は省略することができ、その場合は、カウンターが0クリアされない。

設定を反映させて確認する。

$ sudo ufw reload
$ sudo ip6tables -t nat --list-rules
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-A POSTROUTING -s fd01:db8::/64 -o ens160 -j MASQUERADE

転送許可

カーネルパラメーターを転送可能にしても、それだけではパケットは転送されない。
一般にはデフォルトの転送ポリシーをACCEPTにして転送させるようだけれども、以前の設定を踏襲してポリシーはDROPのままとして、転送ルールを追加してみた。

具体的には、[WebSV]から外に出るものを許可する(135,137:139,445を除く)。

$ sudo ufw route deny in on ens192 out on ens160 to ::/0 port 135,137:139,445 proto tcp
$ sudo ufw route deny in on ens192 out on ens160 to ::/0 port 135,137:139,445 proto udp
$ sudo ufw route allow in on ens192 out on ens160 to ::/0

$ sudo ip6tables -t filter --list-rules ufw6-user-forward
-N ufw6-user-forward
-A ufw6-user-forward -i ens192 -o ens160 -p tcp -m multiport --dports 135,137:139,445 -j DROP
-A ufw6-user-forward -i ens192 -o ens160 -p udp -m multiport --dports 135,137:139,445 -j DROP
-A ufw6-user-forward -i ens192 -o ens160 -j ACCEPT

※順序が重要。delete→insertするか、/etc/ufw/user.rulesの中を並べ替えてreloadするか、どうにかしてそろえる。

外部から送られてくるパケットのうち、接続済み、または、接続済みセッションに関連するものについては通過を許可したい。
確認してみたところ、その設定は標準で入っていた。

$ sudo ip6tables --list-rules ufw6-before-forward
-N ufw6-before-forward
-A ufw6-before-forward -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw6-before-forward -p icmp -m icmp --icmp-type 3 -j ACCEPT
-A ufw6-before-forward -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A ufw6-before-forward -p icmp -m icmp --icmp-type 12 -j ACCEPT
-A ufw6-before-forward -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A ufw6-before-forward -j ufw-user-forward

ここまでの設定で、インターネットへのアクセスができるルーターとして動作する。

UFWによる転送設定(inbound)

インターネットにサービス公開するための設定をしていく。

NAT

[RouterSV]のところに到着したパケットの宛先を[WebSV]に書き換える。

/etc/ufw/before6.rules


# don't delete the 'COMMIT' line or these rules won't be processed
COMMIT

# NAT rules
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-F
-A PREROUTING -d 2001:db8::11/128 -p tcp -m tcp --dport 80 -j DNAT --to-destination fd01:db8::9:77
-A PREROUTING -d 2001:db8::11/128 -p tcp -m tcp --dport 443 -j DNAT --to-destination fd01:db8::9:77
-A POSTROUTING -s fd01:db8::/64 -o ens160 -j MASQUERADE
COMMIT

※赤文字部分を追記。

IPv4のルーターを作ったときには、PPP0に届いたパケットをDNATしていた。
IPv6でもens160に届いたパケットを、[WebSV]にDNATする。

設定を反映させる。

$ sudo ufw reload
$ sudo ip6tables -t nat --list-rules
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-A PREROUTING -d 2001:db8::11/128 -p tcp -m tcp --dport 80 -j DNAT --to-destination fd01:db8::9:77
-A PREROUTING -d 2001:db8::11/128 -p tcp -m tcp --dport 443 -j DNAT --to-destination fd01:db8::9:77
-A POSTROUTING -s fd01:db8::/64 -o ens160 -j MASQUERADE

転送許可

宛先を[WebSV]に書き換えても、転送のデフォルトポリシーはDROPのため、ブロックされる。
そこで、ens160に到着したパケットの[WebSV]への転送を許可する。

$ sudo ufw route allow in on ens160 out on ens192 to fd01:db8::9:77 port 80 proto tcp
$ sudo ufw route allow in on ens160 out on ens192 to fd01:db8::9:77 port 443 proto tcp

$ sudo ufw status
Status: active

To Action From
-- ------ ----
22/tcp ALLOW 192.168.0.0/24 # SSH

135,137:139,445/udp on ens160 DENY FWD Anywhere on ppp0
135,137:139,445/tcp on ens160 DENY FWD Anywhere on ppp0
Anywhere on ens160 ALLOW FWD Anywhere on ppp0
192.168.0.77 80/tcp on ens160 ALLOW FWD Anywhere on ppp0
192.168.0.77 443/tcp on ens160 ALLOW FWD Anywhere on ppp0
135,137:139,445/tcp (v6) on ens160 DENY FWD Anywhere (v6) on ens192
135,137:139,445/udp (v6) on ens160 DENY FWD Anywhere (v6) on ens192
Anywhere (v6) on ens160 ALLOW FWD Anywhere (v6) on ens192
fd01:db8::9:77 80/tcp on ens192 ALLOW FWD Anywhere (v6) on ens160
fd01:db8::9:77 443/tcp on ens192 ALLOW FWD Anywhere (v6) on ens160

Webサーバーの設定

こちらもやはり、IPv4だけを公開していた時とは大きく変わっている。

  • イントラネットからパケットを受け取るため、固定IPアドレスを追加している。
  • ens192を追加し、サービス公開用セグメントのIPアドレスを手動で設定。
    加えて、ens192から送信するパケットを確実にMyRouter向けるため、PBRを設定している。

/etc/netplan/00-installer-config.yaml

network:
ethernets:
ens160:
addresses:
- 192.168.0.77/24
- 2001:db8::77/64
routes:
- to: default
via: 192.168.0.1
- to: default
via: 2001:db8::1
nameservers:
addresses:
- 192.168.0.1
- 2001:db8::1
search:
- myhome.local
ens192:
dhcp4: false
dhcp6: false
accept-ra: false
addresses:
- 192.168.9.77/24
- fd01:db8::9:77/64
routes:
- to: default
via: 192.168.9.1
table: 100
- to: default
via: fd01:db8::9:1
table: 100
routing-policy:
- from: 192.168.9.0/24
table: 100
- from: fd01:db8::/64
table: 100
version: 2

設定変更したら、以下のコマンドで反映させる。

$ sudo netplan apply

これで[WebSV]のサービスを[MyRouter]でしっかりと保護しつつ、Webサービスのみをインターネットに公開できるようになった。

さいごに

ルーターのアップグレードをしたのが今月の初め、ルーティングの見直しを思い立ったのが先週。
通勤途中に気になったことがあって当サイトを見に行ったら、タイムアウトした。

調べようと思ったらtcpdumpにWireShark、概略は分かっているような気がするものの、中身を分析するには知識が足らない。

そんなときには生成AI。
コマンドのパラメーターを教えてもらったり、各種出力結果をそのまま貼り付けて解説してもらったりして、何が起きているのかがすぐに分かる。
最終的に設定結果を確かめるタイミングでも、かなり頼りになる。

でも、設定のアドバイスは外れたりもするんだよなー、そこは人間が判断するしかない。
思い込みができてしまうと払拭するのが大変なので、最初からやり直したりも。

とかなんとか紆余曲折しながらゴールにたどり着いた。

さてさて、こうして記事をまとめながら思っていることは、「全然Webを検索しなかった」ってこと。
過去記事、Copilot、ターミナル、テスト端末、過去記事、Gemini、ターミナル、テスト端末…って感じでどうにかなる。
自分に読解力さえあれば、もっと活用が進みそうな気がする。知識は活用を加速する効果がある程度、かな。

いずれにしても、ちょっと不安に思っていた設定がきれいになったのが嬉しい。
誰にも見られないページをメンテナンスするのは少し寂しいような気もするけれど。

ここから広告
広告
広告ここまで

コメントはこちらから お気軽にどうぞ ~ 投稿に関するご意見・感想・他