すべてのデプロイガイド デプロイ

DockerとリバースプロキシでのSSL証明書

Dockerコンテナは通常、SSL自体を処理しません。前段に配置されたリバースプロキシがTLSを終端し、復号されたトラフィックをコンテナに転送します。このガイドでは、最も一般的な3つのアプローチを解説します。

アプローチ1: Nginxリバースプロキシ + 手動証明書

小規模なデプロイに最もシンプルなアプローチです。GetHTTPSから証明書を取得し、Nginxコンテナにマウントします。

docker-compose.yml

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
      - ./certs/fullchain.pem:/etc/ssl/fullchain.pem:ro
      - ./certs/privkey.pem:/etc/ssl/privkey.pem:ro
    depends_on:
      - app

  app:
    image: your-app:latest
    expose:
      - "3000"

nginx.conf

server {
    listen 443 ssl http2;
    server_name yourdomain.com;

    ssl_certificate     /etc/ssl/fullchain.pem;
    ssl_certificate_key /etc/ssl/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    location / {
        proxy_pass http://app:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

server {
    listen 80;
    server_name yourdomain.com;
    return 301 https://$host$request_uri;
}

更新するには: ./certs/内のファイルをGetHTTPSからの新しいファイルに置き換えてから、docker compose exec nginx nginx -s reloadを実行します。

アプローチ2: TraefikによるLet’s Encrypt自動化

Traefikはコンテナ向けに設計されたリバースプロキシです。Let’s Encrypt証明書を自動的に取得・更新できます。

docker-compose.yml

services:
  traefik:
    image: traefik:v3.0
    command:
      - "--providers.docker=true"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.letsencrypt.acme.email=you@example.com"
      - "--certificatesresolvers.letsencrypt.acme.storage=/acme/acme.json"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - traefik-acme:/acme

  app:
    image: your-app:latest
    labels:
      - "traefik.http.routers.app.rule=Host(`yourdomain.com`)"
      - "traefik.http.routers.app.tls.certresolver=letsencrypt"
      - "traefik.http.services.app.loadbalancer.server.port=3000"

volumes:
  traefik-acme:

Traefikがすべてを処理します:証明書の発行、更新、HTTPSの終端。手動の証明書管理は不要です。

アプローチ3: Caddy(ゼロ設定HTTPS)

Caddyは、設定なしでLet’s Encrypt証明書を自動的に取得・更新します。

docker-compose.yml

services:
  caddy:
    image: caddy:2
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy-data:/data
    depends_on:
      - app

  app:
    image: your-app:latest
    expose:
      - "3000"

volumes:
  caddy-data:

Caddyfile

yourdomain.com {
    reverse_proxy app:3000
}

これが設定のすべてです。CaddyがLet’s Encrypt証明書を取得し、自動的に更新します。

どのアプローチを選ぶべきか?

Nginx + 手動証明書TraefikCaddy
セットアップ中程度(設定 + 証明書ファイル)中程度(ラベル)最小限
自動更新❌(手動)
柔軟性高い高い中程度
学習コスト低い(馴染みがある)中程度低い
最適な用途小規模デプロイ、完全な制御動的コンテナ、マイクロサービスシンプルなサイト、最小限の設定

Dockerでの証明書の更新

アプローチ1(Nginx + 手動):

# ローカルの./certs/ディレクトリの証明書ファイルを置き換え
cp new-fullchain.pem ./certs/fullchain.pem
cp new-privkey.pem ./certs/privkey.pem

# コンテナ内のNginxをリロード(再起動不要)
docker compose exec nginx nginx -s reload

アプローチ2(Traefik)& 3(Caddy):

自動です。内部で更新を処理します。証明書はDockerボリューム(traefik-acmeまたはcaddy-data)に保存され、コンテナの再起動後も維持されます。

Docker Swarm: シークレットの使用

Docker Swarmデプロイメントでは、証明書ファイルをバインドマウントする代わりにDockerシークレットを使用します:

# 証明書ファイルからシークレットを作成
docker secret create ssl_cert fullchain.pem
docker secret create ssl_key privkey.pem
# docker-compose.yml(デプロイモード)
services:
  nginx:
    image: nginx:alpine
    secrets:
      - ssl_cert
      - ssl_key
    configs:
      - source: nginx_conf
        target: /etc/nginx/conf.d/default.conf

secrets:
  ssl_cert:
    external: true
  ssl_key:
    external: true

シークレットはコンテナ内の/run/secrets/ssl_cert/run/secrets/ssl_keyにマウントされ、保存時と転送時に暗号化されます。

よくある間違い

証明書をDockerイメージに組み込む

# ❌ これは絶対にやらないでください
COPY fullchain.pem /etc/ssl/fullchain.pem
COPY privkey.pem /etc/ssl/privkey.pem

証明書は90日ごとに有効期限が切れます。イメージに組み込むと、60日ごとにリビルドして再デプロイする必要があります。常に証明書はボリュームまたはシークレットとしてマウントしてください。

ポート80の公開を忘れる

ポート80は以下のために必要です:

  • HTTP → HTTPSリダイレクト
  • Let’s Encrypt HTTP-01チャレンジ(Traefik/Caddyの自動更新用)
ports:
  - "80:80"    # これを忘れないでください
  - "443:443"

ACMEデータの永続化を忘れる

TraefikとCaddyはLet’s Encryptの証明書とアカウントキーをボリュームに保存します。永続化しないと、コンテナの再起動のたびに証明書を再リクエストし、レート制限に達してしまいます:

volumes:
  traefik-acme:    # 匿名ボリュームではなく、名前付きボリュームにする必要があります
  caddy-data:

よくある質問

アプリコンテナで直接SSLを処理できますか?

技術的には可能ですが、推奨されません。リバースプロキシパターン(エッジでTLSを終端し、内部では平文のHTTPを転送)は標準的な手法です。理由は以下の通りです:アプリが証明書を意識する必要がなく、更新時にアプリの再起動が不要で、TLS設定を一元管理できます。

複数コンテナのSSLを扱うにはどうすればいいですか?

TraefikやCaddyでは、各サービスにラベル/設定を追加するだけで、自動的に個別の証明書を取得します。Nginxの場合は、設定に複数のserverブロックを追加してください。

GetHTTPSとTraefikの組み込みACME、どちらを使うべきですか?

本番環境ではTraefik/Caddyの組み込みACMEを使用してください。自動で更新を処理します。GetHTTPSは、Nginxリバースプロキシアプローチ(アプローチ1)の証明書が必要な場合や、コンテナがACMEチャレンジのために直接インターネットアクセスできない環境で使用してください。

Dockerで証明書を安全にマウントするにはどうすればいいですか?

読み取り専用(:ro)でマウントし、Swarmモードでは秘密鍵にDockerシークレットを使用し、リバースプロキシコンテナのみが証明書ファイルにアクセスできるようにしてください。証明書をDockerイメージに組み込まないでください。有効期限が切れるたびにリビルドが必要になります。

GetHTTPSの証明書をKubernetesで使用できますか?

はい。GetHTTPSの証明書ファイルからKubernetes TLSシークレットを作成します:

kubectl create secret tls my-tls-cert --cert=fullchain.pem --key=privkey.pem

その後、Ingressリソースで参照してください。Kubernetesでの自動更新には、Let’s Encrypt ClusterIssuerを使用したcert-managerを検討してください。

関連記事

デプロイ 2026-05-08
NginxにSSL証明書をインストールする方法
NginxにSSL証明書をインストールするステップバイステップガイド。ファイルアップロード、完全なサーバーブロック設定、TLSベストプラクティス、HTTP/2、HSTS、リダイレクト設定、テスト、6つの一般的なエラーのトラブルシューティングを解説します。
はじめに 2026-05-08
無料SSL証明書の取得方法(ステップバイステップガイド)
Let's Encryptから5分で無料のSSL証明書を取得。ソフトウェアのインストール不要、アカウント作成不要。4つの方法、両方のチャレンジタイプ、6つのプラットフォームへのインストール、トラブルシューティングを網羅した完全ガイドです。
比較 2026-05-07
ブラウザベース vs CLI ACMEクライアント
ブラウザベースのACMEクライアント(GetHTTPSなど)とCLIツール(Certbot、acme.sh)を比較。プライバシー、自動化、ユースケースのトレードオフを解説します。
ブラウザで無料 SSL 証明書を取得
インストール不要、アカウント不要。秘密鍵は常にデバイスに残ります。
証明書を取得