0. 前置き
TCP でポートを使用したトンネリングなら Linux や Windows に搭載されている ssh コマンドで簡単に実現できますが、
ICMP や UDP の場合は VPN を構築する必要があります。
昔の VPN というと、自ノードのインタフェースがすべて VPN に属してしまい、VPN 以外の通信ができなくなることがよくありましたが、これでは使い勝手がよくありません。
今は、一時的に別の LAN を自ノードに取り付けるように VPN を運用することができます。
ガチガチに VPN でしか動作しないノードは珍しい存在になっています。
本稿は WireGuard を使用した VPN の構築について記述します。
Linux ⇔ Windows の VPN です。Linux ⇔ Linux の VPN ならもう少し簡単に構築できます。
WireGuard は技術的に高速かつセキュアな VPN ですが、ユーザ管理という概念がありません。
このため、組織で運用するには注意が必要です。
動作環境
(WireGuard にサーバ / クライアントの区別はありませんが、運用の便宜上サーバ / クライアントという言葉を使用しています)
項目 内容 備考 サーバ OS AlmaLinux release 10.0 (Purple Lion) 本稿記述時の最新版 IP アドレス 192.168.11.20 NIC に割り振られたアドレス IP アドレス (仮想) 10.10.0.1 VPN で使用するアドレス VPN ソフト WireGuard 1.0.0 WireGuard は Alma10 に組み込まれている
追加するのは wireguard-tools疎通確認ソフト socat 1.7.4.1 dnf でインストールできる最新版 クライアント 基本ソフト Windows11 Pro 24H2 - IP アドレス 192.168.11.40 NIC に割り振られたアドレス IP アドレス (仮想) 10.10.0.2 VPN で使用するアドレス VPN ソフト wireguard-amd64-0.5.3 本稿記述時の最新版 疎通確認ソフト Packet Sender 8.9.1 VPN 名前 SampleVPN 設定を保存する名称 ポート (サーバ) 51820/UDP 51820/UDP は WireGuard の標準ポート
他のポートは使用しないポート (クライアント) 動的/UDP -
1. WireGuard のインストール (Linux)
1-1. WireGuard をインストールする。
$ su1-2. サーバの設定をする。
# dnf install -y wireguard-tools
# which wg wg-quick
# wg --version
/bin/wg /bin/wg-quick
# modinfo wireguard | head | fold
wireguard-tools v1.0.20210914 - https://git.zx2c4.com/wireguard-tools/
filename: /lib/modules/6.12.0-55.40.1.el10_0.x86_64/kernel/drivers/net/wir eguard/wireguard.ko.xz alias: net-pf-16-proto-16-family-wireguard alias: rtnl-link-wireguard version: 1.0.0 author: Jason A. Donenfeld <Jason@zx2c4.com> description: WireGuard secure network tunnel license: GPL v2 rhelversion: 10.0 srcversion: 6FC1E1261D4D834B105C922 depends: udp_tunnel,ip6_udp_tunnel,curve25519-x86_64,libcurve25519-generi c
# cd /etc/wireguard1-3. 仮想インタフェースの起動と確認をする。
/etc/wireguard/# umask 077 # <- これをしないと wg コマンドから警告が出る。
/etc/wireguard/# wg genkey > privatekey
/etc/wireguard/# cat privatekey | wg pubkey > publickey
/etc/wireguard/# chmod 644 publickey
/etc/wireguard/# cat > wg0.conf << EOF
[Interface]
Address = 10.10.0.1/24
ListenPort = 51820
PrivateKey = `cat ./privatekey`
EOF
/etc/wireguard/# ls -l
/etc/wireguard/# cat wg0.conf
合計 8 -rw-------. 1 root root 45 10月 27 20:32 privatekey ← 秘密鍵 -rw-r--r--. 1 root root 45 10月 27 20:33 publickey ← 公開鍵 (クライアントへ渡す) -rw-------. 1 root root 130 10月 27 20:43 wg0.conf
[Interface] Address = 10.10.0.1/24 ← WireGuard が使う仮想インタフェースの IP アドレス ListenPort = 51820 ← WireGuard のデフォルトポート (待ち受け) PrivateKey = PrivateKeyb3smPa3yJoHwdDPnEDnUNEWfHZtUOoMjU= ← `cat …` で取り込んだ秘密鍵
/etc/wireguard/# systemctl start wg-quick@wg01-4. トンネリング用ポートを許可する。
/etc/wireguard/# systemctl enable wg-quick@wg0
/etc/wireguard/# wg show
/etc/wireguard/# ip a show wg0 | fold
interface: wg0 public key: PublicKeyZ38z6BgLv0rtF+InPHHzbqWeaWYfLCz9L0= ← ./publickey の内容と同じ private key: (hidden) listening port: 51820
/etc/wireguard/# ping -c 4 10.10.0.1
6: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN gro up default qlen 1000 link/none inet 10.10.0.1/24 scope global wg0 valid_lft forever preferred_lft forever
PING 10.10.0.1 (10.10.0.1) 56(84) バイトのデータ 64 バイト応答 送信元 10.10.0.1: icmp_seq=1 ttl=64 時間=0.032ミリ秒 64 バイト応答 送信元 10.10.0.1: icmp_seq=2 ttl=64 時間=0.046ミリ秒 64 バイト応答 送信元 10.10.0.1: icmp_seq=3 ttl=64 時間=0.058ミリ秒 64 バイト応答 送信元 10.10.0.1: icmp_seq=4 ttl=64 時間=0.074ミリ秒 --- 10.10.0.1 ping 統計 --- 送信パケット数 4, 受信パケット数 4, 0% packet loss, time 3079ms rtt min/avg/max/mdev = 0.032/0.052/0.074/0.015
/etc/wireguard/# firewall-cmd --permanent --add-port="51820/udp"
/etc/wireguard/# firewall-cmd --reload
/etc/wireguard/# firewall-cmd --list-ports
/etc/wireguard/# exit
51820/udp
$
2. WireGuard のインストール (Windows)
2-1. インストーラをダウンロード&実行する。
ここから Windows 版のインストーラをダウンロードする。2-2. トンネル (VPN クライアント) を設定する。
今回は wireguard-amd64-0.5.3.msi だった。
wireguard-installer.exe は起動すると本体のダウンロードが開始される。
UAC が表示される。
ボタンをクリックする。
⇓
インストールが終了し、いきなり設定画面が表示される。
↓ インストールフォルダはここ。
%ProgramFiles%\WireGuard\
トンネルの追加 の から を選択する。
⇓
公開鍵ペア (秘密鍵 / 公開鍵) が自動的に生成される
以下を記入し ボタンをクリックする。
項目 内容 備考 名前(N): SampleVPN 当該ノードのトンネル名 Address = 10.10.0.2/24 当該ノードの IP アドレス [Peer] 接続する WireGuard サーバの定義開始 PublicKey = PublicKeyZ38z…Cz9L0= 上記 1-3 の wg show で確認した public key: の内容 AllowedIPs = 10.10.0.0/24 取り扱うネットワーク範囲 Endpoint = 192.168.11.20:51820 WireGuard サーバの IP アドレスと UDP ポート番号
⇓
公開鍵が確定する。
この公開鍵を使用して当該ノードを WireGuard サーバに登録する。(→ 3-1)
公開鍵の登録が完了しないと接続できない。
(有効化は出来るが、接続したことにならない)
3. クライアントの登録
WireGuard サーバで作業する
3-1. WireGuard の定義ファイルにクライアント情報を追加する。
$ su3-2. WireGuard を再起動する。
# vim /etc/wireguard/wg0.conf
[Peer] セクションは、接続するクライアントの数だけ定義する。
[Interface] Address = 10.10.0.1/24 ListenPort = 51820 PrivateKey = PrivateKeyb3smPa3yJoHwdDPnEDnUNEWfHZtUOoMjU= [Peer] PublicKey = 6/QCOnvN9b7EoloMD6ydaN0o2LTZmyLAX/3GHu27YCo= # 上記 2-2 で確定した公開鍵 AllowedIPs = 10.10.0.2/32 # 10.10.0.2 への送信経路は当該 Peer を使う
# systemctl restart wg-quick@wg0
# exit
$
4. クライアントから接続
4-1. 上記 2 で用意した WireGuard クライアントを起動する。(Windows)
Microsoft Defender でポート開放を設定する必要はない。4-2. トンネルを有効化する。
4-3. トンネルの有効化を確認する。作成したトンネルを選択して
ボタンをクリックする。
4-4. おまけ : 無効化 (切断) する場合。ピア (WireGuard サーバ) のペインが以下であることを確認する。
• 項目 直前のハンドシェイク: が存在すること。
• 項目 転送: の「受信済み」が 0 のままでないこと。
トンネルを無効化し VPN から切り離すには
ボタンをクリックする。
5. 疎通確認
上記 1 ~ 4 の作業により、以下のネットワークが形成されている。
サーバ
Linux192.168.11.20 10.10.0.1 WireGuard
← LAN → ← VPN →
クライアント
Windows11192.168.11.40 WireGuard 10.10.0.2
5-1. 疎通確認(1) サーバ ← ping クライアント
クライアント (Windows) で作業する。5-2. 疎通確認(2) サーバ ping → クライアント
− □ × >_ Windows PowerShell × + | ∨
Windows PowerShell Copyright (C) Microsoft Corporation. All rights reserved. 新機能と改善のために最新の PowerShell をインストールしてください!https://aka.ms/PSWindows PS C:\> # 通常の疎通確認 PS C:\> ping 10.10.0.1 ⏎ 10.10.0.1 に ping を送信しています 32 バイトのデータ: 10.10.0.1 からの応答: バイト数 =32 時間 =2ms TTL=64 10.10.0.1 からの応答: バイト数 =32 時間 =1ms TTL=64 10.10.0.1 からの応答: バイト数 =32 時間 =36ms TTL=64 10.10.0.1 からの応答: バイト数 =32 時間 =1ms TTL=64 10.10.0.1 の ping 統計: パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、 ラウンド トリップの概算時間 (ミリ秒): 最小 = 1ms、最大 = 36ms、平均 = 10ms PS C:\> exit ⏎
サーバ (Linux) で作業する。5-3. 疎通確認(3) サーバ ← UDP クライアント
$ ping -c 4 10.10.0.2
PING 10.10.0.2 (10.10.0.2) 56(84) バイトのデータ 64 バイト応答 送信元 10.10.0.2: icmp_seq=1 ttl=128 時間=35.8ミリ秒 64 バイト応答 送信元 10.10.0.2: icmp_seq=2 ttl=128 時間=1.35ミリ秒 64 バイト応答 送信元 10.10.0.2: icmp_seq=3 ttl=128 時間=1.14ミリ秒 64 バイト応答 送信元 10.10.0.2: icmp_seq=4 ttl=128 時間=34.6ミリ秒 --- 10.10.0.2 ping 統計 --- 送信パケット数 4, 受信パケット数 4, 0% packet loss, time 3005ms rtt min/avg/max/mdev = 1.137/18.218/35.814/16.980 ms
5-3-1. 簡易 UDP サーバを動作させる。(Linux)5-4. 疎通確認(4) サーバ UDP → クライアント
$ socat -v UDP4-LISTEN:10013,fork SYSTEM:'date +UDP\:\\ %Y-%m-%d\\ %H\:%M\:%S'
ログが表示されるが、今回はあまり関係ない。
< 2025/11/01 20:17:00.000297953 length=25 from=0 to=24 UDP: 2025-11-01 20:17:00
5-3-2. UDP の疎通を確認する。(Windows の Packet Sender)
サーバの仮想 IP アドレスに向けて空の UDP パケットを送信し、
UDP パケットの受信を確認する。(ここでは現在時刻)
5-4-1. 簡易 UDP サーバを動作させる。(Windows の PowerShell)5-5. 疎通確認(5) サーバ ← TCP クライアント
中止する場合は を打鍵する。
待ち受けをループにしていないので、1 回の応答で終了する。
− □ × >_ Windows PowerShell × + | ∨
Windows PowerShell Copyright (C) Microsoft Corporation. All rights reserved. 新機能と改善のために最新の PowerShell をインストールしてください!https://aka.ms/PSWindows PS C:\> # UDP で daytime サーバを起動する PS C:\> @' $u = New-Object Net.Sockets.UdpClient(10013) $ep = New-Object Net.IPEndPoint([Net.IPAddress]::Any,0) $u.Receive([ref]$ep) # UDP 受信 (受信データは破棄) $msg = [System.Text.Encoding]::UTF8.GetBytes((Get-Date).ToString() + "`n") $u.Send($msg, $msg.Length, $ep) # 日時を返す '@ | powershell -NoLogo ⏎ PS C:\> exit ⏎
5-4-2. UDP の疎通を確認する。(Linux)
$ echo | socat - UDP4:10.10.0.2:10013
2025/11/01 20:18:14 ← 上記 簡易 UDP サーバからの応答
5-5-1. 簡易 TCP サーバを動作させる。(Linux)5-6. 疎通確認(6) サーバ TCP → クライアント
$ socat -v TCP4-LISTEN:10013,fork SYSTEM:'date +TCP\:\\ %Y-%m-%d\\ %H\:%M\:%S'
ログが表示されるが、今回はあまり関係ない。
< 2025/11/01 20:19:43.000761578 length=25 from=0 to=24 TCP: 2025-11-01 20:19:43
5-5-2. TCP の疎通を確認する。(Windows の Packet Sender)
サーバの仮想 IP アドレスに向けて空の TCP 接続を行い、
応答を確認する。(ここでは現在時刻)
5-6-1. 簡易 TCP サーバを動作させる。(Windows の PowerShell)
中止する場合は を打鍵する。
待ち受けをループにしていないので、1 回の応答で終了する。
− □ × >_ Windows PowerShell × + | ∨
Windows PowerShell Copyright (C) Microsoft Corporation. All rights reserved. 新機能と改善のために最新の PowerShell をインストールしてください!https://aka.ms/PSWindows PS C:\> # TCP で daytime サーバを起動する PS C:\> @' $listener = [Net.Sockets.TcpListener]10013 $listener.Start() $client = $listener.AcceptTcpClient() # 接続待ち $s = $client.GetStream() $msg = [System.Text.Encoding]::UTF8.GetBytes((Get-Date).ToString() + "`n") $s.Write($msg, 0, $msg.Length) # 日時を返す $client.Close() $listener.Stop() '@ | powershell -NoLogo ⏎ PS C:\> exit ⏎
5-6-2. TCP の疎通を確認する。(Linux)
$ echo | socat - TCP4:10.10.0.2:10013
2025/11/01 22:24:35 ← 上記 簡易 TCP サーバからの応答