v6プラス(DS-Lite)環境下でIPv4/IPv6両対応の自宅サーバーを公開する【しきぶろぐ開設の道筋(1)】

投稿者: | 2022年5月1日

連載 しきぶろぐ開設の道筋

  1. v6プラス(DS-Lite)環境下でIPv4/IPv6両対応の自宅サーバーを公開する
  2. ラズパイにWordPressを導入する
  3. AWS Route53 でドメインを取得し、DDNS っぽく運用する
  4. ブログをcertbotでHTTPS対応する

しばらく何にも使われず眠っていた Raspberry Pi 4B (2GB) でブログを公開しようと思い立った式部。「一年無料」の広告に踊らされて楽天ひかりを契約し、高速インターネットに歓喜していた数か月前には思いも至らなかった、IPv6環境におけるサーバー公開の困難が次々と式部を襲う!

きっかけ

かねてからブログを公開してみたいと思っていたので、せっかくならばとクラウド全盛期のご時世にあえて自宅サーバーを使ったブログ公開に挑戦しました。

なんとなく、ポート開放で80番を開ければいいものとタカをくくっていましたが、世はIPv4からIPv6への移行期。自宅のインターネットがIPv6環境であったことから、不勉強なりに聞きかじった知識が全く通用せず想像以上の泥沼に嵌りましたが、なんとか公開にこぎつけたので、ここに一部始終をまとめておきます。参考までに、我が家のインターネット環境は以下の通り。

  • 楽天ひかり
  • ひかり電話等の契約はナシ
  • 無線LANルーターは、楽天推奨の「クロスパス対応」ルーター

実現したいこと

  • ラズパイ4Bを自宅サーバーとする
  • サーバーに対してIPv4環境・IPv6環境の両方からアクセスできる
  • PCやスマホなどサーバー以外の機器は、混雑しにくいIPv6経由でインターネットにつながる

ネットワーク構成

無線LANルーターの上流にスイッチングハブ(L2スイッチ)を挟んで、WAN側をルーターとラズパイの2方向に繋ぎこむことが特徴です。IPv6パケットは無線LAN経由でラズパイのWi-Fiインターフェース(wlan0)に出入りする一方、IPv4パケットはラズパイが eth1 上に構築したPPPoEセッション(ppp0)に出入りする構成になっています。これにより、IPv4/v6両方の環境からラズパイにアクセスできます。

なお、ラズパイのオンボードLAN端子である eth0 はパケットキャプチャの用途で今後使おうと思っていたので、USB-Ethernetアダプタで増設した有線LANインターフェイス eth1 をスイッチングハブに接続しました。

ネットワーク構成図

ラズパイの準備

すでにラズパイの初期設定が終わっており、SSHやVNCで操作できるものとします。この章はラズパイを持っていれば済んでいる場合も多いと思うので手短に。

IPアドレス固定

今回は図のとおり、ラズパイのIPアドレスを 192.168.0.64 としました。こちらのページにそって、IPv4アドレス、デフォルトゲートウェイ、DNSサーバを固定しました。

SSHの公開鍵認証化とポート番号変更

これもラズパイの初期設定の一環で済んでいることが多いです。ラズパイのコマンドラインを外部から操作するツールであるSSHについて、セキュリティの観点からパスワード認証を無効化し公開鍵認証に切り替えます。また、ポート番号をデフォルトの22番から変更することで安全性を高めます。こちらのページにそって実行しました。

ファイアウォールの設定

次章の「ルーターの設定」を終えるとラズパイを含む自宅内のネットワークが外部に公開されるので、不正なアクセスを防ぐためにファイアウォールを導入します。

ファイアウォールアプリ ufw の導入

sudo apt install ufw

最初は無効であることを確認

ファイアウォールの設定手順として、「まず全てのアクセスを遮断」→「必要な物のみ許可」を辿ります。最初にファイアウォールが無効であることを確認して設定を始めないと、ラズパイへのSSH接続もろとも遮断されるので気を付けます。

sudo ufw status

Status: inactive と出ればOKです。

公開したいポートからのアクセスを許可

まずは全てのポートの接続を拒否します。

sudo ufw default deny

必要なポートだけを開放していきます。今回開放したのは、

  • SSH:自分で変更したポート番号
  • VNC:5900番(ローカル環境からのみ許可)
  • HTTP:80番
  • HTTPS:443番

の4つです。使うコマンドは以下の2つです。後者はポート番号への接続をローカルからのみ許可します。

sudo ufw allow [ポート番号]
sudo ufw allow from 192.168.0.0/24 to any port [ポート番号]

ファイアウォールを有効化します。

sudo ufw enable

ラズパイを再起動すると、ファイアウォールが有効になります。sudo ufw status で確認しました。

$ sudo ufw status
To                         Action      From
--                         ------      ----
xxxxx                      ALLOW       Anywhere
5900                       ALLOW       192.168.0.0/24
80                         ALLOW       Anywhere
443                        ALLOW       Anywhere
xxxxx (v6)                 ALLOW       Anywhere (v6)
80 (v6)                    ALLOW       Anywhere (v6)
443 (v6)                   ALLOW       Anywhere (v6)

なおラズパイ以外のPCについても、OSが提供するファイアウォールがデフォルトで有効になっていると思いますが、念のため確認しましょう。

IPv6環境からのアクセス

まず、ラズパイに対してIPv6環境からアクセスできるようにします。目標は、図のような経路でIPv6パケットを通すことです。

実現したい IPv6 インバウンド通信の経路

ルーターの設定でIPv6パケットフィルタを無効化する

一般的なルーターでは、セキュリティ確保のためインターネット側からのアクセスを遮断する機能(IPv6パケットフィルタ)が有効になっています。外部にホームページを公開するためには、この機能を無効化します。我が家のIODATA製品の場合、設定画面の「セキュリティ」>「IPv6 SPI」を「無効」にします。以上により、ルーター配下の機器がIPv6インターネットに対して野ざらしとなり、IPv6アドレスが分かればアクセスできる状態になります。

ルーターの設定画面で、IPv6 SPI を「無効」にする

疎通確認

ラズパイのIPv6アドレスを確認します。

$ ifconfig wlan0
wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.0.64  netmask 255.255.255.0  broadcast 192.168.0.255
        inet6 fe80::23c5:73d3:c1ba:53e0  prefixlen 64  scopeid 0x20<link>
        inet6 2001:f70:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx  prefixlen 64  scopeid 0x0<global>

inet6 と書かれたもののうち、fe80 から始まるものではないほうがグローバルIPv6アドレスです。このアドレスを使えば世界中どこからでもラズパイに繋がるはずなので、試します。

PCをテザリングで4G回線に繋ぎ、PCとラズパイが別ネットワークにある状況で、先ほど調べたラズパイのグローバルIPアドレスにpingします(スマホの回線がIPv6に対応している必要があります。4Gで ipv6-test.com にアクセスすると確認できます)

C:\Users\user>ping 2001:f70:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx

応答があれば成功です。これで、ラズパイにIPv6環境からアクセスすることができました!

[column] IPv6アドレスは原則いつもグローバル

IPv4では、宅外との通信はルーターのWAN側に対してISPから一つだけ割り当てられてたグローバルIPアドレスによって行われています。いっぽう宅内LANに存在するPCやスマホには、192.168 から始まるプライベートIPアドレスが機器ごとに割り当てられており、例えば宅内PCからインターネットに向かって送出したパケット(送信元アドレスは192.168.xx.xx)は、ルーターの NAT (Network Address Translation) と呼ばれる機能で送信元アドレスがグローバルIPアドレスに書き換えられてインターネットへと送り出されます。逆に、外部からルーターへやってきたパケットは、宅内LAN側の機器が送出したリクエストに対する応答に限ってLAN内へと通され、そうでないものはルーターによって遮断されます。これでは外部からやってきたパケット(HTTPを公開するなら80、マイクラのサーバーなら25565、etc)がLAN内の機器へと到着できないので、俗にいう「ルーターのポート開放」を行い、特定のポートに対する通信をLAN内へと通すことで、外部からのアクセスを可能にします。

ところがIPv6の世界では、いくつかの方法によって各機器に設定されたIPv6アドレスは、ルーターでNATが行われず、インターネットに対してやり取りするアドレスとしてそのまま用いられます。ためしに IPv6 test に家からアクセスすると、IPv4ではipconfigで見える自分のIPアドレスとは異なるアドレスからのアクセスとなっていますが、IPv6では自分の一時IPv6アドレスがそのまま見えています。なお、一時IPv6アドレスではない無印のIPv6アドレスは、端末のMACアドレスから生成される端末固有のもので容易に追跡ができてしまうので、インターネットへのアクセスには定期的に変更される一時IPアドレスが使われるようです。

何はともあれ、原理上は自分のIPv6アドレスがインターネットに対して野ざらしなので、外出先からでも IPv6 アドレスひとつで簡単にアクセスできるのです。

IPv4環境からのアクセス

世の中にはIPv4しか使えない環境も多く存在します(たとえば通学先の学内ネットワークはIPv6非対応です)ので、IPv4環境からもラズパイにアクセスできるようにします。

ところが我が家のような IPv4 over IPv6 方式の下では、俗に言うルーターのポート開放ができないそうです。したがって、IPv4環境から発せられたラズパイへのアクセスを無線LANルーター経由でラズパイに届けることはできないのです

対応策を探しまくった結果、「ラズパイでPPPoEセッションを張り、IPv4環境からのアクセスはPPPoEで受ける」方針で実装することにしました。楽天ひかりがIPoEとPPPoEの併用可能との情報に救われました。

実現したい IPv4 PPPoE 方式と IPv6 IPoE 方式の併用

ラズパイのPPPoE接続設定

こちらのサイトの受け売りなので私が書く必要ないかもしれません……。

pppoeパッケージのインストールと設定

pppoe, pppoeconf をインストール。

sudo apt install pppoe pppoeconf -y

pppoeconf を実行します。

sudo pppoeconf

PPPoEセッションを利用可能なネットワークインターフェイス(NIC)を自動で見つけて設定を進めてくれます。全部YesかOKで答えれば問題ありませんでした。途中、PPPoE接続用のユーザー名とパスワードを聞かれるので、ISPから受け取ったログイン情報を手元に準備しておきましょう。

ウィザードが終了したら、

ip addr show ppp0

で正しく接続できたか調べます。

5: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1454 qdisc pfifo_fast state UNKNOWN group default qlen 3
    link/ppp
    inet xxx.xxx.xxx.xxx peer yyy.yyy.yyy.yyy/32 scope global ppp0
       valid_lft forever preferred_lft forever

このように、ppp0 インターフェイスにIPv4アドレスが付与されたら成功です。この xxx.xxx.xxx.xxx が、ラズパイに対して付与されたグローバルIPv4アドレスです! うまく行かない場合はラズパイを再起動しましょう。私は再起動しないとちゃんと接続できませんでした。

手動接続・切断

以下のコマンドで可能です。注意点として、PPPoEセッション数の上限は1~2セッション/user なので、何回も pon しないように気を付けます。再接続したい場合は一度 poff してから pon します。

pon dsl-provider  # 接続
poff              # 切断

PPPoE接続時にデフォルトルートを変更

このままの状態だと、ppp0に到着したパケットに対する返答がppp0ではなくデフォルトのwlan0から出ていってしまうため、IPv4経由で本ブログにアクセスしてきた人が返答を認識できず、ブログを表示できません。そこで、ppp0経由で到着したパケットに対する返答をppp0経由でインターネットに返すよう、ルーティングテーブルを編集します。PPPoEへの接続時に自動実行されるシェルスクリプトを作成します。

sudo nano /etc/ppp/ip-up.d/10dsl-provider

内容は以下の通りです。仕組みについての詳しい解説は、こちらのページに譲ります。超大雑把にまとめると、

  • 「200番」というIDのルーティングテーブルを作成し、デフォルトルートを、ネットワークインターフェイス「dev ppp0」を出発し「$PPP_REMOTE」を経由するようにしなさい
  • 「$PPP_LOCAL」からマシンに入ってきたパケットは、ルーティングテーブル200番に従ってルーティングしなさい。このルールの優先度は200です(元々登録されているルールより優先度が高いので、こちらが優先される)

なお $PPP_LOCAL, $PPP_REMOTE は 10dsl-provider 実行時に pon が渡す環境変数なので、このスクリプトを単体で実行しても何も起きません。

#!/bin/sh
ip route add default via "$PPP_REMOTE" dev ppp0 table 200
ip rule add from "$PPP_LOCAL" table 200 prio 200

実行権限を与えて完了です。

sudo chmod 755 /etc/ppp/ip-up.d/10dsl-provider

参考にしたサイト

先人の方々の丁寧な解説に幾度となく助けられました。ブラウザの履歴の中から、特に参考になったサイトをピックアップしておきます。

更新履歴

  • 2022/9/10 ソースルーティングの設定を編集
  • 2022/9/23 ルーティングテーブルの番号を修正

コメントを残す

メールアドレスが公開されることはありません。