grasys blog

Caddy + DNS-Persist: DNS への権限不要(キーレス)で安全に SSL 証明書を自動化する方法

どうも、Rayanです。

WebサーバーからDNSゾーンへのアクセス権限がいらない、「dns-persist」という新しいACMEチャレンジタイプが発表されました。

今回は、この技術と「Caddy」という自動SSL証明書ツールを使って、DNSへの権限(キーレス)を要求せずに安全にSSL証明書を自動化する方法を紹介します。

メモ:
dns-persist-01は現在テスト段階(Let’s Encryptの本番ロールアウトは2026年Q3予定)のため、今回のデモは現行のDNSチャレンジで行います。本番ロールアウト後に設定を差し替えるための事前準備として、まずは双方のフローを比較してみましょう。

従来のDNSチャレンジのフロー

従来の方式では、CaddyにDNSの変更権限(書き込みや削除)を付与し、毎回レコードを動的に書き換える必要がありました。

DNS-Persist チャレンジのフロー

DNS-Persistでは、事前に手動で固定のレコードを登録しておくため、CaddyサーバーはDNSに変更の権限を持つ必要がありません。

前提条件

  • Google Cloud DNSで管理されている既存のドメイン
    • CaddyサーバーのパブリックIPアドレスを指す DNS Aレコード が設定されていること
  • 証明書管理の対象が、稼働中のGCEインスタンスであること
  • Caddyサーバーへの Cloud DNSのIAM権限 が付与済みであること

手順

今年(2026年Q3)のロールアウト後にすぐdns-persistへ移行できるよう、まずは現行のDNSチャレンジを使ったCaddyの構築手順をステップ・バイ・ステップで紹介します。

Step 1:インストール方法

以下は、Rocky Linux 9.7OS向けです。

dnf install -y dnf-plugins-core
dnf copr enable -y @caddy/caddy
dnf install -y caddy

Google Cloud DNS(DNS-01)はデフォルトでは含まれていないため、モジュールを組み込んだカスタムバイナリでCaddyを再ビルドします。

まずはビルドツールである xcaddy をインストールします。

# install go
dnf install -y go

# install xcaddy
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest

# Rebuild caddy with google cloud dns and caddy events module
~/go/bin/xcaddy build --with github.com/caddy-dns/googleclouddns --with github.com/mholt/caddy-events-exec --output /usr/bin/caddy --output /usr/bin/caddy

Step 2: Caddyfileの設定を更新する

インストールされたか確認する。

> caddy version
v2.11.4 h1:XKxkMTgNSizEvKG6QHue6cAsFOteU2qA61w2tKkCWi0=

他のOSへのインストールについては、 こちらをご参照ください

デフォルトのCaddy設定ファイルをバックアップする。

mv /etc/caddy/Caddyfile /etc/caddy/Caddyfile.bk

以下のコードを新しいCaddyfileにコピーする。

echo "[domain name] {
        header {
                X-Forwarded-Proto https
        }

         # Set this path to your site's directory.
        root * /usr/share/caddy

        # Enable the static file server.
        file_server

        tls {
                # only lets encrypt and not ZeroSSL to handle renewal
                ca https://acme-v02.api.letsencrypt.org/directory

                #dns challenge settings
                dns googleclouddns {
                        gcp_project [project-name]
                }
        }
}" > /etc/caddy/Caddyfile

メモ: ご自身の環境に合わせて [domain name] と [project-name] を書き換えてください。 dns-persist 実装後は、 dns googleclouddnsdns-persist googleclouddnsになるかと思います。

Caddyを起動する。

systemctl start caddy

ACMEチャレンジタイプを確認する。

> journalctl --no-pager -u caddy | grep 'challenge_type'

Jun 25 00:33:52 "challenge_type":"dns-01"

メモ: dns-persist 実装後は, dns-01dns-persist-01になります。

SSL証明書が正常に発行されたか確認する。
ターミナルでの確認方法:

> journalctl --no-pager -u caddy | grep 'certificate obtained successfully'

Jun 25 00:34:01 {"level":"info", ... 
"msg": "certificate obtained successfully", "identifier": "<domain-name>", "issuer": "acme-v02.api.letsencrypt.org-directory"}


> cd /var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/<domain name>
> openssl x509 -in <domain name>.crt -dates -noout

notBefore=Jun 23 09:06:01 2026 GMT
notAfter=Sep 21 09:06:00 2026 GMT

ブラウザでの確認方法:

Step 3: DNSチャレンジの代わりにDNS-persistを使用する場合(追加ステップ)

  1. ACMEのアカウントIDをコピーする。
> journalctl --no-pager -u caddy | grep 'account_id'
{..."account_id":"https://acme-v02.api.letsencrypt.org/acme/acct/1234567890"...}   
  1. Cloud DNSにTXTレコードを作成して配置する。
Name/Host: _validation-persist.<domain>
TYPE: TXT
TTL: 5分
Value: "letsencrypt.org;" "accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234567890"

caddyを再起動する。

systemctl restart caddy

ACMEチャレンジタイプを確認する。

> journalctl --no-pager -u caddy | grep 'challenge_type'

Jun 25 00:33:52 "challenge_type":"dns-persist-01"

Slackへの通知方法

Caddyは証明書の更新と管理を自動で行ってくれますが、正常に更新されたかどうか、通知を受け取りたい場合はどうすればよいでしょうか?

そこで、Caddyの生みの親であるmholt氏が作成した caddy-events-exec プラグインを使用します。

今回はこれをSlackと連携させます。全体の流れは以下の通りです:
Caddyfile → send_to_slack.sh(Bashスクリプト) → Slackチャンネル

こちらがサンプルのBashスクリプトです。

#!/bin/bash

SLACK_WEBHOOK_URL="https://hooks.slack.com/services/.../.../..."


curl -X POST -H 'Content-type: application/json' --data '{"text":"🔒 *Caddy Alert:* SSL Certificate has been successfully renewed!"}' "$SLACK_WEBHOOK_URL"

以下のコードをCaddyfileに追加する。

{
        events {
                on cert_obtained exec /usr/local/bin/send_to_slack.sh
        }
}

SSL証明書の発行後、Slackチャンネルにも通知されます。

まとめ

今回はセキュリティベストプラクティスとなる、新しいACMEチャレンジ dns-persist を使ったCaddyの将来的なセットアップをご紹介しました。

現在 dns-persist-01 はテスト段階です。Let’s Encryptの本番ロールアウトは 2026年Q2からQ3 に予定されており、その後Caddyへも早期に統合される見込みです。

楽しみです^^

参考

https://letsencrypt.org/2026/02/18/dns-persist-01

https://github.com/caddyserver/caddy/issues/7495


採用情報
お問い合わせ