ubuntu24.04/ubuntu22.04にWireGuardをインストールします。

まずはパッケージリストの更新、システムの全アップグレード、そして不要になったパッケージの自動削除をします。。sudo apt -y update は利用可能なパッケージのリストを更新します。sudo apt -y dist-upgrade は新しいバージョンのパッケージにシステムをアップグレードし、依存関係にあるパッケージも考慮します。sudo apt -y autoremove はもはやシステムに必要ではなくなったパッケージを自動的に削除します。

sudo apt -y update && sudo apt -y dist-upgrade && sudo apt -y autoremove

WireGuard VPNソフトウェアをインストールします。

sudo apt -y install wireguard

管理者権限に移行します。sudo iを使うべきだという人もいるでしょう。セキュリティはご自身で考慮ください。

sudo su

WireGuardのフォルダーに移動します。

cd /etc/wireguard

umask 077 を設定します。これにより、現在のシェルセッションで新しく作成されるファイルやディレクトリのアクセス権を設定します。rootのみが読み書きできる権限に設定しました。これでWireGuardの秘密鍵や設定ファイルは、他のユーザーからは操作できません。

umask 077

秘密鍵と公開鍵を生成します。

wg genkey | tee privatekey | wg pubkey > publickey

秘密鍵と公開鍵を表示します。あとで使うのでコピーしてペーストで使うので、適宜メモってください。サーバー側のprivatekey、サーバー側のpublickey、と表現することにします。

cat privatekey 
cat publickey

次は、/etc/sysctl.d/99-sysctl.confをnanoやvimなどで開いて、net.ipv4.ip_forward 行の先頭にあるコメントアウト(#)を削除します。以下sadコマンドで同じことをしています。

sed -i '/^#net\.ipv4\.ip_forward/s/^#//' /etc/sysctl.d/99-sysctl.conf

次に/etc/wireguard/wg0.confを書きます。nanoで開きます。nanoの使い方は説明しません。

nano /etc/wireguard/wg0.conf

以下の設定をペーストします。Addressなど適宜設定してください。WiregaredサーバのIPです。またPostUpとPostDownにて、NATルールに加えてFORWARDチェーンを使用したルールが使うことで、WireGuardインターフェースから受信したトラフィックを、他のインターフェース(この場合は eth0)を通じて転送(フォワーディング)することを許可します。つまり、VPNクライアントがサーバーを経由して他のネットワークへアクセスできるようになります。

eth0は実際に使っているネットワークインターフェースに書き換えてください。[Peer]は後ほど追加するクライアント側の設定です。ip aなどで使っているLANポートの名称(ネットワークインターフェース)を必ず確認してください。enp2s0など、PCによって結構違うことがあります。下記iptablesのeth0をその名称に書き換えてください。

[Interface]
Address = 10.1.0.1
ListenPort = 51820
PrivateKey = <サーバー側のprivatekey>
PostUp = iptables -A FORWARD -i %i -o eth0 -j ACCEPT; iptables -A FORWARD -i eth0 -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -o eth0 -j ACCEPT; iptables -D FORWARD -i eth0 -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
PublicKey = <クライアント側のpublickey>
AllowedIPs = 10.1.0.2/32

WireGuard VPNインターフェースwg0を起動し、設定ファイル(/etc/wireguard/wg0.conf)に基づいてVPN接続を確立します。インターフェースやiptablesルールが正しく設定されているか確認します。

wg-quick up wg0
ip addr show dev wg0
iptables -S

起動時に自動的に開始するように設定して確認します。

systemctl enable wg-quick@wg0
systemctl is-enabled wg-quick@wg0

/etc/sysctl.confファイル内のnet.ipv4.ip_forward=1行のコメントアウトを削除し、IPフォワーディングを有効にする設定のコメントを解除します。

sudo sed -i 's/^#\(net\.ipv4\.ip_forward=1\)/\1/' /etc/sysctl.conf
sudo sysctl -p

リブートしてWireGuardの状態を確認します。

reboot
sudo wg

実際の環境に合わせてufwなど適宜設定してください。ListenPort = 51820を使っているのでポートを許可するなど。この辺りは詳しく説明しません。実際の環境によってさまざまだからです。

sudo ufw allow 51820

次にクライアント側を準備します。ubuntuで準備もできますがWindowsが簡単なのでWindowsで準備します。WindowsのWireguardをインストールします。ubuntuで準備する場合はWireguardをインストールして、/etc/wireguard/wg0.confに以下設定を作ればOKなはずです。

https://www.wireguard.com/install/

トンネルの追加を選択して空のトンネルを追加します。そうするとクライアント側のprivatekey、クライアント側のpublickeyが得られます。以下は使わないのでそのまま公開していますが、公開してはいけない表示です。

例えば以下のように設定します。Address以下を追記します。

[Interface]
PrivateKey = <クライアント側のprivatekey>
Address = 10.1.0.2/32

[Peer]
PublicKey = <サーバー側のpublickey>
AllowedIPs = 10.1.0.0/24
Endpoint = <サーバー側のIP>:51820
PersistentKeepalive = 25

再びサーバー側に戻り、wg0.confファイルを開いて[Peer]にクライアントの設定を追加します。クライアント側のpublickeyを追加します。クライアントを増やす場合は[Peer]をどんどん追加すればOKです。

nano /etc/wireguard/wg0.conf
[Interface]
Address = 10.1.0.1
ListenPort = 51820
PrivateKey = <サーバー側のprivatekey>
PostUp = iptables -A FORWARD -i %i -o eth0 -j ACCEPT; iptables -A FORWARD -i eth0 -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -o eth0 -j ACCEPT; iptables -D FORWARD -i eth0 -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
PublicKey = <クライアント側のpublickey>
AllowedIPs = 10.1.0.2/32

Windows側でVPNを接続します。転送が少しでも受信の数値が出れば、成功です。ここが0だと何か間違っています。

ポートの開放、ポートフォワードの設定が必要になるので、つながらない場合はそれらの設定が上手くいっていないことが多いです。本記事で説明したいところですが、使っているルーターによって大いにことなることや、固定IPやAWSなどサーバー環境によっても大きく違うので適宜設定が必要です。

例えば家のルーターの場合は、NATエントリとして以下のような項目設定になります。51820ポートに来た通信は、192.168.10.203へ転送するよという設定です。

本記事でも、なぜかつながらず10時間ぐらい悩みました。その原因が以下です。

①PostUp PostDownの記述で、eth0としたものの、実際に使ったサーバーのネットワークインターフェースがeno1でした。

②ポート51820を51280としていた。意外と気が付かないミスです。

またWireGuardのサーバーを自宅に設置したのですが、なぜかローカルの機器からはVPN接続ができない現象が発生しました。これは同じ物理ネットワーク内のデバイスが、ネットワークの外部向けに公開されたIPアドレス(例えば、VPNサーバーの公開IP)を使用して、そのネットワーク内のサーバーにアクセスできないためです。

それらを解決するためにNATループバック(またはヘアピンNAT)をルーター側で設定するのですが、自宅のルーターにはそのような機能がありません。そのためhostsファイル(C:\Windows\System32\drivers\etc\hosts)に次のように設定して

192.168.10.21 myvpnserver.local

エンドポイントを以下に設定して直接WireGuardのサーバーに接続するようにしました。

Endpoint = myvpnserver.local:51820

無事繋がりました。でもよく考えたらhostsファイルを使わなくてもこのようにすればよいですね。

Endpoint = 192.168.10.21:51820

しかしこうすると、ローカルに接続した場合と、外のインターネットに接続した場合で毎回設定を変えなくてはいけません。とてもめんどくさい。そこで以下の対策をしたところ自動化できました。これがベストの方法とは思えませんがとりあえず自動で変更されます。

ユーザー名やフォルダーやファイルの位置は、ご自身の環境に合わせて調整してください。

sudo nano /home/riragon/wgchange.sh
#!/bin/bash

# 設定項目
LOCAL_IP="***********:51820"          # サーバーのローカルIPとポート
PUBLIC_IP="***********:51820"        # サーバーのパブリックIPとポート
WG_INTERFACE="wg0"                      # WireGuardインターフェース名
SERVER_PUB_KEY="***********+**********************************"  # サーバー側のpublickey

# ログファイルの設定
LOG_FILE="/var/log/wgchange.log"

# 現在の日時をログに記録
echo "$(date '+%Y-%m-%d %H:%M:%S') - スクリプト開始" >> $LOG_FILE

# ネットワーク内にルーターがいるか確認 # サーバーのローカルIPを***********に入れる
if ping -c 1 -W 1 *********** >/dev/null 2>&1; then
    # ローカルネットワーク内
    ENDPOINT=$LOCAL_IP
    echo "$(date '+%Y-%m-%d %H:%M:%S') - ローカルネットワークと判断。エンドポイントを $ENDPOINT に設定します。" >> $LOG_FILE
else
    # 外部ネットワーク
    ENDPOINT=$PUBLIC_IP
    echo "$(date '+%Y-%m-%d %H:%M:%S') - 外部ネットワークと判断。エンドポイントを $ENDPOINT に設定します。" >> $LOG_FILE
fi

# WireGuardの設定を変更
wg set $WG_INTERFACE peer $SERVER_PUB_KEY endpoint $ENDPOINT
if [ $? -eq 0 ]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') - WireGuardのエンドポイントを $ENDPOINT に設定しました。" >> $LOG_FILE
else
    echo "$(date '+%Y-%m-%d %H:%M:%S') - WireGuardのエンドポイント設定に失敗しました。" >> $LOG_FILE
    exit 1
fi

echo "$(date '+%Y-%m-%d %H:%M:%S') - スクリプト終了" >> $LOG_FILE

権限をあたえます。

sudo chmod +x /home/riragon/wgchange.sh

ログの権限を与えます。

sudo touch /var/log/wgchange.log 
sudo chmod 644 /var/log/wgchange.log 
sudo chown root:root /var/log/wgchange.log

サービス化します。

sudo nano /etc/systemd/system/wgchange.service

管理者権限で実行します。

[Unit]
Description=WireGuard Endpoint Change Service
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/home/riragon/wgchange.sh
RemainAfterExit=true

[Install]
WantedBy=multi-user.target

サービスの自動起動を設定します。

sudo systemctl daemon-reload
sudo systemctl enable wgchange.service
sudo systemctl start wgchange.service
sudo systemctl status wgchange.service

以下のようにローカル化どうかを判断して、エンドポイントを切り替えるスクリプトになります。

● wgchange.service – WireGuard Endpoint Change Service
Loaded: loaded (/etc/systemd/system/wgchange.service; enabled; vendor preset: enabled)
Active: active (exited) since Mon 2024-11-04 10:50:00 JST; 1s ago
Process: 12345 ExecStart=/home/riragon/wgchange.sh (code=exited, status=0/SUCCESS)
Main PID: 12345 (code=exited, status=0/SUCCESS)

2024-11-04 10:50:00 – スクリプト開始
2024-11-04 10:50:00 – ローカルネットワークと判断。エンドポイントを 192.168.10.203:51820 に設定します。
2024-11-04 10:50:00 – WireGuardのエンドポイントを 192.168.10.203:51820 に設定しました。
2024-11-04 10:50:00 – スクリプト終了

という感じで自動的にIPを判別して、エンドポイントを切り替えるスクリプトです。

これが良いかというと微妙な気もします。トラブルが起きたときに原因が分かりにくくなりそう。