🐝

TraefikでDNSチャレンジな証明書(ワイルドカード証明書)を発行/更新しよう!

2024/08/09に公開

始めに

レジストラで独自ドメインを取得してサーバーを公開するとき、SSL証明書を発行したり更新したりすると思います。
今まではCertbotでSSL証明書の発行/更新をして、TraefikでSSL証明書の管理をしていましたが、Traefikの公式ドキュメントを眺めていると、TraefikだけでSSL証明書の発行/更新を行えることに気付いたので、やってみました。
複数のサービスのリバースプロキシとしてTraefikを使用していて、SSL証明書は1枚にまとめたい、という方の参考になれば嬉しいです。
Let's Encrypt!

https://doc.traefik.io/traefik/https/acme/

・レジストラで独自ドメインを取得する方法
・DNSサービスを設定する方法
については記述していません。
また、TraefikをDocker Composeで動作させることを前提としています。

1. Traefikのコンテナを作成する

1.1. compose.ymlを作成する

Traefikを起動するために、compose.ymlを作成します。

compose.yml
services:
  traefik:
    image: traefik:3.1.0
    container_name: rp-traefik
    restart: always
    networks:
      - reverse-proxy
    ports:
      - 80:80
      - 443:443
      - 8080:8080
    labels:
      - traefik.enable=true
      - traefik.http.routers.traefik-reverse-proxy.tls=true
      - traefik.http.routers.traefik-reverse-proxy.tls.certresolver=mydnsjp
      - traefik.http.routers.traefik-reverse-proxy.tls.domains[0].main=*.<domain-name>
    environment:
      - MYDNSJP_MASTER_ID=<mydnsjp-master-id>
      - MYDNSJP_PASSWORD=<mydnsjp-password>
    volumes:
      - ./traefik/volume/etc/traefik:/etc/traefik
      - ${XDG_RUNTIME_DIR}/docker.sock:/var/run/docker.sock:ro
      - /usr/share/zoneinfo/Asia/Tokyo:/etc/localtime:ro

networks:
  reverse-proxy:
    name: reverse-proxy

コンテナやネットワークの名称、ポート番号などは適宜読み替えてください。

要点は下記の通りです。
・certresolverにmydnsjpを指定する
自分はDNSサービスとしてMyDNSを使用しています。
後述するtraefik.ymlで設定を記述します。
・domains[0].mainに*.<domain-name>を指定する
SSL証明書のCNに指定するドメインの名称です。
自分はSSL証明書について十分な知識を持っていなかったため、下記のWebサイトを参考にしました。
https://coolify.io/docs/knowledge-base/traefik/wildcard-certificates
https://www.bestssl.net/faq/put-ssl-together/
Traefikでワイルドカード証明書を発行する方法を検索すると、domains[0].main=<domain-name>とCNを指定して、別途domains[0].sans=*.<domain-name>とSANsを指定するWebサイトが多く見られますが、正確にはそれはマルチドメインワイルドカード証明書に該当するのでは、と思いCNにのみワイルドカードなドメインを指定しました。
自分の環境では、どちらの方法でもワイルドカード証明書として使用できました。

また、環境変数は使用するDNSサービスによって異なりますので、公式ドキュメントを参考に適宜読み替えてください。
https://doc.traefik.io/traefik/https/acme/#providers

1.2. traefik.ymlを作成する

Traefikの設定ファイルを作成します。

traefik.yml
api:
  insecure: true
  dashboard: true

providers:
  docker:
    exposedByDefault: false
    network: reverse-proxy

entryPoints:
  web:
    address: :80
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: :443

certificatesResolvers:
  mydnsjp:
    acme:
      dnsChallenge:
        provider: mydnsjp
      email: <email>
      storage: /etc/traefik/certificate/wildcard/acme.json
      # caServer: https://acme-staging-v02.api.letsencrypt.org/directory

ネットワークの名称、ポート番号、ストレージのパスなどは適宜読み替えてください。

要点は下記の通りです。
・certificatesResolversにmydnsjpを作成する
compose.ymlで指定したcertresolverのことです。
・providerにmydnsjpを指定する
自分はDNSサービスとしてMyDNSを使用しています。
その他のDNSサービスを使用する場合は、公式ドキュメントを参考にしてください。
https://doc.traefik.io/traefik/https/acme/#providers

また、動作が確認できるまではcaServerにステージングのAPIを指定することをおすすめします。

1.3. Traefikのコンテナを起動する

ここまでできたら、Traefikのコンテナを起動します。
起動してしばらく待った後、下記のようなacme.jsonが作成されたら成功です!

acme.json
{
  "mydnsjp": {
    "Account": {
      "Email": "<email>",
      "Registration": {
        "body": {
          "status": "valid",
          "contact": [
            "mailto:<email>"
          ]
        },
        "uri": "https://acme-v02.api.letsencrypt.org/acme/acct/xxx"
      },
      "PrivateKey": "<private-key>",
      "KeyType": "4096"
    },
    "Certificates": [
      {
        "domain": {
          "main": "*.<domain-name>"
        },
        "certificate": "<certificate>",
        "key": "<key>",
        "Store": "default"
      }
    ]
  }
}

2. 任意のサービスのコンテナを作成する

Traefikで発行したSSL証明書を使用する任意のサービスのコンテナを作成します。
PhotoPrismの例は下記の通りです。

compose.yml
<省略>
    labels:
      - traefik.enable=true
      - traefik.http.routers.photoprism.tls=true
      - traefik.http.routers.photoprism.tls.certresolver=mydnsjp
      - traefik.http.routers.photoprism.rule=Host(`photoprism.<domain-name>`)
      - traefik.http.routers.photoprism.entrypoints=websecure
      - traefik.http.routers.photoprism.service=photoprism
      - traefik.http.services.photoprism.loadbalancer.server.port=2342
<省略>

サービスで使用したいドメインの名称と、Webサーバーのポート番号を指定することで、Traefikで発行したSSL証明書を使用できます。
サービスが増えても同じ要領でlabelsを指定すれば良く、SSL証明書は1枚で済むので便利ですね。

終わりに

目論見通りTraefikでSSL証明書を発行できました。
公式ドキュメントを読む限りでは、SSL証明書の更新も自動で実行してくれそうなので、3か月後どうなるか、楽しみです。
記事の内容が間違っていたり、質問がある場合は、気軽にコメントしていただけるとありがたいです🙇🏻‍♂️

Discussion