2026年6月16日
2026年6月16日
DoQ(DNS over QUIC)と DoT(DNS over TLS)を1台のサーバーで併用する設定
DoT と DoQ はどちらもポート 853 を使いますが、DoT は TCP、DoQ は UDP(QUIC)なので、同じサーバー・同じ証明書で同時に提供できます。この記事では、自前の VPS で暗号化 DNS リゾルバを動かしている人向けに、DoT と DoQ を並べて受け付ける構成、証明書とファイアウォールの準備、クライアントからの動作確認までを順に説明します。
DoT と DoQ を併用する理由
DoT(RFC 7858)は TLS の上で DNS をやり取りする方式で、Android の「プライベート DNS」をはじめ対応クライアントが多いのが強みです。一方の DoQ(RFC 9250)は QUIC の上で DNS を運ぶ方式で、TCP の Head-of-Line ブロッキングが起きにくく、接続の再開も速いという利点がありますが、対応クライアントはまだ限られます。
両方を提供しておくと、DoQ に対応したアプリは DoQ を使い、それ以外の端末は DoT を使う、という住み分けができます。また、ネットワークによっては UDP 853 が遮断されていることがあり、その場合でも TCP 853 の DoT なら通る可能性があります。どちらか一方に寄せるより、併用のほうが利用者側の環境差に強い構成になります。
ただし、クライアントが「DoQ が失敗したら DoT に切り替える」動作をするかはアプリごとに異なります。自動で切り替わる前提にせず、利用者に両方の接続先を案内できるようにしておくのが無難です。
構成の考え方
ここでは次の分担で組みます。
- 再帰問い合わせとキャッシュ: Unbound(127.0.0.1 の 5300 番で待ち受け、外には出さない)
- 暗号化の終端: dnsdist(TCP 853 で DoT、UDP 853 で DoQ を受ける)
Unbound 自体も DoT の待ち受けに対応しており、新しめのバージョンでは DoQ の待ち受けにも対応しています。ただし DoQ はビルド時に QUIC ライブラリ(ngtcp2 など)を有効にする必要があり、ディストリビューションのパッケージでは使えないことがあります。dnsdist は DoT・DoQ・DoH の終端をまとめて扱えるので、フロントに置くと証明書や接続制限の管理を一か所に集められます。dnsdist の DoQ 対応は 1.9 系からで、こちらもビルドオプション次第です(2026年10月現在)。導入したパッケージが DoQ を含んでいるかは、後述の起動ログで確認します。
作業前に、既存の DNS 設定ファイルをバックアップし、可能であれば検証用の VPS で一度通してから本番に入れてください。
手順1: 証明書を用意する
DoT も DoQ も TLS 1.3 を使うため、サーバー名(例: dns.example.com)に対する証明書が必要です。Web サーバーと同じく Let's Encrypt で取得できます。
# 80番が空いている場合の例(Webサーバーがある場合は --webroot などに変更)
sudo certbot certonly --standalone -d dns.example.com
dnsdist は専用ユーザーで動くことが多いため、/etc/letsencrypt/live/ 配下の秘密鍵を読めずに起動に失敗する、というつまずきがよくあります。グループ権限で読めるようにするか、更新時のデプロイフックで dnsdist 用のディレクトリにコピーする方法が扱いやすいです。
# /etc/letsencrypt/renewal-hooks/deploy/dnsdist.sh の例
#!/bin/sh
install -o root -g _dnsdist -m 0640 /etc/letsencrypt/live/dns.example.com/fullchain.pem /etc/dnsdist/fullchain.pem
install -o root -g _dnsdist -m 0640 /etc/letsencrypt/live/dns.example.com/privkey.pem /etc/dnsdist/privkey.pem
systemctl restart dnsdist
dnsdist の実行ユーザー名(上の例では _dnsdist)はパッケージによって異なるので、systemctl cat dnsdist などで確認して合わせてください。
手順2: Unbound をローカル専用で待ち受けさせる
Unbound は外部に公開せず、dnsdist からだけ問い合わせを受けるようにします。
# /etc/unbound/unbound.conf.d/local-backend.conf
server:
interface: 127.0.0.1@5300
access-control: 127.0.0.0/8 allow
access-control: 0.0.0.0/0 refuse
do-ip6: yes
unbound-checkconf で文法を確認してから再起動します。ここで外向きのインターフェースを開けてしまうと、平文の DNS で誰でも使えるリゾルバになってしまうため注意が必要です。
手順3: dnsdist で DoT と DoQ を待ち受ける
-- /etc/dnsdist/dnsdist.conf
-- 利用を許可するネットワーク(自宅・社内などに合わせて変更)
setACL({'127.0.0.0/8', '192.0.2.0/24', '2001:db8::/32'})
-- バックエンド(Unbound)
newServer({address='127.0.0.1:5300', name='unbound'})
-- DoT: TCP 853
addTLSLocal('0.0.0.0:853', '/etc/dnsdist/fullchain.pem', '/etc/dnsdist/privkey.pem')
addTLSLocal('[::]:853', '/etc/dnsdist/fullchain.pem', '/etc/dnsdist/privkey.pem')
-- DoQ: UDP 853
addDOQLocal('0.0.0.0:853', '/etc/dnsdist/fullchain.pem', '/etc/dnsdist/privkey.pem')
addDOQLocal('[::]:853', '/etc/dnsdist/fullchain.pem', '/etc/dnsdist/privkey.pem')
ポイントは setACL です。dnsdist の初期状態ではプライベートアドレスなどからの問い合わせしか受け付けないため、外出先のスマートフォンから使いたい場合は、許可する範囲を明示的に書く必要があります。逆に 0.0.0.0/0 を許可すると、暗号化されているとはいえ誰でも使えるリゾルバになり、不正利用や負荷の原因になります。個人用・社内用であれば、許可範囲を絞るか、レート制限を併用してください。
設定を確認してから起動します。
sudo dnsdist --check-config
sudo systemctl restart dnsdist
sudo journalctl -u dnsdist -n 50
ログに DoQ の待ち受けに関するエラー(DoQ 非対応ビルドである旨など)が出ていないかを見ます。ss -lntup | grep 853 で、TCP と UDP の両方で 853 番が開いていれば待ち受けはできています。
手順4: ファイアウォールを開ける
DoT と DoQ の併用で最も多い見落としが、UDP 853 の開け忘れです。DoT だけ動いていた環境では TCP 853 しか許可していないことがよくあります。
# ufw の例
sudo ufw allow 853/tcp
sudo ufw allow 853/udp
VPS 事業者やクラウドのセキュリティグループ側にもフィルタがある場合は、そちらでも UDP 853 を許可します。
手順5: クライアントから動作を確かめる
Knot DNS 付属の kdig は DoT と DoQ の両方を試せるので便利です(DoQ は 3.3 系以降)。
# DoT(証明書のホスト名も検証する)
kdig @dns.example.com +tls +tls-hostname=dns.example.com +tls-ca example.com A
# DoQ
kdig @dns.example.com +quic example.com A
BIND の dig も 9.18 以降で +tls に対応していますが、DoQ には対応していない点に注意してください。
確認時に見るべき点は次の3つです。
- 応答の
status: NOERRORと、期待した A レコードが返っているか - DoT で証明書検証のエラーが出ていないか(中間証明書の欠落はここで分かります)
- DoQ だけタイムアウトする場合は、UDP 853 がどこかで遮断されていないか
DoQ だけ失敗して DoT は成功する、という結果なら、サーバー側のビルド・UDP のファイアウォール・利用者側ネットワークのいずれかが原因です。サーバー内で kdig @127.0.0.1 +quic を実行して成功すれば、サーバー設定は正しく、経路上の問題だと切り分けられます。
運用で気をつけること
証明書の更新は、デプロイフックで dnsdist を再起動する形にしておけば、DoT と DoQ が同時に新しい証明書へ切り替わります。更新処理は sudo certbot renew --dry-run で事前に試しておくと安心です。
また、暗号化 DNS は問い合わせ内容を経路上から見えにくくする仕組みであり、リゾルバ運営者からは問い合わせが見えます。社内向けに提供する場合は、ログをどこまで残すか、保存期間をどうするかを決め、利用者に説明できるようにしておいてください。
クライアントに接続先を自動で知らせる仕組みとして、DDR(RFC 9462)や SVCB レコードで DoT・DoQ の対応を広告する方法もありますが、対応状況は OS やアプリによって差があります。まずは接続先のホスト名を手動で設定してもらう運用から始めるのが確実性の高い進め方です。
まとめ
- DoT は TCP 853、DoQ は UDP 853 を使うため、1台のサーバーで同じ証明書を使って併用できる
- Unbound をローカル専用のバックエンドにし、dnsdist で DoT と DoQ を終端すると管理が一か所にまとまる
- dnsdist の ACL と、UDP 853 のファイアウォール許可が典型的なつまずきどころ
kdig +tlsとkdig +quicで両方を確かめ、DoQ だけ失敗するならサーバー内からの確認で経路の問題かを切り分ける- 証明書の更新はデプロイフックでまとめて反映し、
certbot renew --dry-runで事前に試す