ねこ島

iOSのこととか、日常について雑に書きます

v6プラス環境下でもWireGuardを使って自宅VPNサーバーを構築する

はじめに

コロナ禍が落ち着き出社や外出する機会が増え、外にいる時間が長くなってきたように感じます。 外出時はモバイル回線を利用するので外部からのアクセスを許容しないNASSSHが利用不可となり不便です。これを解決するためにVPNが必要になります。

当初は手軽に利用できたのでTailscaleを使っていましたが、接続のピア数も現状モバイル一つだけという状況でそこまで高機能である必要がなく、前々からVPNサーバーを建ててみたいという気持ちもありました。

そこで今回、HomeBridgeやらモニタリングツールやら色々管理するために利用している我が家のRaspberry PiくんにサクッとWireGuardを導入して外出先から利用できるようにしてみました。

環境

  • v6プラスを契約したフレッツ光回線
  • VPNサーバーを構築するマシン
    • Raspberry Pi 4 (8GB)を利用します
    • docker composeが導入済み前提です

なぜWireGuardを使うのか

様々な種類のVPNプロトコルが存在しますが、今回選定に当たって重視すべきポイントは以下の3つ。

  • 通信ポートの変更が可能かどうか
  • 安全性・セキュリティが確保されているか
  • モバイルで利用しやすいか(サポートされているか、専用Appが用意されているか)

特に一番上の通信ポートの変更が可能かどうかは自宅ネットワーク上で構築する上では必須の要件でした。

なぜなら自宅回線ではv6プラスを契約しているため、使えるポート番号に限りがあります。 追加費用を払って固定IPを契約していれば自由にポート番号が使えますが、そうでなければ他の回線契約者と共有のグローバルIPv4アドレスと決まったポート番号が割り当てられます。

この決まったポート番号というのが厄介で、まずWell knownポートは割り当てられません。つまりWebサーバーの公開や、IPSecはv6プラス環境下において利用できません。

じゃあ1024番以降の固定ポート番号を要求するアプリケーションは使えるのかというとそうでもなく、どのポート番号が使えるかは特定の計算方法で決まるため、基本的にこちら側からポート番号を指定できる必要があります。

これらの条件を満たすVPNプロトコルOpenVPNとWireGuardの二択になり、パフォーマンスの観点でより高速なWireGuardを使うことを決めました。

構築手順

1. 利用可能なポート番号を把握する

VPNサーバーは外部からリクエストを受けるためにポート開放する必要がありますが、前項でも記述したとおり、v6プラス上ではポート番号が決まっているため事前にどのポート番号が利用できるか把握しておく必要があります。

どのポート番号が利用可能かどうかを調べるためには、以下のサイトを利用することで簡単にわかります。

isecj.jp

利用可能なポート番号がいくつか出てくるのでどれか一つを選んでメモっておきます

2. ポート開放する

筆者はYAMAHA製のNVR510を利用しているためそちらの管理画面を例に紹介します。 ルータによってポート開放方法が異なるため、よくわからない場合は「お手持ちのルータ名 + ポート開放」でググってください

1. ダッシュボードの詳細設定 > NATを開き、NATディスクリプターの設定へ進む

2. 静的IPマスカレード設定に以下のパラメータを追加する

  • 内側アドレス: VPNサーバーのプライベートIPアドレス
  • プロトコル: udp
  • ポート番号: 利用可能なポート番号を把握する で決めたポート番号

設定後こんな感じになっていればOKです

これでルータ側の調整はおしまいです。次に実際にWireGuardを導入していきます。

3. [If needed] Linuxカーネルを5.6以降に引き上げる

Linuxカーネルバージョン5.6からWireGuardモジュールがサポートされており、Docker ComposeでWireGuardを立ち上げるときにモジュールが有効かどうかのチェックが行われます。バージョンを確認して必要であればアップグレードしましょう。

カーネルバージョンは以下のコマンドで確認できます

owen@rp:~ $ uname -a
Linux rp 6.1.21-v8+ ...

アップグレードする場合はaptを叩きます

owen@rp:~ $ sudo apt update
owen@rp:~ $ sudo apt full-upgrade

4. Docker ComposeでWireGuardを立ち上げる

筆者はローカル環境を汚すのを嫌うため、アプリケーション系をコンテナ管理にしています。 docker-compose.ymlを作成し、以下のように記述していきます

version: "3"
services:
  wireguard:
    image: lscr.io/linuxserver/wireguard:latest
    container_name: wireguard
    cap_add:
      - NET_ADMIN
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Asia/Tokyo
      - SERVERURL=auto
      - SERVERPORT=xxxxx
      - PEERDNS=xxx.xxx.xxx.xxx
      - PEERS=1
      - LOG_CONFS=true
    volumes:
      - ./config:/config
    ports:
      - xxxxx:51820/udp
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
    restart: unless-stopped

それぞれパラメータについて解説します

environment

  • PUID, PGID
    • コンテナの実行ユーザーIDを指定します
  • TZ
  • SERVERURL
    • サーバーの接続先ドメインを指定できます。筆者はIPv4アドレスを直打ちで使用しているのでautoにしているが、DDNSなどを利用していればここへ
  • SERVERPORT
    • 接続先ポート番号を指定する。前項で決めたポート番号を入力する
  • PEERDNS
    • DNSサーバーの指定があればここに。筆者はルータが持つRecursive DNSを利用しているためルータのIPアドレスを入力しています
  • PEERS
    • ピア(クライアント)の数を指定します。ここは必要台数分指定します
  • LOG_CONFS
    • 設定用のQRコードをログに吐き出すかどうかを設定できます。セットアップで使いたいのでtrue

ports

  • (SERVERPORT):51820/udp
    • サーバー側で待ち受けるポート番号と、コンテナ内部のWireGuardが待ち受けるポート番号をマッピングします
    • ここが漏れてると疎通しないので要注意

sysctls

  • net.ipv4.conf.all.src_valid_mark=1
    • デフォルトでついてたやつ。よくわからなかったので調べてみると、fwmarkとReverse Path Filtering(RPF)を有効にするためのパラメータとのこと

src_valid_mark - BOOLEAN

0 - The fwmark of the packet is not included in reverse path route lookup. This allows for asymmetric routing configurations utilizing the fwmark in only one direction, e.g., transparent proxying.

1 - The fwmark of the packet is included in reverse path route lookup. This permits rp_filter to function when the fwmark is used for routing traffic in both directions.

This setting also affects the utilization of fmwark when performing source address selection for ICMP replies, or determining addresses stored for the IPOPT_TS_TSANDADDR and IPOPT_RR IP options.

IP Sysctl — The Linux Kernel documentation

  • ざっくりした説明としてはパケットの経路を厳密に検証するモードで、IPスプーフィングなど偽装されたパケットを破棄してくれるようになる
  • ただ環境によっては正当なトラフィックであってもパケットが破棄されてしまうケースがあるらしく、デフォルトオンになっていないのでパラメータで有効にしているっぽい

設定できたら docker compose up -d でコンテナを立ち上げます。
しばらくするとログに設定用のQRコードが吐かれるので、docker compose logs でログを確認しましょう

5. モバイルアプリから接続する

有り難いことにAppStoreに専用のアプリケーションが公開されているのでそちらをインストールします。

WireGuard

WireGuard

  • WireGuard Development Team
  • ユーティリティ
  • 無料
apps.apple.com

起動したら右上の+ボタンから前項で確認したQRコードを読み取ります。 プロファイルが作られるのでこれで一旦接続できるか確認してみてください。

6. [If needed] VPNオンデマンドを有効にする

iOSにはWiFi, モバイル回線の接続状態に基づいてVPN接続・切断を自動的に行える仕組みがあります。 WireGuardもこの仕組みに対応しており、プロファイルの編集から設定が可能です。

具体的には以下のように設定できます

  • モバイル回線接続時にVPNへ接続する
  • Wi-Fi接続時にVPNへ接続・切断する
    • 特定のSSIDに接続した場合、VPNを切断するなど

この機能を活用すると、例えば自宅のWiFiに繋がっている間はVPNを切断しておき、外出時にモバイル回線あるいはホットスポットに接続した時はVPNを接続するといった処理を自動で行えるようになるのでおすすめです。

感想

WireGuardを利用し始めて半月ぐらいが経つのですが、ストレスなく利用できて快適です。最初は非力なRaspberry Pi上に構築して大丈夫だろうかと思ってたんですが、軽量なだけあってハングアップすることなく稼働してくれています。

ポート解放の手間だけありますが、それさえ乗り越えてしまえばサクッと導入できて便利なのでこれから自宅VPNの導入を考えている方にぜひお勧めです👍