WireGuardでVPN環境初構築記録

家と作業拠点との間をVPNで接続したくなり、格闘の末なんとか目的を達成できたので、その記録。
実際に色々ハマりながら、なんとか動作する設定に至ると、「あぁこういうことだったのか」と感じることも多く、面白いですね。

環境とここでの用語

家には実は2回線あったことを思い出し(1回線は全然使っていなかったのだけど解約もしていなかった)、これは「2拠点接続の勉強をするのに最適ではないか!」ということで、今回の着手に至った次第。
思い出したほうの回線にラズパイを接続してルータにてDMZ指定。同じネットワークにWindowsのノートPCが一台接続されている状態にしました。こちらをここでは便宜上「サーバ側」とか「RPi側」とか呼ぶことにします。
一方のアクセス元となる環境は、普段の自分の家の環境。WindowsPCが動いています。こちらここでは便宜上「クライアント側」と呼びます。
サーバ側は 192.168.1.0/24、家のほうは 192.168.0.0/24 です。

VPN接続までのおおまかな流れ

サーバ側:

  • WireGuardのインストール
  • 設定ファイルの記述1:予め作成した自分の鍵情報を記述する
  • 設定ファイルの記述2:接続を許可する先(クライアント)の鍵情報などを記述する
  • WireGuard立ち上げ(そして待ち受け)

クライアント側:

  • WireGUardのインストール
  • 設定ファイルの記述1:予め作成した自分の鍵情報を記述する
  • 設定ファイルの記述2:接続先の情報を記述する
  • 接続指示!と確認

構築手順

WireGuardインストール

クライアント側はまずは WSLのUbuntu上にて作業した(後に Windows用アプリを入れてネイティブでも動作確認済)。

サーバ側・クライン側とも

apt install wireguard
鍵ペアの作成

本質的にはサーバ側、クライアント側ともに同じ事をするが、ファイル名を異なるものにしている(べつにファイル名は何でも良いのだけど、なくさないためにファイルに保存し、パーミション制限している。厳密に言えば作ってからパーミッション変更すると、作った瞬間に覗かれる可能性を排除できないので、umaskしたり予めパーミション設定したファイル(touchなど)に鍵を書き込むなどのほうがベスト。)。

サーバ側:

# 秘密鍵を作成
wg genkey | sudo tee /etc/wireguard/server.key
sudo chmod 600 /etc/wireguard/server.key

# 公開鍵を生成
sudo cat /etc/wireguard/server.key | wg pubkey | sudo tee /etc/wireguard/server.pub
sudo chmod 600 /etc/wireguard/server.pub


クライアント側:

# 秘密鍵を作成
wg genkey | sudo tee /etc/wireguard/client.key
sudo chmod 600 /etc/wireguard/client.key

# 公開鍵を生成
sudo cat /etc/wireguard/client.key | wg pubkey | sudo tee /etc/wireguard/client.pub
sudo chmod 600 /etc/wireguard/client.pub
設定ファイルの記述(サーバ側)

サーバ側(接続を待ち受ける側)の設定。[Interface]セクションに自分の(サーバ側の)条件を書き、[Peer]側に接続を許可する相手側の情報を書く

/etc/wireguard/wg0.conf (新規作成する。wg0というインタフェース名にする場合はこのファイル名)

[Interface]
PrivateKey=wOchd2/do5Pe4VRzk3L3pVQHgO4kDUh/3Aec+GBPxFo=
Address=172.16.0.10
ListenPort=51830

[Peer]
PublicKey=bgzIVy3u0A9b+AB5lvknZb5mlfugZ91/9Z0YOBNk460=
AllowedIPs=172.16.0.0/24

InterfaceのPrivateKeyには自分の秘密鍵(server.key)の内容を記述し、
PeerのPublicKeyには接続を許可する相手の公開鍵(client.pub)の内容を記述する。
ここでAddressは、VPN接続に使うインタフェースのアドレス(決める)、
AllowedIPsは、接続を許可する相手のネットワークを記述する。

設定ファイルの記述(クライアント側)

クライアント側(接続をしかける側)の設定。[Interface]セクションに自分の(クライアント側の)条件を書き、[Peer]側に接続先の情報を書く。

[Interface]
PrivateKey = eBXv9XmFgNJYfWxoQH3Z6jBgo4KaX/X22DvTKZKo8lc=
Address = 172.16.0.12/32

[Peer]
PublicKey = aeMvyD+IIlAzphOLS/uyVn9gZdF/pwsT/K6Rs4GtOj4=
AllowedIPs = 172.16.0.0/16, 192.168.1.0/24
Endpoint = XXX.YY.ZZZ.83:51830

InterfaceのPrivateKeyには自分の秘密鍵(client.key)の内容を記述し、
PeerのPublicKeyには接続を許可する相手の公開鍵(server.pub)の内容を記述する。
Addressは、VPN接続に使うインタフェースのアドレス(サーバに設定したのと同じネットワークで、かぶらないもの)。
AllowedIPsは、接続先でアクセスするIPアドレスの範囲。今回はラズパイの裏側にあるネットワーク(今はノートPC1台しかないけど)にもアクセスしたいので、書いておく(実際は裏側にアクセスするためにもう少し設定が必要なので、あとで加えても良いのだけど)。

Endpointは、サーバのIPアドレスと、サーバのwg0.confに記述したポート番号。

接続

サーバ側の待ち受け
sudo systemctl start wg-quick@wg0

(停止したいときは stop、再起動したいときは restart)
設定が正しければ、何のメッセージもなく完了する。誤りがある場合は何か表示される。
このとき wg コマンドで以下の様に表示される。peerに許可先の公開鍵とネットワークが表示されていることがポイント。

$ sudo wg
interface: wg0
  public key: abcdltOAzph/uMvyDZdF/pw+yVSsT/K6Rs4Gn9gOLj4=
  private key: (hidden)
  listening port: 51830

peer: YiKGzKIo6YimEBO5+EsNTuxQymc4VUfC3NgSRJLqryU=
  allowed ips: 172.16.0.0/24
クライアント側からの接続

wg0インタフェースを立ち上げる

sudo wg-quick up wg0

(落とすときは down)
wgコマンドで状態を確認するとこんな感じ。

$ sudo wg
interface: wg0
  public key: gZAB3ku4VlZfbA0m6nb7I9zy30/NZ+vk9u1OYB5bll0=
  private key: (hidden)
  listening port: 50673

peer: tKPslcohiT3Hmsf2mNbvozREpsshlZ+hoAXrBtsc6Bw=
  endpoint: XXX.YY.ZZZ.83:51830
  allowed ips: 172.16.0.0/16, 192.168.1.0/24

正しく設定されていれば、サーバ側RPiへのPingが通るはず。

\> ping 172.16.0.10
172.16.0.10 に ping を送信しています 32 バイトのデータ:
172.16.0.10 からの応答: バイト数 =32 時間 =53ms TTL=64
172.16.0.10 からの応答: バイト数 =32 時間 =17ms TTL=64
172.16.0.10 からの応答: バイト数 =32 時間 =19ms TTL=64
172.16.0.10 からの応答: バイト数 =32 時間 =23ms TTL=64


一度(pingなどで)アクセスがあると、サーバ側ではpeerに接続情報が表示されるようになる。

interface: wg0
  public key: abcdltOAzph/uMvyDZdF/pw+yVSsT/K6Rs4Gn9gOLj4=
  private key: (hidden)
  listening port: 51830

peer: YiKGzKIo6YimEBO5+EsNTuxQymc4VUfC3NgSRJLqryU=
  endpoint: PPP.QQ.RRR.219:26718
  allowed ips: 172.16.0.0/24
  latest handshake: 20 minutes, 33 seconds ago
  transfer: 564 B received, 476 B sent

以上で、家とサーバ側とでVPNが張れました。ただしこの時点では、先方のラズパイとつながっただけです。
なので、最後に「サーバ側で、サーバの裏側のネットワークにもアクセスできるようにする」設定をします。

サーバ側のネットワーク上の機器にアクセスできるようにするための設定

ラズパイ自体の設定

ラズパイ、というか今回使った Ubuntu 24.04 ではネットワーク内の他の機器へのフォワードが許されていないので、まずこれを許可する設定をします。

  • 1. /etc/sysctl.conf に「net.ipv4.ip_forward=1」の行がコメントアウトされているので、有効化する
  • 2. sudo sysctl -p で反映
wg0.confの設定

ip a などでフォーワードしたいネットワークアダプタの名前を確認します(ここでは eth0。無線LANを使っている場合は wlan0とかの場合もあるでしょう)。

[Interface]
(略)
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
アクセス元の wg0.confの設定

ここで wg0.confの [Peer] の AllowedIPsに相手方のアクセスしたネットワーク(ここでは 192.168.1.0/24)を指定するのが流れなのですが、今回は最初に設定してしまったので、とくにここでやることはないです。

あとは、相手側ネットワーク上のPCに向けてアクセスできることを確認すれば良いです。
例:

\> ping 192.168.1.10
192.168.1.10 に ping を送信しています 32 バイトのデータ:
192.168.1.10 からの応答: バイト数 =32 時間 =26ms TTL=127
192.168.1.10 からの応答: バイト数 =32 時間 =23ms TTL=127
192.168.1.10 からの応答: バイト数 =32 時間 =35ms TTL=127
192.168.1.10 からの応答: バイト数 =32 時間 =23ms TTL=127

(おまけ)リモートデスクトップ接続しようとしてハマった件

総仕上げとして、相手側ネットワークにあるWindowsマシンへとリモートデスクトップ接続しようとして、えらくハマりました。私がハマったポイントを。

1. ノートPCをwi-fiに繋ぐ際に「パブリックネットワーク」にしてしまったせいで、全然外からアクセスできなかった
2. セキュリティソフトが「ネットワーク保護」として、外からのアクセスを拒否していた(ファイアウォール
3. そもそもそのノートでリモートデスクトップ許可していなかった

リモートデスクトップ以外の確認方法

あとはpythonで雑にサーバ立てて curlで疎通確認したりもしました。結構便利。

python -m http.server 8080

その他

ここには書いてないけど

  • IPアドレスの固定化
  • デフォルトでRaspPi3のUbuntuがaptでのインストールを許可してくれてなかったのでごにょごにょ設定

など、やっています。


写真はAIが考えたWireGuardのイメージ。