SSD Nodes Learn メモリ 8GB — 年額 $66
ガイド Matt Connor著者 Matt Connor ・更新日 2026-08-01

WireGuardのDNSが使えない3つの原因と対処法

WireGuardのトンネルは接続済みなのに名前解決できない、DNSクエリがローカルルーターへ漏れる、設定が数秒で上書きされる3つの原因を切り分けて直します。

WireGuard トンネルを起動すると DNS が直ちに機能しなくなる理由

WireGuard 経由の DNS は3つの形で失敗し、それぞれに個別の対処が必要です。名前解決がまったくできない場合、名前解決はできてもクエリがトンネルの外部から送信される場合、またはインターフェースの起動後数秒でクライアント自身のリゾルバーマネージャーが設定を上書きする場合があります。ほとんどの場合、問題はトンネルではありません。問題は、クライアントが問い合わせるリゾルバーを指定する1行と、そのリゾルバーへのパケット経路を決めるルーティングです。

WireGuard は IP パケットを転送しますが、DNS(example.com などの名前を IP アドレスに変換するドメインネームシステム)については認識しません。クライアントの [Interface] ブロックにある DNS = 行は、WireGuard の設定ではありません。この行は、インターフェースを起動するシェルラッパーである wg-quick が読み取り、wg-quick がトンネルの稼働中にクライアントのリゾルバー設定を変更し、wg-quick down で元に戻します。したがって、以下の問題はすべてルーティングまたは wg-quick の問題であり、暗号化の問題ではありません。まだトンネルを構築していない場合は、自分の VPS で WireGuard VPN をセルフホストする方法から始め、その後このページに戻ってください。

DNS を変更する前に、トンネルが正常に動作していることを確認してください。

sudo wg show
ping -c 3 10.8.0.1
ping -c 3 1.1.1.1

wg show には、最新の latest handshake を持つピアが表示され、両方の ping に応答があるはずです。ping 1.1.1.1 がタイムアウトする場合は、DNS ではなくフォワーディングまたは NAT(ネットワークアドレス変換)の問題です。リゾルバー設定をどれだけ変更しても解決しません。ここでのすべての例では、トンネルのサブネットに 10.8.0.0/24、サーバーのトンネルアドレスに 10.8.0.1 を使用しています。環境に合わせて置き換えてください。

失敗その1: リゾルバーが応答しないため、何も解決できない

症状は明確です。ping 1.1.1.1 は動作しますが、curl https://example.com は次を返します。

curl: (6) Could not resolve host: example.com

クライアントからトンネルのリゾルバーに直接問い合わせます。dig は Ubuntu と Debian の dnsutils パッケージに含まれています。

dig +short @1.1.1.1 example.com
dig +short @10.8.0.1 example.com

最初のコマンドがアドレスを返す場合、パケットがトンネル経由でインターネットに到達していることが確認できます。2つ目のコマンドは何も返さず、;; communication timed out; no servers could be reached と表示します。診断結果はこれで確定です。クライアントは 10.8.0.1 を参照するよう設定されていますが、10.8.0.1 は UDP port 53 で応答していません。

原因は2つあります。サーバーでリゾルバーが実行されていないか、サーバーのファイアウォールがクエリを到達前に破棄しています。サーバーで両方を確認します。

sudo ss -ulnp | grep ':53'
sudo nft list ruleset

正しく起動してバインドされているリゾルバーは、10.8.0.1:53 または 0.0.0.0:53 を含む行を表示します。Ubuntu では、通常 127.0.0.53:53 が原因です。これは systemd-resolved の stub listener で、loopback アドレスにバインドされ、他のマシンからは意図的に到達できません。唯一のリゾルバーがこの stub listener であるサーバーを VPN クライアントに指定すると、まさにこのタイムアウトが発生します。

トンネルアドレスで待ち受けるリゾルバーを用意し、ピアからのアクセスを許可するファイアウォールルールを1つ追加します。

sudo apt update && sudo apt install -y unbound
printf 'server:\n  interface: 10.8.0.1\n  access-control: 10.8.0.0/24 allow\n' \
  | sudo tee /etc/unbound/unbound.conf.d/wireguard.conf
sudo systemctl restart unbound
sudo ss -ulnp | grep '10.8.0.1:53'

次に、トンネルのトラフィックだけに対してポートを開きます。nftables では、/etc/nftables.confinput chain に次の2行を追加し、sudo systemctl reload nftables で再読み込みします。

udp dport 53 iifname "wg0" accept
tcp dport 53 iifname "wg0" accept

ufw では、sudo ufw allow in on wg0 to any port 53 が同じ役割を果たします。port 53 をパブリックインターネットに公開しないでください。公開された再帰リゾルバーは数日以内にスキャナーに発見され、DoS 攻撃の増幅に悪用されます。プロバイダーは、そのトラフィックをあなたより先に検知します。

クライアントから dig +short @10.8.0.1 example.com を再実行します。出力にアドレスが含まれていれば、リゾルバーへの経路は機能しています。あとはクライアントがそのリゾルバーを使用するよう設定します。クライアントの [Interface] block にその行を追加し、sudo wg-quick down wg0 && sudo wg-quick up wg0 でインターフェイスを再起動します。

[Interface]
PrivateKey = <client private key>
Address = 10.8.0.2/32
DNS = 10.8.0.1

失敗その2: split tunnel は resolver への経路を設定しないため、DNS が漏れます

これはさらに問題です。すべて正常に動作しているように見えるためです。名前解決もページの読み込みも成功します。しかし、クエリは信頼したくないローカルネットワーク上を平文で通過します。

2つの設定が原因になります。1つ目は、AllowedIPs = 0.0.0.0/0, ::/0 が設定されているクライアントに DNS = 行がない場合です。wg-quick は独自の routing table に default route を設定し、suppress_prefixlength 0 を使った rule を追加します。これは、マシンがプリンターに接続できるように、より具体的なローカル経路を意図的に維持します。クライアントが DHCP から取得した resolver は、通常 192.168.1.1 の router ですが、これらのローカル経路の1つに一致します。ネットワークトラフィックは tunnel を通ります。しかし、ローカルネットワークには、検索した名前の完全な一覧が引き続き届きます。

2つ目は、AllowedIPs = 10.8.0.0/24DNS = 9.9.9.9 を使った split tunnel です。9.9.9.9AllowedIPs の内側にないため、クライアントには tunnel 経由でそこへ到達する route がありません。そのため、最初のケースと同じように、クエリはローカルリンクから送信されます。

実際に応答している resolver を確認します。whoami.akamai.net は、問い合わせを行った recursive resolver の IP address を返す public test name です。そのため、応答をサーバーの public address と比較できます。

resolvectl status
dig +short whoami.akamai.net
sudo tcpdump -ni any -c 10 port 53

resolvectl status は、link ごとに1つのブロックを出力します。ethernet または wireless link のブロックに Current DNS Server: 192.168.1.1 が残っていて、wg0 のブロックに何も表示されない場合、それが漏洩です。dig +short whoami.akamai.net がサーバーの address ではなく、自宅の broadband address を返すことでも、相手側から漏洩を確認できます。tcpdump 行は、議論を決着させる証拠です。正常な出力では、port 53 のすべてのパケットが wg0 を通ります。漏洩時は wlan0 または enp3s0 を通ります。

修正には2つの作業が必要で、両方とも必須です。DNS を tunnel 内に存在する address に設定し、その address が AllowedIPs の内側にあることを確認します。

[Interface]
Address = 10.8.0.2/32
DNS = 10.8.0.1

[Peer]
PublicKey = <server public key>
Endpoint = vpn.example.com:51820
AllowedIPs = 10.8.0.0/24, 10.20.0.0/16

10.8.0.110.8.0.0/24 の内側にあるため、クエリは暗号化されてサーバーに送信されます。split tunnel で public resolver を使う場合は、host route として追加します: AllowedIPs = 10.8.0.0/24, 9.9.9.9/32。これでパケットは tunnel を通ります。ただし、以前のセッションから、ローカルネットワークにはその provider を選択したことが分かる可能性があります。自分で運用する resolver を使えば、この問題を避けられます。

resolver の割り当ては、手動で構築した WireGuard と coordinated mesh の違いの1つです。これは、WireGuard と Tailscale の比較 におけるトレードオフの一部です。self-hosted Headscale control server を実行すると、key material を第三者に渡さずに、その coordination を利用できます。

失敗例3: Linuxクライアントでresolvconfとsystemd-resolvedが競合する

macOS、Windows、iOS、Androidのクライアントは公式アプリを通じてDNS =を適用するため、問題はほとんど発生しません。Linuxでは、複数あるリゾルバーマネージャーのうち、どれを使用しているかをシェルスクリプトが推測して設定を適用します。

最初の失敗は明確です。sudo wg-quick up wg0は次のエラーで停止します。

resolvconf: command not found

wg-quickresolvconfを呼び出しますが、そのバイナリがインストールされていません。systemd-resolvedと通信する実装をインストールしてから、インターフェースを再度起動します。

sudo apt install -y openresolv
sudo systemctl restart systemd-resolved
sudo wg-quick down wg0 && sudo wg-quick up wg0
resolvectl status wg0

2つ目の失敗は気付きにくく、数時間を失う原因になります。インターフェースは起動し、resolvectl status wg0は正しくDNS Servers: 10.8.0.1を表示しますが、名前解決は以前のリゾルバーに送られます。systemd-resolvedはリンクごとに別のリゾルバー一覧を保持し、クエリごとに使用するリンクを選択します。名前解決のデフォルトルートとして1つのリンクをマークしない限り、検索ドメインを持つ無線リンクのリゾルバーを使い続けます。使用中のリンクには検索ドメインがないためです。

同じ手順でリゾルバーを設定し、デフォルトルートを指定します。%iはインターフェース名に展開されるため、このブロックはどのインターフェースでもそのまま使用できます。

[Interface]
Address = 10.8.0.2/32
PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~.
PostDown = resolvectl revert %i

この方法でPostUpを使用する場合は、DNS =の行を削除します。そうしないと、2つの仕組みがリゾルバーの状態を書き込み、後処理を行うのはそのうち1つだけになります。~.引数が重要です。これはwg0をすべての名前のルーティングドメインとして指定します。そのため、systemd-resolvedはクエリごとにリンクを選択せず、すべてのクエリをそこへ送ります。確認します。

resolvectl status wg0

正常な出力にはDNS Servers: 10.8.0.1Default Route: yesが含まれます。Default Routenoを読み取る場合、resolvectl domainの処理が実行されていません。その場合は、リンク選択に戻っています。

もう1つ確認すべきケースがあります。/etc/resolv.conf/run/systemd/resolve/stub-resolv.confへのシンボリックリンクではなく実体ファイルの場合、通常はNetworkManagerまたはコンテナランタイムなど、別のソフトウェアがそのファイルを管理しています。他の調査を始める前にls -l /etc/resolv.confを実行してください。ネットワーク変更のたびにそのファイルを書き換えるツールがあると、最も都合の悪いタイミングで設定が元に戻るためです。

トンネル経由で独自のフィルタリングリゾルバーを構築する

クエリが確実にトンネルを通るようになると、接続先のリゾルバーが制御ポイントになります。そこに AdGuard Home を実行すると、クライアントソフトウェアやデバイスごとの設定なしで、接続されたすべてのデバイスにブロックリストによるフィルタリングとクエリログを提供できます。2026年7月に確認した公式インストールスクリプトは1行です。

curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v

初回起動時、セットアップウィザードはポート3000で待ち受けます。そのポートをインターネットに公開する代わりに、トンネル経由で http://10.8.0.1:3000 にアクセスしてください。ウィザードでは、DNSの待ち受けアドレスと管理画面の待ち受けアドレスの両方を 10.8.0.1 に設定します。最初の障害の unbound がまだ同じアドレスを使用している場合は、まず sudo systemctl disable --now unbound で停止してください。1つのアドレスでUDPポート53に2つのプロセスをバインドすることはできず、後から起動したプロセスは listen udp 10.8.0.1:53: bind: address already in use で終了するためです。

クライアント設定がすでに DNS = 10.8.0.1 になっている場合、変更は不要です。これでクエリログにすべてのピアからのすべての名前解決が表示されます。これは無条件の利点ではなく、実際のプライバシー上の判断です。信頼先をインターネットプロバイダーから自分自身に移すことになり、そのサーバーにパッチを適用し続ける責任も自分にあります。インターネットに公開するサーバーでは、まず基本的な対策を整える必要があります。新しいVPSで最初の10分間に行う作業で説明しています。

FAQ

WireGuard トンネルは接続しますが、名前を解決できないのはなぜですか?

トンネルはパケットを転送しますが、名前は処理しません。そのため、トンネルが機能しているのに名前解決に失敗する場合は、指定したリゾルバーが応答していません。クライアントで dig +short @10.8.0.1 example.com を実行してテストします。communication timed out の応答は、通常、トンネルのアドレスで待ち受けているリゾルバーがないことを示します。systemd-resolved のスタブが 127.0.0.53 のみで待ち受けている場合や、サーバーのファイアウォールが wg0 から到着する UDP port 53 を破棄している場合に発生します。まず待ち受け設定を修正し、その後、wg0 のみに対して port を開放します。

WireGuard 経由で DNS が漏れているかどうかを確認するにはどうすればよいですか?

クライアントで sudo tcpdump -ni any -c 10 port 53 を実行し、ブラウジング中に interface 列を監視します。すべてのパケットが wg0 上にある必要があります。wireless または ethernet interface に表示される場合、クエリが平文で送信されています。dig +short whoami.akamai.net でも確認できます。これはクエリを受けた recursive resolver の public address を返すため、サーバーの address 以外が返れば、漏洩していることが確認できます。

split tunnel を使用する場合、DNS = 行は必要ですか?

はい。resolver address も AllowedIPs 内に含まれている必要があります。含まれていない場合、クライアントはその address への route を持ちません。AllowedIPs = 10.8.0.0/24 では、10.8.0.1 の resolver が対象になり、クエリは暗号化されます。9.9.9.9 のような public resolver は対象になりません。そのため、DNS 行が正しく見えても、クエリは local link 経由で送信されます。

resolvectl には正しい server が表示されるのに、名前解決が別の場所へ送られるのはなぜですか?

systemd-resolved は link ごとに resolver list を保持し、クエリごとに使用する link を選択します。そのため、wg0 の正しい設定は、別の link が名前解決用の default route を保持している間は無視されます。クライアントの [Interface] block に PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~. を追加し、DNS = 行を削除します。その後、resolvectl status wg0Default Route: yes を報告するはずです。

複数のクライアントで問題が発生している場合、どのクライアントから修正すべきですか?

まず Linux クライアントを1台修正します。仕組みを確認できるのは Linux クライアントだけだからです。resolvectl statustcpdump により、どの resolver が応答し、どの interface がパケットを運んだかを確認できます。phone と desktop のアプリは、表示される仕組みがなくても同じ DNSAllowedIPs の値を適用します。そのため、Linux クライアントが正しくなれば、動作を確認済みの設定をコピーできます。