MyDNS×Certbot(DNS-01)でSSL証明書を全自動更新
■ はじめに:なぜDNS-01認証なのか
通常、Certbotでよく使われるのは80番ポートを利用した http-01 認証(ACMEチャレンジ)だが、本環境ではセキュリティ対策として 80番ポートおよび443番ポートへのアクセスを国内限定に絞っている。
Let’s Encryptの認証サーバーは海外からもアクセスしてくるため、この制限下では通常のWeb認証が通らない。
そこで、ポート開放状況に左右されずに証明書を発行・更新できる DNS-01チャレンジ を採用した。
また、ハニーポット(迷い込み用サイト)運用において、あえて正規ドメイン(sky.0t0.jp)用の証明書をハニーポット側にセットすることで、アクセス者に「ドメイン不一致の警告」を見せ、意図的に隙があるように演出している。
この正規証明書の更新プロセスを自動化した際の記録。
■ 1. 構築環境と課題
・対象ドメイン: sky.0t0.jp, deepsky.0t0.jp
・手法: Certbotの manual モード + MyDNS DirectEdit(PHPスクリプト)
・直面した課題: certbot renew を実行すると、設定ファイル (.conf) に dns と記述していても、なぜかhttp-01 認証(Web 経由のチャレンジ)を試行してしまい、更新に失敗する。
■ 2. なぜ設定ファイルの記述だけでは不十分なのか
検証の結果、Certbotの仕様による以下の挙動が原因であることが判明した。
・設定ファイルの限界: /etc/letsencrypt/renewal/xxx.conf 内に preferred_challenges = dns と書いても、コマンドライン引数で明示的に上書きしない限り http-01 認証が実行されてしまう。
Certbot 1.12.0 では、renew 実行時に認証方式が明示されていない場合、manual 認証であっても http-01 が選択される挙動が確認された。
renewal 設定ファイル内の preferred_challenges = dns だけでは、この挙動を抑止できないケースがある。
・解決策: challenge 選択の曖昧さを回避するため、実行コマンド側に直接オプションを付与する必要がある。
■ 3. 運用のポイント:certbot.timer に頼らない自動化
certbot.timer はディストリビューション標準の ExecStart 設定で certbot renew を実行するため、
認証方式を上書きするオプションを注入できない。
そのため、上述した「履歴優先」の仕様によって http-01 に戻ってしまい、DNS-01認証が動かない。
【対策】
systemd の override で ExecStart を書き換える方法もあるが、今回は運用の単純さを優先し、cron による明示実行を採用した。
・certbot.timer は放置(または停止)。
・cron を使い、自作のシェルスクリプトからオプションを強制指定して実行する。
■ 4. 最終的な自動更新設定
- 定期実行シェルスクリプト (/root/cert_renewal.sh)
#!/bin/bash
--preferred-challenges dns を明示して認証方式を固定し、静かに(quiet)実行する
/usr/bin/certbot renew --preferred-challenges dns --quiet
- Cron登録(週1回)
毎週月曜の深夜2時に実行
0 2 * * 1 /root/cert_renewal.sh
■ 5. 結果
--dry-run テストにて、sky.0t0.jp および deepsky.0t0.jp 両方の検証パスを確認。
ハニーポットにはこの正規証明書を充て、「正規のドメインだが証明書エラーが出る」という狙い通りの環境を、手放しで維持できるようになった。
■ まとめ(覚書)
・認証の固定: 自動更新時はコマンド引数で --preferred-challenges dns を指定し、Certbotの履歴優先仕様を上書きする。
・フックの活用: MyDNSのDirectEditスクリプトを manual-auth-hook に設定することで、DNSレコードの操作も自動化。