Traefik v3 × Cloudflare DNS Challenge:DockerコンテナのワイルドカードSSLを完全自動化する設定ガイド

Docker tutorial - IT technology blog
Docker tutorial - IT technology blog

背景と概要:なぜTraefikとDNS Challengeを使うのか?

数十個のコンテナをVPS上で動かしながら、従来の方法でSSLを管理する?それは本当に悪夢です。新しいサービスを追加するたびに手間がかかります——NginxのServer Blockを設定して、ポート80を開けて、Aレコードを向けて、そしてLet’s EncryptがHTTP-01 Challengeで検証するのを待つ。新しいサブドメイン1つで10〜15分。10個あれば午後が丸々潰れます。

Traefik v3はこの問題をまったく違うアプローチで解決します。Docker Socketを常時監視し、正しいラベルが付いた新しいコンテナを起動すると、Traefikが自動でSSLを検出・発行してくれます。特にCloudflare DNS Challengeと組み合わせることで:

  • ワイルドカードSSL(*.yourdomain.com)の発行:1枚の証明書をすべてのサブドメインで共有できます。
  • ポート80を公開する必要がない——インターネットに公開したくない内部サービスに最適です。
  • 有効期限前に自動更新されるため、手動での対応は不要です。

以前はNginx Proxy Managerを使っていましたが、Traefik v3に乗り換えてみると、まるでマニュアル車からオートマ車に替えたような感覚でした。DockerのLabelsシステムのおかげで、すべてが完全に自動化されます。

インストールと事前準備

以下の3つのうち1つでも欠けると途中で詰まります。始める前にしっかり準備しておきましょう。

1. Cloudflare APIトークン

このトークンにより、TraefikはDNS上に一時的なTXTレコードを作成してドメインの所有権を確認します——Let’s EncryptはそのレコードをチェックしてからCertを発行します。Global API Keyは使わないでください。漏洩した場合、Cloudflareアカウント全体がCompromiseされる恐れがあります。

My Profile > API Tokens > Create Tokenに進みます。「Edit zone DNS」テンプレートを選択し、使いたいゾーン(ドメイン)のみに権限を付与しましょう——アカウント全体への権限付与は避けてください。

2. ディレクトリ構成

管理とバックアップがしやすいよう、ディレクトリを次のように整理しています:

mkdir -p ~/traefik/data
touch ~/traefik/data/acme.json
chmod 600 ~/traefik/data/acme.json
touch ~/traefik/docker-compose.yml
touch ~/traefik/data/traefik.yml

注意: acme.jsonはSSL証明書の保存ファイルです。必ず権限を600に設定してください——設定しないと、Traefikは“acme.json” should have permissions 600というエラーで起動を拒否します。

3. ドメインをVPSに向ける

CloudflareのダッシュボードでAレコードを追加し、*.yourdomain.comをVPSのIPアドレスに向けます。重要:この時点ではProxy(黄色い雲のアイコン)をオフにしてください。Proxyを有効なままにすると、TraefikはVPSのIPではなくCloudflareのIPを受け取り、Cert Requestがすぐに失敗します。

Traefik v3の詳細設定

このセクションでは各ファイルを順番に解説します。Traefik v3はv2からいくつかの構文が変更されています——特にentryPointscertResolverの部分に注意が必要で、古い設定をそのままコピーするのは避けてください。

ステップ1:静的設定ファイル(traefik.yml)

このファイルはTraefik起動時に一度だけ読み込まれ、EntryPoint、Dockerプロバイダー、そして自動Cert発行のためのACME設定を定義します。

api:
  dashboard: true
  debug: false

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

  websecure:
    address: ":443"

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false

certificatesResolvers:
  cloudflare:
    acme:
      email: [email protected]
      storage: /acme.json
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - "1.1.1.1:53"
          - "8.8.8.8:53"

ステップ2:Docker Composeファイル(docker-compose.yml)

このファイルはTraefikを起動し、必要な3つのものを正しくマウントします:静的設定ファイル、Docker Socket(コンテナのラベルを読み取るため)、そしてacme.json(発行されたCertを保存するため)。

services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: always
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    ports:
      - 80:80
      - 443:443
    environment:
      - CF_DNS_API_TOKEN=YOUR_CLOUDFLARE_API_TOKEN
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./data/traefik.yml:/traefik.yml:ro
      - ./data/acme.json:/acme.json
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.dashboard.entrypoints=websecure"
      - "traefik.http.routers.dashboard.rule=Host(`traefik.yourdomain.com`)"
      - "traefik.http.routers.dashboard.service=api@internal"
      - "traefik.http.routers.dashboard.tls.certresolver=cloudflare"
      - "traefik.http.routers.dashboard.tls.domains[0].main=yourdomain.com"
      - "traefik.http.routers.dashboard.tls.domains[0].sans=*.yourdomain.com"

networks:
  proxy:
    external: true

実行前にNetworkを作成します:docker network create proxy。このNetworkはTraefik経由でExposeしたいすべてのコンテナで共有します——一度作れば、ずっと使えます。

Docker APIのレスポンスをデバッグしたり、TraefikのDynamic ConfigをJSON形式で確認したりするときは、toolcraft.app/ja/tools/developer/json-formatterにペーストするとフォーマットされて読みやすくなります——ブラウザ拡張機能をインストールするより手軽です。

ステップ3:サンプルアプリのデプロイと動作確認

システムが正しく動作しているか確認するには、小さなwhoamiコンテナをデプロイしてみましょう:

services:
  whoami:
    image: traefik/whoami
    container_name: test-app
    networks:
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.rule=Host(`whoami.yourdomain.com`)"
      - "traefik.http.routers.whoami.tls.certresolver=cloudflare"

動作確認とモニタリング

docker compose up -dを実行したら、すぐにログを確認します

docker logs -f traefik

"Legitimate certificate retrieved for domain yourdomain.com"という行が表示されればCertの取得成功です。https://whoami.yourdomain.comを開いて、HTTPSが緑色で警告が出なければ完了です。

モニタリング時のポイント:

  • Dashboard: https://traefik.yourdomain.comにアクセスすると、実行中のRouterとServiceをビジュアルで確認できます——デバッグ時に非常に役立ちます
  • Rate Limit: Let’s EncryptはDomain1つあたり週50枚のCertに制限しています。設定ミスで繰り返しRestartすると、数時間でQuotaを使い切ってしまいます。テスト時は、traefik.ymlacmeセクションにcaServer: "https://acme-staging-v02.api.letsencrypt.org/directory"を追加してstaging環境を使いましょう。
  • Propagation: CloudflareのTXTレコードがPropagateされるまで30秒〜数分かかることがあります。最初の1〜2分でCertが確認できなくても、すぐにコンテナをRestartしないでください——Traefikが自動で処理します。

このセットアップを数週間運用した後、もうSSLに手をかける必要がなくなりました。新しいサービスを追加するときは正しいラベルを付けるだけで、あとはTraefikがすべて処理してくれます。APIトークンの権限やDNS Propagationの部分でつまずいた場合は、ぜひ下のコメント欄で教えてください。

Share: