2026年6月18日
2026年6月18日
DANE と DoH (DNS over HTTPS) を併用する設定|送信メールサーバーの上流問い合わせを DoH にし、DNSSEC の検証は手元の Unbound で行う
DANE と DoH を併用するときは、「DoH は上流への通信路を暗号化する手段、DANE に必要な DNSSEC の検証は自分のホストで行う」と役割を分けるのが基本です。送信メールサーバー(Postfix)と同じホストに検証役の Unbound を置き、Unbound の上流に DoH の転送役(dnscrypt-proxy)をつなぐ構成にすると、TLSA レコードの検証結果を Postfix に正しく渡しながら、宛先ドメインの問い合わせを経路上で読まれにくくできます。この記事では、その構成の設定、Postfix に検証結果が届かない典型的な原因、動作の確認方法までを説明します。
同じサイトの「DANE と DoT を併用する設定」は上流を DoT にする構成です。この記事は上流を DoH にする場合に固有の点(Unbound 単体では上流に DoH を使えないこと、転送役の選び方、HTTPS が通る環境での使いどころ)に絞っています。
先に押さえておく役割分担
DANE(SMTP では RFC 7672)は、受信側メールサーバーの証明書や公開鍵の指紋を TLSA レコードとして DNS に公開し、送信側が TLS 接続時に照合する仕組みです。TLSA レコードは DNSSEC で署名されていることが前提で、送信側は「署名の検証に成功した応答」だけを信用します。
DoH(RFC 8484)は DNS の問い合わせを HTTPS で運ぶ仕組みです。守れるのは自分と DoH サーバーの間の通信路であり、応答の中身が正しいかどうかは保証しません。DoH サーバーが付けてきた AD ビット(検証済みの印)をそのまま信じると、信頼の範囲が上流の事業者まで広がってしまいます。
そこで、検証は自分のホストの Unbound で行い、DoH は「上流まで暗号化して運ぶ部分」にだけ使います。DoH を使う動機は、たとえば次のような場面です。
- 外向きの DNS(53番や853番)が制限されたネットワークで、HTTPS(443番)しか通らない
- 送信先ドメインの一覧を、データセンターや経路上の機器に平文で見せたくない
逆に、53番の直接の再帰問い合わせに制限がないなら、Unbound に自分でフルリゾルバーとして問い合わせさせるほうが構成は単純です。DoH の併用は「必要な理由があるときに足すもの」と考えてください。
構成の全体像
Postfix ── 127.0.0.1:53 ── Unbound(DNSSEC 検証・キャッシュ)
└─ 127.0.0.1:5053 ── dnscrypt-proxy ── HTTPS 443(DoH)── 上流のリゾルバー
Unbound は上流への DoT 転送には対応していますが、上流へ DoH で転送する機能は持っていません(2026年10月現在)(Unbound の DoH 対応は、クライアントからの DoH を受ける側です)。そのため、DoH で上流に問い合わせる部分を dnscrypt-proxy に任せます。なお、Cloudflare の cloudflared にも DNS の転送機能(proxy-dns)がありましたが、廃止が告知されているため新しく組む構成では避けたほうが無難です。最新の扱いは Cloudflare の案内で確認してください。
dnscrypt-proxy の設定
パッケージで導入した場合、設定ファイルは /etc/dnscrypt-proxy/dnscrypt-proxy.toml にあることが多いです。作業前に元のファイルをバックアップしてください。
# /etc/dnscrypt-proxy/dnscrypt-proxy.toml(抜粋・例)
listen_addresses = ['127.0.0.1:5053']
# DoH のサーバーだけを使う
doh_servers = true
dnscrypt_servers = false
# DNSSEC に対応し、ログを残さず、フィルタリングしないと表明しているサーバーに絞る
require_dnssec = true
require_nolog = true
require_nofilter = true
# 使うサーバーを名前で固定する(名前は公開リストで確認する)
server_names = ['your-doh-server-1', 'your-doh-server-2']
server_names に入れる名前は、dnscrypt-proxy が参照する公開リゾルバーの一覧(public-resolvers)に載っている名前から選びます。名前やサーバーの提供状況は変わることがあるため、リストを見て決めてください。2か所以上の事業者を入れておくと、片方が止まっても転送が続きます。
ここで大事なのは require_nofilter です。広告やマルウェアのドメインを遮断する「フィルタあり」の DoH サーバーは、遮断したドメインに偽の応答を返します。署名されたドメインでこれが起きると Unbound の検証が失敗し、メールの配送が保留されます。メールサーバーの上流には、フィルタなしのサーバーを選ぶのが安全です。
設定後は dnscrypt-proxy を再起動し、単体で DNSSEC の情報が通るかを確かめます。
sudo systemctl restart dnscrypt-proxy
dig +dnssec @127.0.0.1 -p 5053 example.com SOA
応答に RRSIG レコードが含まれていれば、DNSSEC の署名が転送の途中で落とされていません。RRSIG が無い場合は、上流のサーバー選びか dnscrypt-proxy の設定を見直します。なお、ソケットを systemd で起動する配布パッケージでは、待ち受けアドレスを dnscrypt-proxy.socket 側で決めていることがあります。設定ファイルを変えても待ち受けが変わらないときは、ソケットのユニットも確認してください。
Unbound の設定
# /etc/unbound/unbound.conf.d/dane-doh.conf(例)
server:
interface: 127.0.0.1
access-control: 127.0.0.0/8 allow
# ループバック上の転送先に問い合わせるために必要
do-not-query-localhost: no
# DNSSEC 検証のトラストアンカー(配布パッケージで設定済みのことが多い)
auto-trust-anchor-file: "/var/lib/unbound/root.key"
edns-buffer-size: 1232
forward-zone:
name: "."
forward-addr: 127.0.0.1@5053
# 転送先が止まったときに平文の再帰問い合わせへ切り替えない
forward-first: no
do-not-query-localhost は、既定では Unbound がループバックアドレスに問い合わせないようにする設定です。転送先が 127.0.0.1 なので、no にしないと問い合わせが届きません。
トラストアンカーが設定されていないと、Unbound は検証を行わず、AD ビットも付けません。unbound-checkconf で文法を確かめてから再起動します。
sudo unbound-checkconf
sudo systemctl restart unbound
dig @127.0.0.1 example.com SOA +dnssec
応答のフラグ欄に ad があれば、Unbound が検証に成功しています。
forward-first: no にしているのは、DoH の転送役が止まったときに、Unbound が自分で平文の再帰問い合わせを始めないようにするためです。その場合は名前解決が失敗してメールが保留になりますが、DANE の観点では「検証できないまま送る」より安全側の挙動です。保留より配送の継続を優先したい場合は yes にもできますが、そのときは問い合わせの一部が平文で出ていくことを受け入れることになります。どちらにするかは運用方針として決めておいてください。
Postfix に検証結果を届ける
Postfix 側では、DNSSEC の検証結果を使うことと、DANE を有効にすることを指定します。
# /etc/postfix/main.cf(抜粋)
smtp_dns_support_level = dnssec
smtp_tls_security_level = dane
設定は postconf で確認し、postfix reload で反映します。ここでつまずきやすいのが、Unbound が付けた AD ビットが Postfix に届かないケースです。主な原因は次の3つです。
- resolv.conf の trust-ad:glibc 2.31 以降は、
/etc/resolv.confにoptions trust-adが無いと AD ビットをアプリケーションに渡しません。nameserver 127.0.0.1とoptions trust-adの2行を入れます。 - systemd-resolved の管理:Ubuntu などでは
/etc/resolv.confが systemd-resolved の管理するファイルへのリンクになっており、127.0.0.53 を向いています。Unbound を直接参照させるには、リンクを外して自分で書いたファイルに置き換えるか、resolved の設定で上流を Unbound にする必要があります。変更前に元の状態をメモしておくと戻しやすくなります。 - chroot 内の resolv.conf:Debian 系の Postfix は smtp プロセスを chroot で動かすことがあり、その場合は
/var/spool/postfix/etc/resolv.confが参照されます。ホスト側の resolv.conf を直しても古い内容のままのことがあるので、両方を確かめてください。
動作の確認
まず、TLSA レコードの検証結果を Unbound 経由で確かめます。宛先のメールサーバー名は、DANE を導入済みの相手に置き換えてください。
dig +dnssec @127.0.0.1 _25._tcp.mx.example.net TLSA
TLSA レコードが返り、フラグに ad があれば、検証済みの TLSA を取得できています。次に、Postfix 付属の posttls-finger で DANE の照合まで試します。
posttls-finger -c -l dane example.net
照合に成功すると「Verified TLS connection established」のような表示になります。実際の配送ログ(/var/log/mail.log など)でも、DANE で照合できた相手は Verified、照合できなかった相手は Untrusted などと区別されて記録されます。
最後に、上流への問い合わせが平文で出ていないかを確かめます。
sudo tcpdump -ni eth0 'udp port 53 or tcp port 53'
メールを送りながらこのコマンドを実行し、外向きの53番の通信が出ていなければ、問い合わせは DoH 経由になっています。インターフェース名は環境に合わせて変えてください。
運用で気をつけること
- 上流の停止はメールの保留につながる:
forward-first: noの構成では、DoH の上流がすべて使えなくなると名前解決ができません。dnscrypt-proxy のプロセス監視と、メールキューの滞留の監視(mailqの件数など)を組み合わせておくと気づきやすくなります。 - ブラウザの DoH とは別物:ブラウザの DoH 設定はブラウザの名前解決だけに効き、HTTPS の証明書を DANE で照合する仕組みは主要なブラウザに実装されていません。この記事の構成はメールサーバーの名前解決を対象にしたものです。
- 自分のドメインの TLSA は別の作業:送信側の構成とは別に、受信側として TLSA を公開する場合は、証明書の更新に合わせて TLSA を差し替える運用が必要です。
設定変更はステージング環境やテスト用のホストで動作を確かめてから本番に反映し、本番では元の設定ファイルを残したうえで作業してください。
まとめ
- DoH は上流までの通信路の暗号化、DANE に必要な DNSSEC の検証は自分のホストの Unbound で行う。
- Unbound は上流への DoH 転送に対応していないため、dnscrypt-proxy などの転送役を間に置く。転送先がループバックなら
do-not-query-localhost: noが必要。 - 上流はフィルタなしの DoH サーバーを複数選び、RRSIG が通ることを確かめる。
- Postfix に AD ビットが届かないときは、resolv.conf の
options trust-ad、systemd-resolved の管理、chroot 内の resolv.conf を順に確認する。 - 上流が止まったときに平文へ切り替えるかどうかは、メールの保留と暗号化のどちらを優先するかで決めておく。