WireGuard(ワイヤーガード)は、公開鍵を交換したピア同士をUDPで結ぶVPNプロトコルです。2020年3月リリースのLinux 5.6でカーネルに統合され、Windows・macOS・Android・iOS向けの公式クライアントもあります。この記事では、暗号とハンドシェイクの仕組み、料金とライセンス、Linuxでの設定手順、スマートフォンとWindowsのアプリ、OpenVPN・IPsecとの違いを順に説明します。後半では、検証環境に2台のピアを作り「繋がらない」状態を4通り再現した結果をもとに、wg show の表示から原因を絞り込む方法を示します。
まとめ:WireGuardの要点
- WireGuardはNoise_IKpsk2を土台にしたVPNプロトコルで、暗号はCurve25519・ChaCha20Poly1305・BLAKE2sなどに固定されている。暗号方式を選ぶ設定はない。
- 料金は無料。Linuxカーネル実装とwireguard-toolsはGPLv2、wireguard-go・Windows・iOS/macOS版はMIT、Android版はApache 2.0で公開されている。
- 設定は鍵ペアを作り、wg0.confに自分の秘密鍵・トンネル内アドレスと相手の公開鍵・AllowedIPsを書いて
wg-quick up wg0を実行するだけ。 - ハンドシェイクは開始148バイト・応答92バイトの1往復。送信時に鍵が120秒より古くなっていれば、開始側が鍵を作り直す。
- 通信はUDPのみでTCPは使えない。ユーザー認証やIPアドレスの自動割り当ても持たないため、多人数ならTailscaleなどの管理層と組み合わせる。
- 繋がらないときは、pingなどで通信を発生させてから
wg showの latest handshake が更新されるかを見る。更新されなければ鍵・PresharedKey・UDPの到達性、更新されるのに通信できなければAllowedIPs・ルーティング・MTUの順に疑う。
以下、仕組み・料金・設定手順・アプリ・比較・制約・切り分けの順に根拠を示します。
WireGuardとは:開発の経緯と料金・ライセンス
WireGuardはJason A. Donenfeld氏が開発したVPNプロトコルと、その実装群の名前です。使う暗号を1組に固定し、設定項目を鍵とアドレスと経路に絞っています。
Linux 5.6への統合とWireGuard 1.0.0
Linus Torvalds氏がLinux 5.6のリリースを告知したのは2020年3月29日(LWNに転載された告知)で、翌30日に開発者がWireGuard 1.0.0のリリースをメーリングリストで告知しました。5.6以降のカーネルならモジュールが同梱されているので、追加のカーネルパッチは要りません。
よく引かれる「約4,000行」は統合前の論文の数字です。2026年10月18日時点のLinux本体(7.3-rc7)の drivers/net/wireguard は、自己テストと自動生成コードを除いて6,071行、空行とコメント行を除くと約4,650行でした(暗号プリミティブの lib/crypto は含まない)。
料金は無料:実装ごとのライセンス
WireGuard自体に利用料はかかりません。費用が出るのはサーバーにするVPSの代金か、WireGuardを使う商用VPNサービスの月額です。製品に組み込むときは実装ごとのライセンスが効いてきます。
| 実装 | 用途 | ライセンス |
|---|---|---|
| Linuxカーネル実装 | Linux 5.6以降のモジュール | GPLv2 |
| wireguard-tools | wg・wg-quick | GPLv2 |
| wireguard-go | ユーザー空間実装 | MIT |
| wireguard-windows | Windowsクライアント | MIT |
| wireguard-apple | iOS・macOSクライアント | MIT |
| wireguard-android | Androidクライアント | Apache 2.0 |
各リポジトリのCOPYINGで確認しました(例:wireguard-androidのCOPYING)。なお「WireGuard」の名称とロゴはDonenfeld氏の登録商標で、製品名に使うときは商標ポリシーに従う必要があります。
対応OSと公式クライアントの現行版
2026年10月19日時点で確認した公式クライアントの最新版は次のとおりです。iOS・macOS版は2023年2月の1.0.16から更新が止まっていますが、App Storeで配布は続いています。
| 対象 | 最新版 | 日付 |
|---|---|---|
| wireguard-tools(Linux・macOS等) | v1.0.20260223 | 2026-02-23 |
| Windows | 1.1.1 | 2026-09-20 |
| Android | 1.0.20260315 | 2026-03-15 |
| iOS・macOS | 1.0.16 | 2023-02 |
Windows版は2021年12月の0.5.3のあと、2026年4月18日に1.0、5月7日に1.1、9月20日に1.1.1のタグが付きました(wireguard-windowsのリポジトリ)。Linuxはディストリビューションのパッケージが最新タグより遅れることがあり、検証に使ったAlpine 3.22のパッケージは v1.0.20250521 でした。
WireGuardの仕組み:暗号・ハンドシェイク・ローミング
Noise_IKpsk2と固定された暗号
公式のプロトコル解説によると、ハンドシェイクはNoise Protocol FrameworkのIKpsk2パターンで組まれ、次の暗号を使います。wireguard-goのソースでも、構成名は Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s と1つの文字列で埋め込まれています。
- 鍵交換:Curve25519(ECDH)
- 暗号化と改ざん検知:ChaCha20Poly1305(RFC 7539のAEAD)
- ハッシュと鍵付きハッシュ:BLAKE2s
- 鍵導出:HKDF(RFC 5869)
- ハッシュテーブルの鍵:SipHash24
暗号の交渉が無いので、弱い暗号へのダウングレード攻撃は起こりません。代わりに暗号を設定で差し替えることはできず、破られたらプロトコルの版を上げて対応します。
148バイトと92バイトの1往復と送信時の再鍵条件
接続を始める側は148バイトのハンドシェイク開始メッセージを送り、相手は92バイトの応答を返します。これで双方がセッション鍵を導出し、データ送信が始まります。wireguard-goの device/constants.go に定義されたタイマーは次のとおりで、論文の値と一致します。
| 定数 | 値 | 意味 |
|---|---|---|
| RekeyAfterTime | 120秒 | 送信時に鍵がこれより古ければ再鍵 |
| RejectAfterTime | 180秒 | これより古い鍵のパケットは捨てる |
| RekeyAttemptTime | 90秒 | ハンドシェイクを再試行し続ける上限 |
| RekeyTimeout | 5秒 | 応答が無いときの再送の基準間隔 |
| KeepaliveTimeout | 10秒 | 受信後に返す空パケットの待ち時間 |
| RekeyAfterMessages | 2の60乗 | この通数でも鍵を作り直す |
再鍵は時計で一律に起きるのではなく、開始側がパケットを送ろうとした時点で鍵が120秒より古ければ行われます。通信が無い間はハンドシェイクも起きません。再送はRekeyTimeoutの5秒に最大334ミリ秒の揺らぎを足した間隔です(wireguard-goの device/timers.go)。セッション鍵を使い捨てるので、長期の秘密鍵が後から漏れても過去の通信は復号できません(前方秘匿性)。検証では、UDPを遮断していたサーバーの遮断を外して6秒後に打ったpingが通りました。再送の間隔そのものは測っていません。
UDPのみ・送信元が変わっても追従するローミング
WireGuardのパケットはすべてUDPで運ばれ、公式の既知の制約にあるとおりTCPには対応しません。各ピアは、認証と復号に成功した最新パケットの送信元IPアドレスとポートを、次の送信先として使います。
検証でクライアント側の送信元ポートを35141から40000へ変えたところ、サーバー側の wg show wg0 endpoints は1回のpingで 172.30.0.3:40000 に書き換わりました。Wi-Fiとモバイル回線を切り替えても張り直しが要らず、サーバー側にクライアントの Endpoint を書かなくてよいのはこの仕組みのためです。
WireGuardの使い方:Linuxでのサーバーとクライアントの設定手順
ここではLinuxのサーバー1台とクライアント1台を、トンネル内アドレス 10.8.0.0/24 で結ぶ最小構成を作ります。ポートはwg(8)マニュアルの例と同じ51820/UDPにします。ListenPortは省略するとランダムに決まるので、待ち受ける側だけ固定すれば足ります。
OS別のwireguard-toolsのインストール
# Ubuntu / Debian
sudo apt install wireguard-tools
# Fedora / RHEL系
sudo dnf install wireguard-tools
# Alpine
sudo apk add wireguard-tools
# macOS(Homebrew)
brew install wireguard-tools
WireGuardの鍵ペアの生成
サーバーとクライアントのそれぞれで秘密鍵と公開鍵を作ります。公開鍵はBase64で44文字です。
umask 077
wg genkey | tee privatekey | wg pubkey > publickey
umaskを077にしておくと、作られるファイルは所有者しか読めません。wg genkey > privatekey のように通常ファイルへ直接書き出したときに限り、他のユーザーが読める権限だとwgが「Warning: writing to world accessible file.」と警告します。上の例のようにteeへパイプで渡す場合は警告が出ないので、ls -l privatekey で権限が -rw——- になっているかを自分で確かめます。他人に読まれた可能性がある鍵は作り直し、相手側に登録した公開鍵も差し替えます。相手に渡すのは公開鍵だけです。
サーバー側wg0.confの設定
# /etc/wireguard/wg0.conf(サーバー)
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = サーバーの秘密鍵
[Peer]
PublicKey = クライアントの公開鍵
AllowedIPs = 10.8.0.2/32
AllowedIPsは2つの働きを兼ねます。送るときは「この宛先はこのピアへ」という経路表に、受け取るときは「このピアから来てよい送信元」というフィルターになります。サーバー側ではクライアント1台につき /32 を1つ割り当てるのが基本です。範囲の書き方はCIDRとは?表記の読み方と計算方法・サブネット設計とAWS VPCでの使い方を実装者向けに解説で確認できます。
クライアント側wg0.confの設定
# /etc/wireguard/wg0.conf(クライアント)
[Interface]
Address = 10.8.0.2/24
PrivateKey = クライアントの秘密鍵
# DNS = トンネル内で応答するDNSサーバーのアドレス(用意した場合のみ)
[Peer]
PublicKey = サーバーの公開鍵
Endpoint = サーバーのグローバルIP:51820
AllowedIPs = 10.8.0.0/24
PersistentKeepalive = 25
AllowedIPsを 10.8.0.0/24 にするとVPN内の通信だけがトンネルを通ります。IPv4の通信をすべて通すなら 0.0.0.0/0、IPv6も通すなら ::/0 を並べて書きます。PersistentKeepaliveは、NATの内側のクライアントが、サーバー側から先に届く通信(クライアントへの接続やサーバーからのping)を受ける必要があるときに付けます。25秒は公式Quick Startが挙げる値で、ルーターのNAT対応表が消える前に空パケットを送ります。既定は0(無効)です。DNS行を書く場合、wg-quickは resolvconf コマンドを呼び出してDNSを登録します。検証でresolvconfを外して起動すると「resolvconf: command not found」で止まり、wg-quickは作りかけのwg0を削除しました(終了コード127)。DNS行を使うなら、openresolvなどresolvconf互換のコマンドがあるかを先に確かめてください。
wg-quickでの起動とwg showでの接続確認
次のコマンドはUbuntu(UFWとsystemdを使う環境)の例です。IP転送は、クライアントの通信をサーバーの先のLANやインターネットへ中継する場合だけ必要で、VPN内の10.8.0.0/24同士で通信するだけなら要りません。
sudo ufw allow 51820/udp
sudo sysctl -w net.ipv4.ip_forward=1
sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0 # 再起動後も自動で上げる
検証環境(colima上のUbuntuカーネル6.8.0、Alpine 3.22のコンテナ2台)でクライアントを上げたときの出力です。MTUを指定しなくても、wg-quickが外側の経路のMTU 1500から80を引いた1420を設定しています。80は外側のIPv6ヘッダー・UDPヘッダー・WireGuardのヘッダーと認証タグの合計です。
[#] ip link add dev wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.8.0.2/24 dev wg0
[#] ip link set mtu 1420 up dev wg0
PersistentKeepaliveを付けたクライアントは、pingを打つ前の時点でハンドシェイクを済ませていました。サーバー側の wg show には、設定に書いていないクライアントの送信元が endpoint として現れます。
peer: ZTLdai47J2N6zC+643nx8GGfed5udyq2RK6O6T1cNVc=
endpoint: 172.30.0.3:40718
allowed ips: 10.8.0.2/32
latest handshake: Now
transfer: 180 B received, 92 B sent
送信の92バイトはハンドシェイク応答そのものです。latest handshake は過去に成功した時刻なので、その後の遮断までは保証しません。pingなどを打った直後に「Now」や数秒前へ更新されていれば、その時点で鍵とUDPの到達性は確認できます。経路の途中でMTUが1500より小さい回線(PPPoEなど)では、1420でも大きすぎて大きなパケットだけが落ちることがあります。その見分け方はMTUとは?最大転送単位の仕組み・1500とジャンボフレーム・PMTUD/MSS調整と測定手順を実装者向けに解説にまとめています。
Android・iOS・WindowsのWireGuardアプリの設定
Android・iOS:QRコードでの設定の取り込み
スマートフォンでは公式アプリ「WireGuard」を入れ、サーバー側で作ったクライアント設定を読み込みます。アプリの画面にも出てくる方法は、設定ファイルをQRコードにして端末のカメラで読む手順です。QRコードにはクライアントの秘密鍵がそのまま入るので、画面の撮影や共有は秘密鍵を渡すのと同じです。読み取ったら表示を消してください。
qrencode -t ansiutf8 < client.conf
あわせてサーバーのwg0.confに、スマートフォンの公開鍵とトンネル内アドレス(例:10.8.0.3/32)を [Peer] として追記し、sudo bash -c 'wg syncconf wg0 <(wg-quick strip wg0)' で反映します。プロセス置換の中の wg-quick strip もroot権限で動かす必要があるので、全体をsudoで起動したbashに渡します。syncconfは既存のピアの接続を切らずに差分だけを適用します。
Android版のソースで確かめた機能は次のとおりです。最低対応はAPIレベル24(Android 7.0)です。
- アプリ単位の除外と「指定アプリだけ通す」設定
- Android本体の「常時接続VPN」からの起動
- クイック設定タイルでのオンとオフ
- 端末起動時に、前回有効だったトンネルを戻す設定
- root化端末でのカーネル実装の利用(使えなければroot不要のユーザー空間実装で動く)
Windows:トンネルのサービス化と設定の暗号化保存
Windows版は公式サイトのインストーラーで入れ、.confファイルを取り込むか画面で新規作成します。設定は %ProgramFiles%\WireGuard\Data\Configurations\ にDPAPIで暗号化した .conf.dpapi として保存されます。このフォルダへ平文の .conf を置くと、マネージャーが暗号化して元のファイルを削除するので、配布スクリプトからの追加にも使えます。
トンネルを有効にすると、サービス名 WireGuardTunnel$トンネル名、表示名「WireGuard Tunnel: トンネル名」のWindowsサービスが作られます。このサービスはトンネルを有効にしている間だけ存在し、無効にすると削除されます。サービス一覧で見かける「WireGuard Tunnel」はこれです。画面を使わずに配布するときは、企業向けの説明にある次のコマンドを管理者権限で実行します。
wireguard /installtunnelservice C:\path\to\wg0.conf
wireguard /uninstalltunnelservice wg0
WireGuardとOpenVPN・IPsecの違い
| 項目 | WireGuard | OpenVPN | IPsec(IKEv2) |
|---|---|---|---|
| 外側の通信 | UDPのみ | UDPかTCP | IKEはUDP、データはESP |
| 暗号の交渉 | なし(固定) | TLSで交渉 | IKEで交渉 |
| ハンドシェイク | 1往復 | TLSの往復 | IKE_SA_INIT等で2往復 |
| 認証の単位 | 公開鍵のみ | 証明書・ID/パスワード | 証明書・PSK・EAP |
| アドレス割り当て | 手動 | サーバーから配布 | サーバーから配布 |
| 回線切り替え | 送信元を自動追従 | floatの設定で追従 | MOBIKEで対応 |
速度については、公式の性能ページ自身が、掲載しているベンチマークはLinux 4.6.1時代の古いもので、その後WireGuardとIPsecはどちらも速くなったと注記しています。同ページの評価は「WireGuardはマルチスレッドのおかげで場合によってIPsecをやや上回り、OpenVPNは非常に遅いまま」です。数倍の差を断言する記事は古い計測を引いていることが多いので、自分の回線とCPUで iperf3 を回して確かめてください。
UDPが通らない社外ネットワークから443/TCPで入る必要があるならOpenVPN。相手が既存のルーターやクラウドのVPNゲートウェイならIPsecです。AWS・Azure・Google Cloudの拠点間接続用マネージドVPNはIPsecしか受け付けないので、クラウドとの拠点間接続はSite-to-Site VPNとは?3クラウドのIKE既定値とstrongSwan接続手順の方式になります。自前のサーバーや端末同士を少ない設定でつなぐならWireGuardが向きます。
WireGuardのデメリットと公式が挙げる制約
公式の既知の制約ページから、導入前に知っておくべき点を挙げます。
- TCPで使えない:UDPを止めるネットワークでは通らない。udp2rawのFakeTCPモードはTCPヘッダーを付けた擬似通信で、本物のTCP接続ではないため、プロキシ経由でしか外に出られない環境は通せない。
- 通信を偽装しない:WireGuardのパケットは見ればそれと分かり、DPIによる遮断を避ける機能は無い。
- ユーザー認証とアドレス配布が無い:公開鍵1つが1台を表す。退職者の鍵の失効や、端末ごとのアドレス管理は自分で行う。
- 時刻に依存する:ハンドシェイクのリプレイ対策にシステム時刻を使う。時刻が過去へ戻るとハンドシェイクができなくなるため、RTCが無い機器ではNTPの同期を先に済ませる。
- 量子計算機への耐性は標準では無い:PresharedKeyを追加すると、その分の耐性が上乗せされる。
PresharedKeyは wg genpsk で作り、両側の [Peer] に同じ値を書きます。検証で片側だけに入れたところ、クライアントは148バイトの開始メッセージを送り続けるだけで、受信は0バイトのまま接続できませんでした。
利用者の入社・退職で鍵の追加と失効が日常的に起きる、端末ごとに通してよい宛先を変えたい、ログイン履歴を残したい、といった要件があるなら、素のWireGuardに鍵とアドレスの台帳を手で持たせる運用では追いつきません。管理画面を足すなら wg-easy(v15.4.0・AGPL-3.0)や wg-portal(v2.3.1・MIT)、IDプロバイダーでのログインやNAT越えまで任せるなら、WireGuardを土台にしたTailscaleが選択肢です。Tailscaleの調整サーバーを自前で持ちたい場合はheadscaleがあります。
逆に、外部に公開したいのが1つのWebアプリだけなら、ネットワークごとつなぐWireGuardは過剰です。ポート開放なしで公開できるCloudflare Tunnelの方が設定は少なく済みます。社内システムとクラウドを含めたネットワーク全体の設計は、インフラ構築(AWS・Google Cloud・Azure)の支援でもご相談いただけます。
WireGuardが繋がらないときの切り分け(wg showの表示別)
WireGuardは認証に失敗したパケットに返事をしないため、「繋がらない」の見た目はどれも同じです。そこで検証環境で4つの失敗を再現し、wg show の表示を記録しました。AllowedIPsの不一致はサーバー側のピア表示、それ以外はクライアント側のピア表示です。鍵の誤り・UDP遮断・PresharedKeyの試験では、クライアントのトンネルかピアの登録を作り直してハンドシェイク履歴を消してから測っています。すでに動いていた接続が途中で切れた場合は、latest handshake に古い時刻が残ったまま更新されない形で現れます。
| 再現した原因 | latest handshake | transfer | ping |
|---|---|---|---|
| 正常 | 表示あり | 送受信あり | 成功 |
| サーバー側AllowedIPsの不一致 | 表示あり | 送受信あり | 失敗 |
| 相手の公開鍵の誤り | 行が出ない | 受信0 B・送信148 Bの倍数 | 失敗 |
| サーバーでUDP 51820を遮断 | 行が出ない | 受信0 B・送信148 Bの倍数 | 失敗 |
| PresharedKeyを片側だけ設定 | 行が出ない | 受信0 B・送信148 Bの倍数 | 失敗 |
表から、確認の順番が決まります。
- 通信を発生させても latest handshake が出ない・更新されない:鍵・PresharedKey・UDPの到達性のどれか。クライアント側の表示だけでは3つを区別できません。サーバーで
sudo tcpdump -ni any udp port 51820を実行し、パケットが届いていなければファイアウォールやクラウドのセキュリティグループ、届いていれば鍵とPresharedKeyを疑います。 - latest handshake は更新されるのにpingが通らない:まずAllowedIPsを見ます。サーバー側の [Peer] のAllowedIPsにクライアントのトンネル内アドレスが入っていないと、届いたパケットは送信元の検査で捨てられます。AllowedIPsが正しければ、相手ホストのファイアウォール(ICMPの拒否)や、トンネル内アドレスへの経路の重複を確認します。
- pingは通るがWebが開けない:全通信を流しているならサーバーのIP転送とNAT(MASQUERADE)、名前解決ができないならクライアントのDNS行を確認します。
- 小さな通信だけ通り、大きなファイルやHTTPSが止まる:MTUです。wg0.confに
MTU = 1380などと書いて下げてみます。
ログを見るなら、カーネル実装はroot権限で echo module wireguard +p > /sys/kernel/debug/dynamic_debug/control を実行して dmesg を読み、wireguard-goは LOG_LEVEL=verbose を付けて起動します(Quick Startに記載)。
よくある質問
WireGuardの料金はいくらですか?
無料です。オープンソースで商用利用にもライセンス料はかからず、かかるのはサーバーにするVPSなどの費用か、WireGuardを使う商用VPNサービスの料金です。
WireGuardのポート番号は何番ですか?
決まった番号はありません。公式マニュアルの例が51820/UDPなので、それが慣例として広まっています。ListenPortを省略するとランダムなポートで待ち受けるため、接続を受ける側だけ番号を固定し、そのUDPポートを開けます。
Windowsの「WireGuard Tunnel」とは何ですか?
Windows版WireGuardがトンネルごとに作るサービスの表示名です。「WireGuard Tunnel: トンネル名」として登録され、サービス名は WireGuardTunnel$トンネル名 になります。トンネルを有効にすると作られ、無効にすると削除されます。
AndroidでWireGuardを使うにはどうすればよいですか?
Google Playで公式アプリ「WireGuard」を入れ、クライアント設定をQRコードかファイルで取り込みます。対応はAndroid 7.0以降です。
WireGuardはTCPで使えますか?
使えません。TCPの中にTCPを通すと再送が二重に起きて遅くなるため、公式は意図的にUDPだけにしています。UDPだけを止めるファイアウォールなら udp2raw のFakeTCPモードで通せることがありますが、本物のTCP接続やHTTPプロキシが必須の環境では、TCPで動くOpenVPNを選びます。