Debian LinuxでもWireGuardで自宅VPNネットワークを構築するやり方


2022/03/02
蛸壺の技術ブログ|Debian LinuxでもWireGuardで自宅VPNネットワークを構築したいと思った時の話

VPN(Virtual Private Network)接続はその名の通りで、ソフトウェア的に特定の人のみが利用できる仮想の専用ネットワークを構築する技術です。

VPNというと一般の個人レベルユーザーにはかなり導入の敷居が高く、専用のルーターを設置したり、管理者として通信のトンネリング・暗号化など、通信セキュリティ面で十分な知識をもって扱わないと不安だったりと、気軽に扱うこともできない代物でした。

近年、注目のVPNオープンソースプロジェクトとして注目を集めてきている
「WireGuard」をネット記事でもチラホラと見るようになり、自前のDebianOSパソコンがちょうど遊んでいたため、少しこのWireGuardを試してみたくなりました。

ということで、今回はDebianOS上で、WireGuardサーバーを立ち上げておいて、適当なクライアントでSSH接続させるまでの手順を説明していきましょう。


WireGuardサーバーをDebianOS上に構築する

今回の構成の模式図は以下のようになります。

合同会社タコスキングダム|蛸壺の技術ブログ

まずは自宅のWireGuardサーバー機のほうからインストールしていきます。

WireGuardアプリケーションのインストール方法はOSごとに違いますので
公式のドキュメントを良く読んで頂くとして、今回はDebianOSにWireGuardをインストールします。

手元で試したのは以下の環境の通りです。

            
            #👇基本OS情報
$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 11 (bullseye)
Release: 11
Codename: bullseye

#👇Debianのマイナーバージョン情報
$ cat /etc/debian_version
11.2

#👇Linuxカーネルの情報
$ uname -srv
Linux 5.10.0-10-amd64 #1 SMP Debian 5.10.84-1 (2021-12-08)
        
では早速サーバー機にwireGuardをインストールします。

            
            $ sudo apt update
$ sudo apt install wireguard
        
これでDebianにWireGuardがインストールされました。

            
            $ wg --version
wireguard-tools v1.0.20210223 - https://git.zx2c4.com/wireguard-tools/
        
インストールしたら設定を反映させるために一度再起動しておいたほうが良いでしょう。

WireGuardのクレデンシャルの設定

次にWireGuardを使うための公開鍵と秘密鍵を生成するステップに移ります。

WireGuardにもSSHと同じように秘密鍵と公開鍵をセットで利用することになります。

ただし、WireGuardの認証形式は、SSHのようにサーバーに公開鍵、クライアントに秘密鍵を持たせて2つを照合するのではなく、サーバとクライアントの双方に以下のようなクレデンシャルを設定する必要があります。

            
            + wgserver.key サーバ用秘密鍵
+ wgserver.pub サーバ用公開鍵
+ wgclient.key クライアント用秘密鍵
+ wgclient.pub クライアント用公開鍵
        
これらのクレデンシャルのセットがVPN接続認証に必要になります。このクレデンシャルは、wgコマンドから作成をすることができます。

クレデンシャルの生成・アクセスには通常のユーザーからは制限されているので、以下の操作はルートユーザー(su)から操作することにします。

            
            $ su
#👇以降ではルートユーザーで操作
># cd /etc/wireguard

#👇サーバー用のキーを生成
># wg genkey > wgserver.key
># wg pubkey < wgserver.key > wgserver.pub

#クライアント用のキーを生成
># wg genkey > wgclient.key
># wg pubkey < wgclient.key > wgclient.pub

#👇ルートユーザー以外の秘密鍵のファイル操作権限を制限
># chmod 600 wgserver.key
># chmod 600 wgclient.key

#suから抜ける

$ sudo ls -la /etc/wireguard/
-rw-------   1 root root    45  2月 28 11:58 wgclient.key
-rw-r--r--   1 root root    45  2月 28 11:58 wgclient.pub
-rw-------   1 root root    45  2月 28 11:56 wgserver.key
-rw-r--r--   1 root root    45  2月 28 11:57 wgserver.pub
        
これでWireGuardクレデンシャルの準備は完了です。

ちなみに、suで管理者ルートモードに入って作業するのがなんだかダサいと思われる方は、
teeコマンドからのパイプで/etc/wireguard/以下にファイルを生成できるようになります。

            
            $ wg genkey | sudo tee /etc/wireguard/wgclient.key
$ sudo cat /etc/wireguard/wgclient.key | wg pubkey | sudo tee /etc/wireguard/wgclient.pub
$ sudo chmod 600 /etc/wireguard/wgclient.key /etc/wireguard/wgclient.pub
        

またコマンドでクレデンシャルを生成するのが面倒な方は、オンラインツールの
Wireguard Config Generatorでも同じ用にキーペアを作ることができます。

クレデンシャルの生成はお好みの方法を選択できるのですが、その後生成した鍵は失くさないようにきちんと管理を心がけましょう。

【サーバー側】WireGuardのconfファイルを設定する

次にWireGuardサーバー側で内部confファイルを設定していきます。

/etc/wireguard/以下にwg0.confを作成して、以下のような内容で編集します。

今回は例として、WireGuardサーバー側に
10.0.17.1、とそのクライアント一台に10.0.17.2を割り振ります。

なお、現在のLANネットワークに競合するようなプライベートIPが無い限りはこのWireGuardネットワークのIP値は自由に割り振ることが可能です。

            
            [Interface]
Address = 10.0.17.1/32
PrivateKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(※wgserver.keyの中身)
MTU = 1420
ListenPort = 51820

[Peer]
PublicKey = yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy(※wgclient.pubの中身)
AllowedIPs = 10.0.17.2/32
        
WireGuardの設定ファイルの簡単な書式だけ説明しておくと、

            
            [Interface]: 自分側の設定
    Address: WireGuardで使用するIPアドレスを指定
    MTU: 接続時のMTU値。
        デフォルトでは1420が設定される。
        環境によってはネットワークが不安定動作 (切断を繰り返す等)
        する場合、1400や1380に下げて試す
    PrivateKey: 秘密鍵(.key)の中身を貼り付ける
    ListenPort: WireGuardのサービスポート番号。
        サーバー側のデフォルトでは51820
    DNS: 優先するDNSサーバーを指定できる
    PostUp: WireGuardの起動時に実行するコマンドを記述。
        ここでiptablesを設定することでポートフォワーディングなどを構築する
    PostDown: 停止時に実行するコマンドを記述

[Peer]: 相手側の設定
    PublicKey: 相手側の秘密鍵(.key)からペアリングした
        公開鍵(.pub)の中身を貼り付ける
    AllowedIPs: 相手がクライアントならば、VPN接続を許可したい
        クライアントのIPリストを記述する。
        対向がサーバーの場合にはサーバー側ネットワーク内にある接続機器のうちで
        通信を許可するIPリストになる
    Endpoint: (クライアントのときのみ使用)サーバーのIPとポートを指定
        
サーバーのconfファイルを設定し終えたら、一度試しにWireGuardの起動してみましょう。

WireGuardの起動や終了は、
wg-quickというスクリプトを介して行われます。

本番前のWireGuardサーバーをデバッグするならwg-quickをコマンドとして利用して起動状態をターミナルから確認できます。

            
            $ sudo wg-quick up wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.0.17.1/32 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] ip -4 route add 10.0.17.2/32 dev wg0
        
正常にWireGuardが立ち上がりました。

ipコマンドでもWireGuardインターフェースが正常に生成されていることを確認しておきます。

            
            $ ip address
(...略...)
12: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none
    inet 10.0.17.1/32 scope global wg0
       valid_lft forever preferred_lft forever
        
wg0.confで指定していたサーバー側のIPアドレス(10.0.17.1)が割り振られていればWireGuardサーバーの起動に成功してます。

WireGuardサーバー落とす場合には、

            
            $ sudo wg-quick down wg0
[#] ip link delete dev wg0
        
では問題無さそうですので、WireGuardのインターフェースwg0を使って本番サービスとして常駐化させてみます。

ここではシステムデーモンのユニット名は
「⁠wg-quick@使用するインターフェイス名」で呼び出すルールとなっています。

            
            $ sudo systemctl enable wg-quick@wg0
$ sudo systemctl start wg-quick@wg0
        
これで設定ファイルに異常がなければ以下のように起動していることが確認できます。

            
            $ systemctl status wg-quick@wg0
● wg-quick@wg0.service - WireGuard via wg-quick(8) for wg0
     Loaded: loaded (/lib/systemd/system/wg-quick@.service; disabled; vendor preset: enabled)
     Active: active (exited) since Mon 2022-02-28 13:43:27 JST; 1min 2s ago
       Docs: man:wg-quick(8)
             man:wg(8)
             https://www.wireguard.com/
             https://www.wireguard.com/quickstart/
             https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8
             https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8
    Process: 1215 ExecStart=/usr/bin/wg-quick up wg0 (code=exited, status=0/SUCCESS)
   Main PID: 1215 (code=exited, status=0/SUCCESS)
        CPU: 37ms
        

サーバーサイドのポートフォワード(IPv4)の設定確認

先程までの内容だと、実はまだ十分なVPN接続が確立できていません。

WireGuardはVPN通信のための仮想IPアドレスとwgインタフェースが内部で作成されて動作します。

素のままだと、インターネットからWireGuard VPNまでの通信は確立できるようになるのですが、肝心のWireGuardから自宅LAN側の他のネットワーク機器と通信ができません。

そこでWireGuard(VPN)ネットワークから自宅LAN(192.168.0.1等)に存在する他の機器へのルーティングを作成しましょう。

まずパケットのポートフォワーディングを有効にしておく必要があります。

そこでサーバー機の
/etc/sysctl.confのconfファイルの中身を確認しておきましょう。

            
            #...中略
#👇コメントアウトを外す
net.ipv4.ip_forward=1
#...以下省略
        
こうすることで、WireGuardインタフェースとLinuxサーバーの標準インタフェース間で通信が正常に確立されるようになります。

sysctl.confを書き換えたら以下のコマンドで変更を反映させます。

            
            $ sudo sysctl -p
        
次にWireGuardサーバー機で、起動と終了時にIPマスカレードを行うためのiptablesルールをwg0.confのPostUpPostDownに追加しましょう。

            
            [Interface]

#...中略

#👇追加
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o enp3s0(※) -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o enp3s0(※) -j MASQUERADE
#...略
        
なお手元の環境では-oオプションにenp3s0というアクティブなインターフェースを指定しますが、ネットワークインターフェース名は環境によって違います。現在のサーバー機でアクティブになっている実機NICに置き換える必要がありますのでご注意ください。

これでwg0を再起動して、
iptablesコマンドを使うと、新しいIPマスカレードルールが追加されていることが確認できます。

            
            $ sudo systemctl restart wg-quick@wg0
$ sudo iptables -L -n -t nat
#...略
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0
#...略
        

NATを越えるために〜ブロードバンドルータのポート開放

さて、折角WireGuardサーバーがお宅内に立てても、外部から繋げないと意味がありません。

このため外部からのアクセスを遮断するのためにブロードバンドルーターは全てのポートを閉じていると思いますが、WireGuard用にポートを一つ開けておくが必要になります。

最近のブロードバンドルーターには必ずと言っていいほどポートフォワーディング設定を手動で行える機能があると思いますので特にどの機種が良いというのは無いのですが、ここでは手持ちでコストパフォーマンスの良さから
「TP-Link Archer A10」を使っています。

従来のOpenVPNなどでは、ルーターにもポートフォワーディング設定をする必要がありました(今はどうなのかな....?)。

NAT転送の設定手順の詳細はルーター製品の取扱説明書を良く読んで貰うとして、TP-LINK Archerルーターの場合、ルーターの管理画面にログインをし、
[詳細設定] > [NAT転送] > [仮想サーバー]に進みます。

そして以下のように新しいNAT転送ルールを追加します。

合同会社タコスキングダム|蛸壺の技術ブログ

これで外部からWireGuardサーバーへアクセスする場合の設定は完了です。

なお、TP-LINKルーターでNAT転送指定するWireGuardサーバー機のプライベートIPは固定する必要があるので、MACアドレスで固定IPをバインドしているかを確認しましょう。

余談〜ラズパイでPiVPNを使ったVPNサーバーの構築

WireGuardサーバーを立ち上げるのに、設定ファイルをアレヤコレヤと手動で設定するのは多少骨が折れます。

ラズパイを持っていて、それをWireGuardサーバーにしたいというかたがいらっしゃるなら、
PiVPNを使うと、より簡単にWireGuardサーバーが構築できるようです。

参考|ラズパイで簡単にVPNを構築する

参照|ネットワークに外出先からアクセス! ラズパイ(Raspberry Pi)とWireguardで作るVPNサーバ

PiVPNはVPNの設定をCUIからYes/Noでポチポチと設定作業できるようになっているだけで、WireGuardの中身としては今回手動で設定していることと同じことをラズパイ内部で処理しているようです。


WireGuardクライアントを試す

さて、先程のパートでは自宅にWireGuardサーバーを構築しとりあえず起動状態しておくところまで解説してみました。

早速どこか自宅外のネットワークから、自宅のWireGuardに接続してみたい衝動に駆られますが、実はここまでWireGuardを解説しておきながら
後述する実に田舎の地方自治体的な理由で、個人的な自宅VPN化計画が少し頓挫しています...。

折角ここまでWireGuard VPNを構築したのでVPN接続の雰囲気だけでも試してみることにします。

ということでWireGuardクライアントから、自宅外からではなく内部のネットワークからWireGuardサーバーにアクセスし、ローカルでVPN接続が出来ているかを検証していきます。

NAT越えしないローカルでWireGuardを試す場合、以降で説明するクライアント機のconfファイルのEndpointを、

            
            #....

[Peer]
#....
#EndPoint = [グローバルIPアドレス]:51820
#👇ローカルでWireGuardを試す場合
EndPoint = [サーバー機のプライベートIPアドレス]:51820
#....
        
で指定してあげると、ローカルVPNモードで接続可能です。

別のLinuxOSクライアントで試す

現在、WireGuardクライアントはほぼすべてのOSと言っていいほど充実した対応になっています。

各OSごとのWireGuardのインストール方法は
公式のドキュメントに従ってください。

ここではなにか別のLinuxOSをクライアントにしてからWireGuard VPNに接続してみます。

まずはWireGuardクライアント側にもconfファイルを設定します。

confファイルの書式作法としては
先程説明していた内容と同じです。

先程のサーバーの設定と同様に
/etc/wireguard/wg0.confを以下の内容で作成しましょう。

            
            [Interface]
PrivateKey = vvvvvvvvvvvvvvvvvvvvvv (※wgclient.key)
Address = 10.0.17.2/32 (※クライアントのIPアドレス)
ListenPort = 51820

[Peer]
PublicKey = zzzzzzzzzzzzzzzzzzzzzzz (※wgserver.pub)
#EndPoint = [(自宅の)グローバルIPアドレス]:51820
EndPoint = [WireGuardサーバー機のプライベートIPアドレス]:51820
AllowedIPs = 0.0.0.0/0 (※WireGuardサーバー側にある通信したいIPアドレス)
        
クライアント側だと、[Interface]にクライアント自身の設定、[Peer]にサーバー側の情報を登録するように記述します。

[Interface]の設定から軽く解説すると、まず先程上のパートで生成しておいたwgclient.keyの中身を貼り付けます。

そしてサーバー側で許可(
AllowedIPs)していた10.0.17.2というIPをクライアントのIPとして割り当てています。

クライアントの
[Peer]には、やはり先程のあらかじめ生成しておいたサーバー側の公開鍵(wgserver.pub)の中身を貼り付けます。

EndPointプロパティには、インターネット越しに外部から家庭内へ接続する場合、サーバー側のIPアドレスはグローバルIPアドレスを設定します。もしグローバルIPが何らかの理由で固定割り当てできない場合には、適当なDNSサービスを利用してこのEndPointへ割り当てを行います。

後はサーバー側でアクセスしたいIPのリストを
AllowedIPsに付与します。

ここでは深く考えず、
0.0.0.0/0はサーバー機のVPN仮想IP(10.0.17.1/32)も含めて、LAN内に存在しているネットワーク機器のIP全てでアクセスする想定の設定を使っています。

ではWireGuardクライアントを立ち上げてみましょう。

            
            $ sudo wg-quick up wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.0.17.2/32 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] wg set wg0 fwmark 51820
[#] ip -4 route add 0.0.0.0/0 dev wg0 table 51820
[#] ip -4 rule add not fwmark 51820 table 51820
[#] ip -4 rule add table main suppress_prefixlength 0
        
...エラーが出なればこれでVPN接続できたようです。

適当にクライアントからサーバー機にpingしてみると、

            
            $ ping 10.0.17.1
PING 10.0.17.1 (10.0.17.1) 56(84) bytes of data.
64 bytes from 10.0.17.1: icmp_seq=1 ttl=64 time=674 ms
64 bytes from 10.0.17.1: icmp_seq=2 ttl=64 time=2.10 ms
64 bytes from 10.0.17.1: icmp_seq=3 ttl=64 time=2.29 ms
#.....
--- 10.0.17.1 ping statistics ---
15 packets transmitted, 15 received, 0% packet loss, time 32ms
rtt min/avg/max/mdev = 1.820/46.805/674.177/167.672 ms
        
接続が確立できているようです。

他方サーバー側で
wgコマンドから接続状態を確認してみます。

            
            $ sudo wg
interface: wg0
  public key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=
  private key: (hidden)
  listening port: 51820

peer: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=
  endpoint: xxx.xxx.xxx.xxx:51820
  allowed ips: 10.0.17.2/32
  latest handshake: 1 minute, 16 seconds ago
  transfer: 11.80 KiB received, 18.87 KiB sent
        
確かにクライアント(10.0.17.2)がWireGuardサーバーへ接続していることが確認できました。

余談〜おらが村のインターネット事情:グローバルIP...じゃない?

VPN接続に欠かせないの要素の一つが、外部から家庭内LANにアクセスするための『グローバルIP』になるわけです。

著者も数年前に引っ越ししてきた傍ら、現在の周りにほぼ田園しかない集落でインターネットをどうするか町役場に相談したところ、
「町内光回線」しかブロードバンドに対応したインターネット回線の選択肢がないとのことで、深く考えずに契約してしまいました。

で、そこからしばらく経ち、自宅VPNを構築しようとしてルーター設定を確認したところ、

合同会社タコスキングダム|蛸壺の技術ブログ

WAN側のIPが、なんだかプライベートIPで割り振られているのに気づきました。

こちらの
自治体のブログでも同じような話を紹介されていらっしゃいますが、どうも住んでいる町が独自に契約した光回線をさらに町内の一般家庭へと分線している都合で、家庭に割り振られているWAN IPもプライベートIP...結構正規の光回線サービスの料金が取られていてこれはショックです。

契約前に聞いておくべきだったのですが、
当然グローバルIP無いと、お家VPN出来ません。

この忌まわしき「町内光回線」は3年間契約で、もう少しで契約満期なので、とりあえず契約が終わるのを待ってから別のグローバルIPの使えるインターネット回線への乗り換えを考えております。

当然、ドが付くくらいの田舎ですので、グローバルIPの付くインターネットサービスという選択肢は限られております。

グローバルIPを手頃な値段で利用したいのであれば、モバイル通信回線のキャリア各社の提供する
WiMax2+系のプランがコストパフォーマンスに優れています。

例えば、
『DTI WiMAX 2+』のグローバルIPオプションを付ければ良さそうです。

合同会社タコスキングダム|蛸壺の技術ブログ

グローバルIPオプションの付いているWiMax2+プランは他にもあり、料金的に少しだけお得な
『BIGLOBE WiMAX 2+』も候補として良さそうです。

ただし、BIGLOBE WiMAX 2+では
UQコミュニケーションズの提供するグローバルIPオプション(WiMAX 2+用)を別で契約する必要があるとのことで多少手間かも知れません。

また、グローバルIP固定に様々なサービスバリエーションを提供する
『ASAHIネット WiMAX2+』も固定IPオプションを利用することで、VPNを気軽に使えるようにできるようです。

合同会社タコスキングダム|蛸壺の技術ブログ

モバイルでもグローバルIP固定サービス付きの高速回線が使えるようになってきているので、既に光回線サービスに拘らなければならない時代もいずれ終わりに近づくのかも知れません。


まとめ

今回はWireGuardを使った簡単に構築できるVPN接続の話をまとめてみました。

これまで「ちょっと敷居が高くて自宅VPNをやってみたいけど...」と、ためらっていたかたも、この際WireGuardを試してみるのも一興かと思います。

参考サイト

WireGuardでVPNサーバーを構築する

WireGuardを使って自宅にVPN接続する方法

さくらのVPSにWireGuard入れて個人用途のVPN環境作った

【2021年版】AWS EC2 AmazonLinux で WireGuard による VPN 環境構築