Linux上のAdGuard HomeでDNS over QUIC(DoQ)とDNS over HTTP/3(DoH3)を設定する方法

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

クイックスタート:5分でDoQとDoH3を立ち上げる

DoTやDoHのような従来の暗号化DNSプロトコルは、厳格なTCPハンドシェイクに依存しています。これに対する最新の代替手段であるDNS over QUIC(DoQ)とDNS over HTTP/3(DoH3)は、UDPベースのQUICを採用しています。この移行により、パケットロスの多い回線でのヘッドオブラインブロッキング(HoLブロッキング)が解消され、初回のクエリレイテンシが30〜80ms削減されます。DebianまたはUbuntuでプライベート再帰リゾルバーをセットアップするのに必要な時間は、5分もかかりません。

まず、AdGuard Homeの公式バイナリインストーラーを取得して実行します。

# 公式インストールスクリプトをダウンロードして実行
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v

# 53番ポートを解放するため、systemd-resolvedのDNSStubListenerを無効化
sudo sed -r -i.orig 's/#?DNSStubListener=yes/DNSStubListener=no/g' /etc/systemd/resolved.conf
sudo systemctl restart systemd-resolved

QUICハンドシェイクには有効なTLS証明書が必須です。独自ドメインを所有している場合は、スタンドアロンモードのcertbotを使用して無料のLet’s Encrypt証明書を生成します(80番ポートが一時的に開放されていることを確認してください)。

sudo apt update && sudo apt install -y certbot
sudo certbot certonly --standalone -d dns.example.com --agree-tos -m [email protected] --non-interactive

ブラウザでhttp://<your-server-ip>:3000にアクセスし、初期Webセットアップウィザードを進めます。ダッシュボードが表示されたら、設定 > 暗号化設定へ移動します。暗号化を有効にするにチェックを入れ、サーバー名(dns.example.com)を入力し、証明書ファイルのパスを指定します。

証明書ファイル: /etc/letsencrypt/live/dns.example.com/fullchain.pem
秘密鍵ファイル: /etc/letsencrypt/live/dns.example.com/privkey.pem

AdGuard Homeは直ちに、標準のHTTPSと並行してDoQをUDPポート853、DoH3をUDPポート443にバインドします。すぐにファイアウォールで両方のポートを開放しましょう。

sudo ufw allow 853/udp comment 'DNS over QUIC (DoQ)'
sudo ufw allow 443/udp comment 'HTTP/3 and DoH3'
sudo ufw reload

詳細解説:QUICがヘッドオブラインブロッキングを解決する理由

標準的なDoT(TCP 853)およびDoH(TCP 443)は、TCP上のTLS 1.3上で動作します。通常の接続確立には、TCPの3ウェイハンドシェイク(1 RTT)と、それに続くTLS鍵交換(さらに1 RTT)が必要です。モバイル環境で電波状況が悪化し、わずか2%のパケットロスが発生した場合でも、TCPはドロップしたセグメントが再送されて到着するまで、並行して走るすべてのDNSリクエストを停止させます。このボトルネックである「ヘッドオブライン(HoL)ブロッキング」は、ページの読み込み時間を数百ミリ秒も遅延させる原因となります。

QUICは、トランスポート層全体をUDPに移行することで、このアーキテクチャ上の欠点を解決します。

  • Zero Round-Trip Time(0-RTT):リピート接続のクライアントはハンドシェイクを省略できます。過去のクエリによる暗号化セッションチケットをキャッシュすることで、デバイスは最初のパケットで即座にDNSペイロードを送信できます。
  • 独立したマルチストリーミング(Independent Multi-Streaming):メディアを多用する最新のWebサイトでは、一度に30〜60もの異なるドメインの名前解決が発生することがよくあります。トラッカーの解決中にパケット4番がドロップしても、残りの59件のDNSクエリは何の影響も受けずに名前解決を継続します。
  • シームレスな接続移行(Connection Migration):玄関を出て外に出ると、スマートフォンはWi-Fiから5Gへと切り替わります。TCPの場合、IPアドレスの変更によってすべてのソケットが切断され、再ネゴシエーションが強制されます。一方、QUICは送信元IPではなく任意の64ビットConnection IDに依存するため、パケットを1つもドロップすることなく名前解決ストリームを維持できます。

RFC 9250において、ネイティブのDoQはUDPポート853で動作します。DNS over HTTP/3は、UDPポート443上のHTTP/3リクエストストリーム内にバイナリDNSフレームをカプセル化します。不安定な衛星回線やLTEアップリンクを介してブランチオフィスを管理する現場のエンジニアにとって、UDPベースのリゾルバーへの移行はP99クエリレイテンシの即時短縮につながります。

高度な設定:AdGuardHome.yamlのチューニングとプロトコルのテスト

GUIだけでも運用を開始できますが、パワーユーザーなら設定ファイルを直接操作するのが最適です。/opt/AdGuardHome/AdGuardHome.yamlを編集することで、細かなソケットバッファリング、詳細なTTLオーバーライド、アップストリームへのDoQフォワーディングなどが設定可能になります。

コア設定の強化

設定ファイルを直接編集する前には、必ずデーモンを停止してください。

sudo systemctl stop AdGuardHome
sudo nano /opt/AdGuardHome/AdGuardHome.yaml

dnsおよびtlsセクションを調整し、高速なDoQおよびDoH3エンドポイント経由でアップストリームにルーティングさせ、キャッシュ制御を最適化します。

dns:
  bind_hosts:
    - 0.0.0.0
  port: 53
  upstream_dns:
    # 上流のDoQおよびDoH3リゾルバーへ名前解決を転送
    - quic://dns.adguard-dns.com
    - h3://cloudflare-dns.com/dns-query
  fastest_addr: true
  cache_size: 67108864 # 64 MBのインメモリキャッシュ(約250,000件のキャッシュレコード)
  cache_ttl_min: 300   # 最小TTLを5分に強制
  cache_ttl_max: 86400 # レコードの最大保持期間を24時間に制限

tls:
  enabled: true
  server_name: dns.example.com
  force_https: false
  port_https: 443
  port_dns_over_quic: 853
  certificate_path: /etc/letsencrypt/live/dns.example.com/fullchain.pem
  private_key_path: /etc/letsencrypt/live/dns.example.com/privkey.pem
  strict_sni_check: true

サービスを再起動し、システムログを確認してQUICリスナーが正常に初期化されたことを確認します。

sudo systemctl start AdGuardHome
sudo journalctl -u AdGuardHome -n 50 --no-pager | grep -i quic

コマンドラインからのクエリベンチマーク

dig、drill、nslookupなどの従来型ツールはQUICに対応していません。Nathan Sales氏が開発したオープンソースのqクライアントを使用すれば、DoQやDoH3、従来のプロトコルを標準でサポートしているため、この問題を解決できます。

# コンパイル済みバイナリをダウンロードしてインストール
wget https://github.com/natesales/q/releases/download/v0.19.2/q_0.19.2_linux_amd64.tar.gz
tar -xvf q_0.19.2_linux_amd64.tar.gz
sudo mv q /usr/local/bin/

# DNS over QUIC経由で問い合わせ
q @quic://dns.example.com example.com A

# DNS over HTTP/3経由で問い合わせ
q @h3://dns.example.com/dns-query example.com AAAA

ターミナルに出力された応答の最後の行を確認してください。Protocol: QUICという表示とともに、ウォームアップ済みの0-RTT接続ではRTT(往復レイテンシ)が15ms未満まで短縮されていることが確認できるはずです。

本番運用の信頼性を高める実践的なTips

1. UDPソケット受信バッファの最大化

Linuxのデフォルトのネットワークバッファは、高スループットなQUIC通信を処理するには小さすぎます。急激なトラフィックバースト(マイクロバースト)が発生すると、カーネルはAdGuard Homeが受信する前に受信UDPフレームを警告なしにドロップしてしまいます。/etc/sysctl.d/99-quic.confを作成して、ソケットメモリの割り当てを増やしましょう。

cat << 'EOF' | sudo tee /etc/sysctl.d/99-quic.conf
net.core.rmem_max = 7500000
net.core.wmem_max = 7500000
net.core.rmem_default = 262144
net.core.wmem_default = 262144
EOF

sudo sysctl --system

2. ダウンタイムゼロでの証明書自動リロード

Let’s Encryptの証明書の有効期限は90日です。Certbotが新しい証明書を取得した際、新しいキーペアを読み込ませるためにAdGuard Homeを安全にリロードする必要があります。Certbotの更新後フック(post-renewal)ディレクトリに自動デプロイフックを配置します。

cat << 'EOF' | sudo tee /etc/letsencrypt/renewal-hooks/post/adguard-reload.sh
#!/usr/bin/env bash
systemctl restart AdGuardHome
EOF

sudo chmod +x /etc/letsencrypt/renewal-hooks/post/adguard-reload.sh

3. 制限の厳しいISPやWi-Fiフィルタリングの回避

空港のWi-Fiネットワーク、ホテルのキャプティブポータル、制限の厳しい企業ゲートウェイなどでは、853番ポートへのUDPアウトバウンドトラフィックが日常的にブロックされます。リモートデバイスが通信不能にならないよう、次のような対策を講じておきましょう。

  • 優先フォールバック先として443番ポートのDoH3を指定したモバイル構成プロファイル(iOSの.mobileconfigファイルやAndroidのプライベートDNSなど)を導入します。UDP 443番ポートをブロックするとGoogle各種サービス、YouTubeのストリーミング、Cloudflareを利用するCDNなどが影響を受けるため、企業のファイアウォールでも遮断されることは稀です。
  • 上位ISPによって生のDoQパケットがドロップされる場合は、AdGuardHome.yamlで代替リスナーポート(UDP 8853番など)にバインドするか、エッジルーター上でeBPFやiptablesによるリダイレクトルールを設定してください。
Share: