WireGuardで自宅LANに接続できない時の設定確認手順
WireGuardのハンドシェイクは成功するのに自宅LAN内のホストへ通信できない原因を解説します。AllowedIPsの設定、IP転送の有効化、戻りルートの確保など、パケットが到達するために必須となる4つの設定項目を順を追って確認する方法をまとめました。
WireGuard 経由で自宅 LAN に接続できない理由
WireGuard 経由で自宅 LAN にルーティングするには、4 つの個別の設定が整合している必要があります。3 つが正しくてもトンネルは正常に見えるため、この問題の切り分けは困難です。wg show は直近のハンドシェイクを報告し、ping 10.8.0.1 は数ミリ秒で応答し、ping 192.168.20.10 は何も返しません。
パケットが通過する順序でリストを以下に示します。LAN とは、自宅ルーターの背後にあるプライベートネットワークを指します。
- クライアント側の
AllowedIPsがリモートサブネットをカバーしている必要があります。そうでない場合、パケットはトンネルに入りません。 - サーバー側の
AllowedIPsがクライアントのトンネルアドレスをカバーしている必要があります。そうでない場合、パケットは復号された直後に破棄されます。 - サーバー側で
net.ipv4.ip_forwardが1に設定されている必要があります。Linux は自分宛てではないパケットを破棄するためです。 - LAN 側が
10.8.0.0/24への戻りルートを知っている必要があります。サーバー上のマスカレードルール、または自宅ルーターの静的ルートで設定します。
これらのいずれかが欠けていてもエラーメッセージは表示されません。ログにも記録されず警告も出ませんが、ハンドシェイクは正常に機能し続けます。この順序で確認すれば、約 1 分で問題箇所が特定できます。
本ガイドで使用するネットワーク
以下の各アドレスは例です。自身の環境に合わせて置き換えてください。設定の更新漏れは、この種の問題で2番目に多い原因となるため、一貫性を保つことが重要です。
- ホームLANは
192.168.20.0/24です。ホームルーターは192.168.20.1です。 - WireGuardサーバーは、そのLAN上のLinuxマシンです。LANインターフェース
enp1s0には192.168.20.5が割り当てられ、トンネルインターフェースwg0には10.8.0.1が割り当てられています。 - アクセス対象のホストは、
192.168.20.10にあるNAS(ネットワーク接続ストレージ)です。 - クライアントは外部にあるラップトップで、トンネル内では
10.8.0.2となります。
サーバーはルーターそのものではなく、LAN上のマシンです。これはRaspberry Piや古いミニPCなど、一般的な構成です。これはルール4において重要です。ルーターに伝えない限り、ルーターはトンネルの存在を認識できません。また、LAN上のすべてのホストは、サブネット外へのトラフィックをそのルーターへ送信します。
自宅の回線にパブリックIPアドレスがない場合、インターネット側から自宅へのハンドシェイクを開始できないため、この構成単体では動作しません。その場合は、中継役としてVPSを配置するセクションを参照してください。その場合も同じ4つのルールが適用されますが、ピアが1つ増えるため注意が必要です。
AllowedIPs は2つの異なる意味を持ちます
1つの設定が2つの役割を担っており、両端で同じように解釈してしまうことが、多くの問い合わせの原因となっています。WireGuard はこの仕組みを cryptokey routing と呼んでおり、詳細は WireGuard が公開鍵と IP レンジを紐付ける仕組み で説明されています。
送信側として読む場合、AllowedIPs はルーティングテーブルです。 wg-quick は各エントリを wg0 へのルートに変換します。192.168.20.10 宛てのパケットは、そのアドレスを含むレンジを主張するピアが存在する場合にのみ、暗号化されてそのピアへ送信されます。10.8.0.0/24 のみを指定すると、ラップトップは LAN トラフィックをローカルの Wi-Fi 経由で送信してしまい、そこで破棄されるか、全く別の 192.168.20.10 に到達することになります。
受信側として読む場合、AllowedIPs はアクセス制御リストです。 WireGuard がピアからのパケットを復号した後、内部の送信元アドレスをそのピアの AllowedIPs と照合し、一致しない場合はパケットを破棄します。この破棄に関するログやカウンタは存在しません。パケットは単に消失します。
したがって、2つの設定ファイルが鏡合わせになることはありません。クライアントはサーバー経由で到達したい範囲をリストし、サーバーはそのクライアントが送信元アドレスとして使用を許可されている範囲をリストします。
対となる設定ファイル
クライアント側、/etc/wireguard/wg0.conf:
[Interface]
PrivateKey = <laptop private key>
Address = 10.8.0.2/32
[Peer]
PublicKey = <server public key>
Endpoint = home.example.com:51820
AllowedIPs = 10.8.0.0/24, 192.168.20.0/24
PersistentKeepalive = 25サーバー側、/etc/wireguard/wg0.conf:
[Interface]
PrivateKey = <server private key>
Address = 10.8.0.1/24
ListenPort = 51820
[Peer]
PublicKey = <laptop public key>
AllowedIPs = 10.8.0.2/32ホームルーターでも UDP 51820 ポートを 192.168.20.5 へ転送する設定が必要です。これを行わないとハンドシェイクが開始されず、クライアントのログに Handshake for peer 1 did not complete after 5 seconds, retrying が記録されます。本ガイドでは、その段階を完了していることを前提とします。
通常のフルトンネル構成から変更している箇所は4点あり、それぞれ意図があります。
- クライアント側の
AllowedIPs = 10.8.0.0/24, 192.168.20.0/24。0.0.0.0/0, ::/0の代わりに使用します。これはスプリットトンネルです。トンネルサブネットとホーム LAN への通信のみがwg0を経由し、それ以外の通信はローカルのルーティングを維持します。NAS へのアクセスのみが必要な場合、Web ブラウジングまで自宅回線を経由させないのが一般的です。 - サーバー側の
AllowedIPs = 10.8.0.2/32。範囲指定ではなく単一のアドレスを指定します。ここに10.8.0.0/24と記述すると、そのクライアントがトンネル内の任意のアドレスを詐称できるようになります。重複する範囲を持つ2つ目のピアを追加すると、エラーも表示されずに、最後に設定されたピアへトラフィックが流れるようになります。 - クライアント側のみの
PersistentKeepalive = 25。クライアントは NAT (ネットワークアドレス変換) の背後に存在します。ルーターは通信がないと1〜2分で UDP のマッピングを破棄するため、サーバーからクライアントへ到達できなくなります。サーバーはパブリックアドレスを持つため、keepalive は不要です。 DNS =行はまだ追加しません。これを追加すると、クライアントマシン全体の名前解決が変更されます。有効にする前に何が起こるかは、以下の DNS セクションで解説します。
フルトンネルでも 0.0.0.0/0 がすべてのアドレスに一致するため、LAN への到達は可能です。ただし、すべてのトラフィックが消費されるほか、クライアント側からは修正不可能なサブネットの競合が発生します。
両端で同じサブネットを使用すると接続が失敗する理由
192.168.20.0/24 や 10.44.7.0/24 のように、他ではほとんど使われないホームサブネットを選択してください。192.168.1.0/24 および 192.168.0.0/24 は多くの家庭用ルーターの工場出荷時設定であるため、カフェやホテルのネットワークに接続した際、ノートPCが偶然同じ範囲のIPアドレスを取得してしまう事態が遅かれ早かれ発生します。
この衝突は致命的な問題であり、状況によって現れる現象が異なります。スプリットトンネルの場合、wg-quick はWi-Fiインターフェース上に既に存在するプレフィックスに対してルートを追加しようとしますが、ip route add がこれを拒否するため、インターフェースの起動に失敗します。
RTNETLINK answers: File existsフルトンネルの場合、wg-quick はメインテーブルから特定のルートを意図的に除外するポリシーベースルーティングルールをインストールします。ローカルの 192.168.1.0/24 ルートがトンネルよりも優先されるため、リモートLAN宛てのすべてのパケットはローカルリンク経由で送信されてしまいます。トンネルは確立され、ハンドシェイクも正常に行われますが、NASには到達できません。ホームLANのIPアドレス体系を再設計することが、唯一の根本的な解決策です。
サーバーをルーター化する
ip route show default
printf 'net.ipv4.ip_forward = 1\n' | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system
sysctl net.ipv4.ip_forward最初のコマンドで、LANインターフェースの正確な名前を確認します。現在のイメージでは enp1s0 や ens3 といった名前が使われ、eth0 は稀です。マスカレードルールで誤ったインターフェースを指定すると、どのパケットも一致しません。最後のコマンドを実行すると net.ipv4.ip_forward = 1 と表示されるはずです。単に sudo sysctl -w を実行しても同じ値を設定できますが、再起動後に設定が消えてしまいます。これが「火曜日までは動いていた」という典型的なトラブル報告の原因です。
パケット転送はファイアウォールを通過させる必要もあります。Ubuntuで ufw が有効な場合、/etc/default/ufw 内で DEFAULT_FORWARD_POLICY="ACCEPT" が設定されていない限り、転送パケットは破棄されます。Dockerは独自に同様のポリシーを設定するため、手動でファイアウォールを設定していない環境でも sudo iptables -S FORWARD | head -1 が -P FORWARD DROP を出力する場合は、Dockerが設定を行ったことを意味します。その場合、トンネルトラフィックには明示的な許可ルールが必要です。
なぜ応答が戻ってこないのか
ルール 1 から 3 を正しく設定すれば、ping は確かに NAS に到達します。それでも応答がないのは、戻り先への経路がないためです。NAS は 10.8.0.2 という自身のサブネット外のアドレスに応答しようとするため、パケットをデフォルトゲートウェイである 192.168.20.1 のホームルーターに渡します。そのルーターは 10.8.0.0/24 について知らないため、応答をさらに自身のデフォルトゲートウェイであるインターネット接続先へ転送し、そこで破棄されます。リクエストは届いても、応答は捨てられているのです。
オプション A: WireGuard サーバーでのマスカレード
サーバーは、転送されるすべてのパケットの送信元アドレスを、自身の LAN アドレスである 192.168.20.5 に書き換えます。NAS から見ると、リクエストは同じサブネット内の隣接ホストから来たように見えるため、サーバーへ直接応答を返します。サーバーは書き換えを元に戻し、トンネル経由でクライアントへ送り返します。LAN 内の他の設定を変更する必要はありません。
このルールをサーバーの [Interface] ブロックに記述し、インターフェースの有効化に合わせてルールが適用されるようにします。
PostUp = iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o enp1s0 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o enp1s0 -j MASQUERADEすでに nftables で管理されている環境では、代わりに /etc/nftables.conf に記述します。
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 10.8.0.0/24 oifname "enp1s0" counter masquerade
}
}counter キーワードは残してください。これがないと、sudo nft list ruleset はパケットカウントを表示しません。このカウントこそが、ルールが実際に使用されているかを確認する唯一の手段です。
マスカレードには、見落としがちな利点がもう一つあります。多くのホストは、自身のサブネットからの接続のみを許可するファイアウォールを実行しています。Windows のファイル共有や、多くの NAS 管理パネルがデフォルトでこの挙動をとります。10.8.0.2 からのパケットは、ルーティングが完璧であってもターゲットホストによって破棄されます。マスカレード後は送信元が LAN アドレスになるため、これらのルールに合致するようになります。代償として、LAN 内のすべてのホストのログにおいて、すべてのトンネルクライアントが 192.168.20.5 として記録されます。そのため、クライアントを個別に識別できず、LAN デバイス側でのクライアントごとのルール設定も機能しません。
オプション B: ホームルーターでのスタティックルート
ルーターに対し、10.8.0.0/24 は 192.168.20.5 の背後に存在することを伝えます。Linux ルーターであれば、以下のコマンド 1 つで済みます。
sudo ip route add 10.8.0.0/24 via 192.168.20.5一般的なルーターでは、詳細設定内の「スタティックルート」または「ルーティング」というページから設定します。宛先を 10.8.0.0、マスクを 255.255.255.0、ゲートウェイを 192.168.20.5 に指定します。Linux マシンで実行した ip route add は再起動で消えてしまうため、必ずルーターの保存済み設定として保存してください。
この方法であれば、実際のクライアントアドレスが維持されるため、LAN 内のログやクライアントごとのルール設定が有効に機能します。ただし、スタティックルートをサポートするルーターが必要であり、そのルーターをデフォルトゲートウェイとして使用しているホストにしか効果がありません。サブネット限定のローカルファイアウォールを持つホストについては、依然として 10.8.0.0/24 向けのルールを個別に設定する必要があります。まずは管理下のサーバーだけで完結するマスカレードから始め、実際のクライアントアドレスが必要になった段階でスタティックルートへ移行することをお勧めします。
4 つの要素のうち、どこに問題があるかを確認する方法
クライアント側から外側に向かって順に確認します。各ステップで、パケットがどこまで到達しているかを特定できます。
パケットはトンネルに入っていますか? クライアント上で以下を実行します。
ip route get 192.168.20.10出力には dev wg0 が表示されるはずです。Wi-Fi インターフェース名が表示される場合、ルール 1 が誤っており、クライアントの AllowedIPs が LAN サブネットをカバーしていません。ping: connect: Network is unreachable でも同じ行が示されます。
パケットはサーバーに到達していますか? サーバー上で以下を実行し、クライアントから NAS へ ping を送信します。
sudo tcpdump -ni wg0 icmp正常な経路であれば IP 10.8.0.2 > 192.168.20.10: ICMP echo request が表示されます。ICMP はインターネット制御メッセージプロトコルであり、ping が使用するものです。ハンドシェイクが正常であるにもかかわらず何も表示されない場合、ルール 2 が原因です。サーバー側のそのピアに対する AllowedIPs に 10.8.0.2 が含まれていないため、wg0 に到達する前に復号段階でパケットが破棄されています。
パケットは LAN 側へ送信されていますか? サーバー上で LAN 側を監視します。
sudo tcpdump -ni enp1s0 icmpwg0 でリクエストが確認できるのにここには表示されない場合、ルール 3 が原因です。IP フォワーディングが無効であるか、FORWARD ルールによってパケットが破棄されています。ここでソース 10.8.0.2 のリクエストは見えるが応答がない場合、ルール 4 が原因です。戻りの経路が存在しません。ここでソース 192.168.20.5 のリクエストが見えるが応答がない場合、マスカレードルールは機能しており、ターゲットホスト自体が拒否しています。NAS のファイアウォールを確認してください。icmp を port 445 やその他の対象ポートに置き換えれば、他の通信でも同様の手順で切り分けが可能です。
IPアドレスには到達できるがホスト名では到達できない
ssh 192.168.20.10 は動作し、ssh nas.home.arpa は失敗します。
ssh: Could not resolve hostname nas.home.arpa: Name or service not knownトンネル自体に問題はありません。名前解決は別の経路で行われるため、ラップトップは依然としてローカルのWi-Fiから取得したリゾルバに問い合わせています。そのリゾルバは、自宅ネットワーク内のホスト名を知りません。
自宅のホスト名で解決するには、2つの条件を満たす必要があります。まず、リゾルバのアドレスがクライアント上の AllowedIPs 内に含まれていること。さもなければ、DNS(ドメインネームシステム)クエリがトンネル内に入りません。次に、リゾルバが 10.8.0.2 を送信元とするクエリに応答する設定になっていることです。多くの家庭用リゾルバはデフォルトでこれを拒否します。dnsmasq を local-service で実行すると、直接接続されたサブネットからのクエリのみに応答します。また、Pi-hole はデフォルトでローカルからのリクエストのみを許可するリスニングモードで出荷されています。マスカレードルールを使用すると、書き換え後のクエリが 192.168.20.5 から送信されたように見えるため、この問題が隠蔽されます。
クライアント側の設定は1行です。
DNS = 192.168.20.1openresolv または同等の機能が必要なLinuxクライアントでは、これを行わないと wg-quick が resolvconf: command not found で停止します。systemd-resolved を使用しているマシンで設定を行う前に、その動作を理解してください。wg-quick は指定したサーバーを排他的に登録するため、トンネルが有効な間は、自宅のホスト名だけでなく、ラップトップ上のすべての名前解決が自宅のリゾルバへ送信されます。結果は resolvectl status wg0 で確認してください。自宅のホスト名のみを自宅で解決し、それ以外はローカルで解決するスプリットDNSを希望する場合は、WireGuardトンネル経由のDNS設定で詳細な構成を確認してください。
自宅にグローバルIPがない場合、VPSを中継する
ルーターのステータス画面でWANアドレスが 100.64.0.0/10 やプライベートな 192.168.x.x アドレスになっている場合、CGNAT(キャリアグレードNAT)配下にあり、インターネットからのハンドシェイクは自宅に到達できません。発信方向のハンドシェイクは通常通り機能するため、解決策はパブリックアドレスを持つ第3のノードを介することです。小型のVPSをハブとして稼働させ、自宅のボックスからそこへ接続します。
4つのルールに変更はありません。ただし、2ホップにまたがるため、管理項目は倍になります。
- VPS側では、自宅ボックスのピア設定に
AllowedIPs = 10.8.0.3/32, 192.168.20.0/24を記述します。これには自身のトンネルアドレスと、通信を許可するサブネットを含めます。 - VPS側では、ラップトップのピア設定は
AllowedIPs = 10.8.0.2/32のままです。 - ラップトップ側では、VPSのピア設定を
AllowedIPs = 10.8.0.0/24, 192.168.20.0/24にします。すべての通信がハブを経由するためです。 - 自宅ボックス側では、VPSのピア設定を
AllowedIPs = 10.8.0.0/24にし、PersistentKeepalive = 25を設定します。NAT配下にあるのはこちら側だからです。 - VPSには
net.ipv4.ip_forward = 1も必要です。また、そのforwardチェーンでwg0からwg0への通信を許可する必要があります。ラップトップからのトラフィックが同じインターフェースで到着し、出ていくためです。単純なフルトンネルVPS用に書かれたファイアウォール設定では、まさにこの通信がブロックされます。
VPS側の構築がまだの場合は、VPSでのWireGuardセットアップで鍵生成、ファイアウォール、systemdユニットの設定を確認してください。着信接続を受け入れられないマシンにアクセスするより広範なパターンについては、CGNAT配下からのリバーストンネル開設を参照してください。ピアアドレスの手動管理が煩雑になった場合は、Tailscaleサブネットルーターの運用を行うことで、アドレス管理を自動化しつつ同様のルーティングを実現できます。
再起動後も設定を維持する
sudo systemctl enable --now wg-quick@wg0
sudo systemctl enable --now nftables
sudo wg showenable --now は、多くの人が見落とす重要な手順です。手動で実行した wg-quick up wg0 は、カーネルのアップグレードや再起動後に消滅します。wg show を実行した際、最近の latest handshake 行が表示され、双方向の転送カウンタがゼロ以外であることを確認してください。
後から2台目のクライアントを追加する場合、再起動は不要です。再起動を行うと、現在接続中のすべてのセッションが切断されてしまいます。
sudo bash -c 'wg syncconf wg0 <(wg-quick strip wg0)'wg-quick strip は、wg-quick だけが解釈できるキー情報を除いた設定を表示します。syncconf を使用すると、ライブセッションを維持したまま差分を適用できます。これはピアのみを更新します。Address の変更や新しい PostUp 行の追加には、依然として完全な down と up の操作が必要です。
FAQ
WireGuard サーバーには ping が通るのに、自宅 LAN 内の他の機器には繋がりません。なぜですか?
10.8.0.1 への ping は、トンネルが確立していることしか証明しません。LAN 内の他の機器への通信はルーティングの問題です。クライアントの AllowedIPs に 192.168.20.0/24 が含まれていないと、パケットはトンネルに入りません。サーバー側で net.ipv4.ip_forward を 1 に設定していない場合、サーバー自身宛てではないパケットは破棄されます。また、LAN 側には 10.8.0.0/24 への戻りルートが必要です。ping を実行しながらサーバーで sudo tcpdump -ni enp1s0 icmp を実行してください。10.8.0.2 を送信元とするリクエストが出ていても応答がない場合、戻りの経路が不足しています。
自宅のルーターに静的ルートを設定する必要がありますか?
マスカレードルールを省略する場合のみ必要です。WireGuard サーバー上のマスカレードルールは、トンネルトラフィックの送信元アドレスをサーバー自身の LAN アドレスに書き換えます。これにより、LAN 内のホストは既知の隣接機器からの通信として応答するため、ルーターの設定は不要です。別の方法として、サーバーの LAN アドレスを経由する 10.8.0.0/24 への静的ルートを設定することも可能です。LAN 内のホストのログにクライアントの本来のアドレスを残したい場合や、クライアントごとにファイアウォールルールを適用したい場合には、この設定を行う価値があります。
両端で同じサブネットを使用するとトンネルが機能しないのはなぜですか?
ノート PC は同一プレフィックスに対して 2 つのルートを保持できません。ローカルネットワークが 192.168.1.0/24 を割り当てており、自宅 LAN も 192.168.1.0/24 である場合、ip route add が RTNETLINK answers: File exists を返すとスプリットトンネルの wg-quick up は失敗します。代わりにフルトンネルが確立されますが、wg-quick がメインテーブルからより詳細なルートを除外するポリシーを適用するため、ローカルネットワークが優先され、リモートの LAN には到達できなくなります。自宅 LAN を 192.168.20.0/24 のような珍しいネットワークアドレスに変更してください。クライアント側での修正は不可能です。
IP アドレスでは NAS に到達できますが、ホスト名では到達できません。何が足りないのでしょうか?
名前解決は自動的にはトンネルを通りません。クライアントの [Interface] ブロックに自宅の DNS リゾルバーである DNS = 192.168.20.1 を追加し、そのアドレスがピアの AllowedIPs に含まれていることを確認してください。含まれていない場合、クエリはトンネルに入りません。また、リゾルバーが自身のサブネット外からのクエリに応答するように設定されているか確認してください。dnsmasq と local-service の組み合わせや、Pi-hole のローカルのみを待ち受けるモードでは、外部からのクエリが拒否されます。WireGuard サーバー上でマスカレードルールを設定し、クエリの送信元アドレスを書き換えることでこの問題を回避できます。
自宅の回線にグローバル IP アドレスがありません。それでも LAN にアクセスできますか?
はい、第 3 のノードを使用すれば可能です。CGNAT 環境下ではルーターの WAN アドレスがプライベート IP であるため、インターネット上のピアからハンドシェイクを開始できませんが、外向きのハンドシェイクは通常通り機能します。グローバルアドレスを持つ VPS 上で WireGuard を実行し、自宅の機器から PersistentKeepalive = 25 を使用して VPS へ接続します。VPS 側のピア設定には、トンネルアドレスと 192.168.20.0/24 を含む AllowedIPs を指定します。VPS 側で転送を有効にし、wg0 から wg0 への通信を許可する転送ルールを設定してください。