DockerとNginxでSSLを設定する方法 | HTTPS化手順

はい、承知いたしました。DockerとNginxを使用してウェブサイトをHTTPS化するための詳細な手順を含む記事を作成します。約5000語の要件を満たすため、各ステップ、設定オプション、背景知識について可能な限り詳細に記述します。


DockerとNginxでSSLを設定する方法 | HTTPS化手順の詳細ガイド

はじめに

現代において、ウェブサイトのHTTPS化はもはや必須と言えるでしょう。HTTPSは、ブラウザとサーバー間の通信を暗号化することで、データの盗聴や改ざんを防ぎ、ユーザーに安全な体験を提供します。Googleなどの検索エンジンもHTTPS化されたサイトを優遇しており、SEOの観点からも非常に重要です。また、多くの新しいブラウザ機能(例えばService Worker、HTTP/2など)はHTTPS環境でのみ利用可能です。

この記事では、コンテナ技術のデファクトスタンダードであるDockerと、高性能なウェブサーバー・リバースプロキシであるNginxを組み合わせ、無料で信頼性の高いSSL/TLS証明書を提供するLet’s Encryptを利用して、ウェブサイトをHTTPS化する手順を詳細に解説します。

Dockerを使うことで、環境構築の手間を省き、アプリケーションとその依存関係を分離できます。Nginxは高速かつ柔軟な設定が可能であり、ウェブサーバーとしてもリバースプロキシとしても機能します。Let’s Encryptは、Certbotというツールを通じて証明書の発行と更新を自動化できるため、運用負担を大幅に軽減できます。

本記事は、以下のような方を対象としています。

  • Dockerの基本的な使い方を知っている方
  • Nginxの基本的な設定に触れたことがある方
  • 自身のウェブサイトをDockerコンテナで運用したい方
  • ウェブサイトのHTTPS化に興味がある方
  • Let’s Encryptを使った証明書取得・更新方法を知りたい方

この記事を通じて、Dockerコンテナ環境で安全かつ効率的にウェブサイトをHTTPS化する技術を習得できることを目指します。

前提知識

本記事の手順を進めるにあたり、以下の基本的な概念について理解しておくとスムーズです。

  • Docker: アプリケーションとその依存関係をコンテナと呼ばれる軽量な実行環境にパッケージ化する技術です。コンテナは、ホストOSから隔離された独立した環境を提供し、開発・実行環境の差異による問題を減らします。Docker Imageはコンテナの設計図であり、Docker Containerはその実行インスタンスです。Volumeはコンテナの永続的なデータをホストマシンや別のストレージに保存するための仕組みです。
  • Docker Compose: 複数のDockerコンテナで構成されるアプリケーションを定義し、管理するためのツールです。YAMLファイル (docker-compose.yml) にサービスの定義(どのイメージを使うか、どのポートを開けるか、どのボリュームをマウントするかなど)を記述することで、コマンド一つでアプリケーション全体を起動、停止、管理できます。
  • Nginx: 高性能なオープンソースのHTTPおよびリバースプロキシサーバーです。静的ファイルの配信、ロードバランシング、SSL/TLS終端など、様々な用途で利用されます。設定ファイル (nginx.confなど) にディレクティブを記述して動作を制御します。
  • SSL/TLS: Secure Sockets Layer (SSL) および Transport Layer Security (TLS) は、インターネット上でデータを安全に送受信するための暗号化プロトコルです。現在ではTLSが主流ですが、一般的にSSL/TLSまたは単にSSLと呼ばれます。
  • SSL/TLS 証明書: 通信相手のサーバーの身元を証明するための電子証明書です。認証局 (CA) と呼ばれる第三者機関によって発行されます。ブラウザはCAの公開鍵を使って証明書の署名を検証し、信頼できる証明書であることを確認します。Let’s Encryptは無料で利用できるCAです。
  • DNS (Domain Name System): インターネット上のドメイン名 (例: example.com) をIPアドレス (例: 192.168.1.1) に変換するシステムです。ウェブサイトにドメイン名でアクセスするためには、そのドメイン名に対応するIPアドレスが正確にDNSに登録されている必要があります(Aレコードなど)。
  • ポート (Port): ネットワーク通信において、アプリケーションを識別するための番号です。HTTP通信には通常ポート80が、HTTPS通信には通常ポート443が使用されます。
  • ファイアウォール: ネットワークの境界に設置され、事前に定義されたルールに基づいて通信を許可または拒否するシステムです。ウェブサーバーを公開するには、ポート80と443を外部からのアクセスに対して開ける必要があります。

HTTPS化のアプローチ選択

DockerとNginxでHTTPSを構成する場合、いくつかの方法が考えられます。それぞれの方法にはメリットとデメリットがあります。

  1. Nginxコンテナ内で証明書を管理・更新する:
    • 概要: Nginxコンテナ内にCertbotなどの証明書取得・更新ツールをインストールし、コンテナ内で証明書の発行と更新を行います。
    • メリット: 構成がシンプルになる可能性があります。Nginxと証明書管理が同じコンテナにまとまります。
    • デメリット: Nginxコンテナイメージをカスタマイズする必要がある場合があります。証明書更新のためにNginxコンテナを再起動またはリロードする必要があり、更新処理がNginxの運用と密接に結合します。コンテナ内でCronなどを設定して定期実行する必要があります。
  2. 別コンテナ(Certbotなど)で証明書を取得・更新し、Nginxコンテナにマウントする:
    • 概要: Certbot専用のコンテナを別途用意し、そのコンテナで証明書を取得・更新します。取得した証明書ファイルは、Docker Volumeを使ってNginxコンテナと共有します。
    • メリット: Nginxコンテナと証明書管理コンテナが分離されるため、それぞれの役割が明確になり、管理が容易になります。Nginxコンテナは標準的なイメージを利用できます。証明書更新のためにCertbotコンテナを起動するだけで済みます(更新後にNginxのリロードは必要)。
    • デメリット: Docker Composeファイルに複数のサービスを定義する必要があります。Volumeの設定が重要になります。
  3. リバースプロキシとしてNginxを使用し、バックエンドのアプリケーションコンテナと連携させる:
    • 概要: 前述のいずれかの方法(通常は2)でHTTPSを受け付けるNginxコンテナを用意し、そのNginxコンテナがバックエンドで動作する別のアプリケーションコンテナ(例: Node.jsアプリ、Pythonアプリ、PHPアプリなど)にHTTPでトラフィックを転送します。HTTPS通信はNginxコンテナで終端されます。
    • メリット: アプリケーションコンテナはHTTPSに対応する必要がなく、シンプルなHTTPサーバーとして動作させることができます。SSL証明書の管理はNginxコンテナに集約されます。
    • デメリット: 構成が少し複雑になります(複数のコンテナ、ネットワーク設定)。

本記事では、最も一般的で推奨されるアプローチである「別コンテナ(Certbot)で証明書を取得・更新し、Nginxコンテナにマウントする」方法を中心に解説します。この方法は、コンテナの責務を分離し、管理性と柔軟性に優れています。バックエンドにアプリケーションがある場合は、Nginxをリバースプロキシとして設定する応用例も示します。

必要なものと環境構築

本手順を進めるには、以下のものが必要です。

  • Docker および Docker Compose がインストールされた環境: サーバーOSとしては、UbuntuやCentOSなどのLinuxディストリビューションが推奨されますが、開発環境であればmacOSやWindowsでも基本的な手順は同様です。Dockerの公式ドキュメントを参照してインストールしてください。
  • ドメイン名: HTTPS化したいウェブサイトのドメイン名が必要です (例: your_domain.com)。
  • ドメインのDNS設定へのアクセス権: ドメインのDNSレコード(特にAレコード)を編集できる権限が必要です。ドメインがサーバーのグローバルIPアドレスを指すように設定します。
  • サーバーのグローバルIPアドレス: ウェブサイトを公開するサーバーの固定グローバルIPアドレスが必要です。
  • ファイアウォール設定: サーバーのファイアウォールで、外部からのTCPポート80 (HTTP) とポート443 (HTTPS) へのアクセスが許可されている必要があります。
    • 例 (UFW on Ubuntu): sudo ufw allow 80/tcp, sudo ufw allow 443/tcp, sudo ufw enable

これらの準備が整っていることを確認してください。特にDNS設定は、AレコードがサーバーのIPアドレスを正しく指し、その変更がインターネット全体に反映されるまで時間がかかる場合があります(DNS伝播)。Certbotはドメイン名を使ってサーバーのIPアドレスを特定し、そのサーバーに対してチャレンジ(認証)を行いますので、DNS設定が完了し反映されていることが必須です。

実践: Let’s EncryptとCertbot/NginxでのHTTPS化

それでは、具体的な手順に入ります。

ステップ1: プロジェクトディレクトリの準備

まず、プロジェクトのルートとなるディレクトリを作成します。このディレクトリ内に、Nginxの設定ファイル、Docker Composeファイル、Certbotが生成する証明書や検証用ファイルなどを配置します。

“`bash
mkdir my-web-app
cd my-web-app

Nginxの設定ファイルを置くディレクトリ

mkdir nginx

Certbotが証明書や検証用ファイルを保存するディレクトリ

Docker Volumeとして利用するため、ホスト側に作成しておく

mkdir -p data/certbot/conf
mkdir -p data/certbot/www
“`

作成されるディレクトリ構造は以下のようになります。

my-web-app/
├── docker-compose.yml
├── nginx/
│ └── nginx.conf
└── data/
└── certbot/
├── conf/ # Certbotが生成する証明書などが保存される
└── www/ # Certbotがドメイン所有権を検証するためのファイルを一時的に置く場所 (.well-known)

data/certbot ディレクトリは、NginxコンテナとCertbotコンテナの両方からVolumeとしてマウントされます。これにより、Certbotが生成した証明書をNginxが読み込めるようになります。

ステップ2: Nginxの設定ファイル作成 (nginx/nginx.conf)

次に、Nginxの設定ファイルを作成します。このファイルは、HTTP (ポート80) でのリクエストを受け付け、Let’s Encryptのドメイン認証用ファイル (.well-known/acme-challenge) へのアクセスを許可し、それ以外のHTTPリクエストをHTTPS (ポート443) へリダイレクトするように設定します。また、HTTPSの設定も記述しますが、最初はダミーの証明書パスなどを指定しておき、後からCertbotで取得した正規のパスに修正します。

nginx/nginx.conf ファイルを作成し、以下の内容を記述します。

“`nginx

nginx.conf の内容

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log info;
pid /run/nginx.pid;

Load dynamic modules. See /usr/share/nginx/README.dynamic.

include /usr/share/nginx/modules/*.conf;

events {
worker_connections 1024;
}

http {
log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent” “$http_x_forwarded_for”‘;

access_log  /var/log/nginx/access.log  main;

sendfile            on;
tcp_nopush          on;
tcp_nodelay         on;
keepalive_timeout   65;
types_hash_max_size 2048;

include             /etc/nginx/mime.types;
default_type        application/octet-stream;

# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;

# HTTP設定 (ポート80)
server {
    listen 80;
    listen [::]:80; # IPv6 も listen する場合
    server_name your_domain.com www.your_domain.com; # ここをあなたのドメイン名に置き換えてください

    # Let's Encryptによるドメイン所有権の検証 (.well-known/acme-challenge/)
    # Certbotがここに一時ファイルを配置し、Let's Encryptのサーバーがここへアクセスします。
    location /.well-known/acme-challenge/ {
        root /var/www/certbot; # docker-compose.yml で設定する Certbot の検証用ディレクトリへのパス
    }

    # その他のHTTPリクエストはHTTPSにリダイレクト
    # Certbotでの証明書取得中は、このリダイレクトは一時的にコメントアウトまたは無効化します。
    # 取得後は有効に戻すか、HTTPS設定を有効にする際に記述します。
    # 今回はHTTPS設定を記述し、最初は証明書がなくても起動する前提で進めるため、
    # HTTP→HTTPSリダイレクトはHTTPS設定側に記述します。
    # ここでは、証明書取得のために.well-known以外のアクセスをブロックしないようにします。
}

# HTTPS設定 (ポート443)
server {
    listen 443 ssl;
    listen [::]:443 ssl; # IPv6 も listen する場合
    server_name your_domain.com www.your_domain.com; # ここをあなたのドメイン名に置き換えてください

    # ★★★ 証明書と秘密鍵のパスを設定 ★★★
    # Certbotで証明書を取得後、このパスを正規のパスに修正します。
    # 取得前はダミーのパスを指定しておきます。
    # 例: ダミーファイルでも良いですし、Certbotが生成するパスを先に指定しておいても構いませんが、
    # ファイルが存在しないとNginx起動時にエラーになるので注意が必要です。
    # ここでは、Certbotが生成するパスを予め記述しておき、初回起動時はダミーファイルを作成するか、
    # あるいは certbot/conf/live/your_domain.com/ 以下が作成されるのを待つ前提とします。
    # Certbotが証明書を生成するパスは、通常 /etc/letsencrypt/live/your_domain.com/ となります。
    # docker-compose.yml で /data/certbot/conf を /etc/letsencrypt にマウントするため、
    # コンテナ内のパスは /etc/letsencrypt/live/your_domain.com/ となります。
    ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem; # フルチェイン証明書
    ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem; # 秘密鍵

    # ★★★ 推奨SSL設定 ★★★
    ssl_protocols TLSv1.2 TLSv1.3; # 安全なプロトコルのみを有効化 (TLSv1.0, TLSv1.1 は非推奨)
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384'; # 安全な暗号スイートを選択
    ssl_prefer_server_ciphers off; # クライアントよりもサーバー側の暗号スイートの優先度を低く設定(通常はoffが推奨される)
    ssl_session_cache shared:SSL:10m; # SSLセッションキャッシュの設定
    ssl_session_timeout 10m; # セッションタイムアウト時間
    ssl_session_tickets off; # セッションチケット無効化 (forward secrecyのために推奨)

    # OCSP Stapling の有効化 (証明書の失効情報をNginxがキャッシュしてクライアントに提供)
    # DNSリゾルバが必要
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s; # Google Public DNSなどを指定
    resolver_timeout 5s;

    # Strict-Transport-Security (HSTS) ヘッダーの追加
    # 初回アクセス時にブラウザにHTTPSでのアクセスを強制させる (設定ミスに注意)
    # `includeSubDomains` はサブドメインにも適用する場合
    # `preload` はHSTS Preload Listに登録する場合 (初回アクセスから強制したい場合)
    # https://hstspreload.org/ でサイトを申請
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";

    # その他セキュリティヘッダー (任意だが推奨)
    add_header X-Frame-Options DENY; # クリックジャッキング対策
    add_header X-Content-Type-Options nosniff; # MIMEタイプ推測対策

    # HTTPからHTTPSへのリダイレクト (ポート80のserverブロックではなくこちらに記述する場合)
    # ポート80のserverブロックで /.well-known/ は処理しつつ、それ以外をリダイレクトするのが一般的
    # ここでは単にHTTPSのデフォルト設定として記述
    # error_page 497 https://$host:$server_port$request_uri; # 非SSLポートへのHTTPSリクエストをHTTPSへリダイレクト (nginx 1.15.0以降は不要)

    # ウェブサイトのコンテンツルート
    # ここはあなたのアプリケーションや静的ファイルがある場所を指定します。
    # 例: 静的ファイルを配信する場合
    # root /usr/share/nginx/html;
    # index index.html index.htm;

    # 例: バックエンドのアプリケーションコンテナへリバースプロキシする場合
    # location / {
    #     proxy_pass http://your_backend_service_name:port; # your_backend_service_name は docker-compose.yml で定義したサービス名
    #     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;
    # }

    # デフォルトの静的ページ (リバースプロキシを使わない場合)
    location / {
        root /usr/share/nginx/html; # Nginxコンテナ内のデフォルトのドキュメントルート
        index index.html index.htm;
        try_files $uri $uri/ =404; # ファイルが存在しない場合は404
    }
}

# HTTPからHTTPSへのリダイレクトを、HTTPS設定とは別にポート80のserverブロックに記述する方法
# 上記HTTP設定の server ブロックに以下を追加する
# location / {
#     return 301 https://$host$request_uri;
# }
# これにより、Certbotの検証パス以外のHTTPリクエストはすべてHTTPSにリダイレクトされるようになります。

}
“`

重要な注意点:

  • server_nameyour_domain.com www.your_domain.com は、必ずあなたのドメイン名に置き換えてください。Let’s Encryptは指定されたドメイン名に対して証明書を発行します。
  • ssl_certificatessl_certificate_key のパスは、Certbotが生成する証明書のパスです。初回 Certbot 実行前にこれらのファイルは存在しません。ファイルが存在しない状態でNginxを起動するとエラーになるため、Certbot実行前にダミーファイルを作成しておくか、Certbot実行後にNginxを起動する手順を踏む必要があります。より簡単なのは、最初はHTTPS設定をコメントアウトしておき、証明書取得後にコメントアウトを解除して再起動する方法です。今回は、設定ファイルには記述しておき、Certbot実行後にNginxを再起動する流れで進めます。
  • /etc/letsencrypt/live/your_domain.com/ は、Docker ComposeでVolumeマウントする際にホスト側の ./data/certbot/conf/live/your_domain.com/ に対応します。
  • .well-known/acme-challengeroot /var/www/certbot; は、CertbotコンテナとNginxコンテナで共有するボリュームのパスと一致させる必要があります。これはCertbotが認証ファイルを書き込む場所です。
  • ssl_protocols, ssl_ciphers, add_header Strict-Transport-Security などのSSL設定は、セキュリティ強度に直結する重要な設定です。上記の例は推奨設定ですが、最新のセキュリティ情報に合わせて適宜見直してください。Mozilla SSL Configuration Generatorなどのツールも参考になります。
  • リバースプロキシとして使用する場合は、location / ブロック内の proxy_pass 設定を適切に行ってください。your_backend_service_name は、後述する docker-compose.yml で定義するアプリケーションサービスの名称です。

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

次に、NginxサービスとCertbotサービスを定義する docker-compose.yml ファイルを作成します。

docker-compose.yml ファイルを作成し、以下の内容を記述します。

“`yaml

docker-compose.yml の内容

version: ‘3.8’

services:
nginx:
image: nginx:latest # 最新のNginxイメージを使用
ports:
– “80:80” # HTTP ポートをホストの80番ポートにマッピング
– “443:443” # HTTPS ポートをホストの443番ポートにマッピング
volumes:
# Nginxコンテナの設定ファイルをホスト側の設定ファイルで上書き
– ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro # ro は読み取り専用 (Read-Only)
# Certbotが生成した証明書をNginxコンテナから参照できるようにマウント
# ホスト側の ./data/certbot/conf が コンテナ内の /etc/letsencrypt に対応
– ./data/certbot/conf:/etc/letsencrypt:ro
# Certbotがドメイン認証で使用するディレクトリをマウント
# ホスト側の ./data/certbot/www が コンテナ内の /var/www/certbot に対応
# このディレクトリは Nginx の .well-known/acme-challenge の root と一致させる
– ./data/certbot/www:/var/www/certbot:ro
# Nginxのデフォルトのドキュメントルート (index.htmlなどを置く場合)
# 静的ファイルを配信する場合や、リバースプロキシを使わない場合に必要
# デフォルトのNginxイメージに含まれる /usr/share/nginx/html をマウント
# – ./html:/usr/share/nginx/html:ro # 例: ホスト側の ./html に静的ファイルを置く場合
# depends_on: # バックエンドのアプリケーションがある場合、Nginxを後から起動させる
# – your_backend_service_name
restart: always # コンテナが停止した場合に常に再起動

certbot:
image: certbot/certbot # Certbot公式イメージを使用
volumes:
# Nginxと共有するディレクトリをマウント
# Certbotはこのディレクトリに証明書などを書き込む
– ./data/certbot/conf:/etc/letsencrypt
# Certbotはこのディレクトリを使ってドメイン認証を行う
– ./data/certbot/www:/var/www/certbot
# command: “certonly –webroot –webroot-path /var/www/certbot -d your_domain.com -d www.your_domain.com –email [email protected] –agree-tos –no-eff-email –staging” # 初回取得コマンド (後で docker-compose run で実行)
# command: “renew” # 更新コマンド (後で cron などで定期実行)
# Certbotコンテナ自体は通常起動させておく必要はありません。
# 証明書取得時や更新時に一時的に起動してコマンドを実行する用途で利用します。
# そのため、ports マッピングや restart: always は不要です。
# 認証時にNginxが動作している必要があるため、depends_on を指定する場合もありますが、
# 手動実行の場合は意識しなくてOKです。

名前付きボリュームを使用する場合 (オプション)

volumes:

certbot_conf:

certbot_www:

services:

nginx:

volumes:

– ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro

– certbot_conf:/etc/letsencrypt:ro

– certbot_www:/var/www/certbot:ro

certbot:

volumes:

– certbot_conf:/etc/letsencrypt

– certbot_www:/var/www/certbot

“`

重要な注意点:

  • nginx サービスの volumes 設定は非常に重要です。
    • ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro: ホスト側の設定ファイルをコンテナ内のNginxのメイン設定ファイルにマウントします。:ro は読み取り専用でマウントすることを意味し、コンテナからの誤った変更を防ぎます。
    • ./data/certbot/conf:/etc/letsencrypt:ro: Certbotが証明書を保存するディレクトリを、Nginxが証明書を参照する /etc/letsencrypt にマウントします。:ro は読み取り専用でマウントすることを意味します。
    • ./data/certbot/www:/var/www/certbot:ro: Certbotがドメイン認証で使用するディレクトリを、Nginxが .well-known からアクセスできるようにマウントします。:ro は読み取り専用でマウントすることを意味します。
  • certbot サービスの volumes 設定は、Nginxサービスと同じホスト側のディレクトリをマウントしますが、Certbotはファイルを作成・更新する必要があるため、:ro オプションは付けません
  • certbot サービスの command は、証明書取得や更新のコマンドを指定しますが、docker-compose up -d certbot のようにサービスとして永続的に起動するのではなく、docker-compose run --rm certbot <command> のように一時的にコンテナを起動してコマンドを実行するために使用します。そのため、docker-compose.yml にはコメントアウトしておくか、空にしておいても構いません。
  • ports マッピングは、ホスト側のポートとコンテナ内のポートを関連付けます。ホスト側の80/443ポートが、Nginxコンテナの80/443ポートに転送されるように設定します。

ステップ4: NginxをHTTPで起動 (Certbot認証用)

Certbotがドメイン所有権を証明するために、ウェブサイトの .well-known/acme-challenge パスから特定のファイルを取得できる必要があります。この認証は通常HTTP (ポート80) で行われます。そのため、HTTPS化を完了させる前に、まずはNginxをポート80で起動し、.well-known パスへのアクセスを許可しておく必要があります。

HTTPS設定 (nginx/nginx.conflisten 443 ssl 側の server ブロック) は、証明書ファイルが存在しないため、この時点ではエラーになる可能性があります。設定ファイルにダミーパスを指定している場合でも、ファイルが存在しないことによる起動エラーを避けるため、一時的にこのHTTPS設定ブロックをコメントアウトしておくのが最も確実です。

nginx/nginx.conf を編集し、HTTPS設定の server ブロック全体をコメントアウトします。

“`nginx

… (省略) …

# HTTP設定 (ポート80)
server {
    listen 80;
    listen [::]:80;
    server_name your_domain.com www.your_domain.com;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    # 仮のルート設定 (Certbot認証用)
    # ここをあなたのアプリケーションや静的ファイルのルートに合わせる必要があります
    # Certbot認証中は、.well-known以外のアクセスはリダイレクトせず、一旦デフォルトのページなどを表示させておきます
    location / {
         root /usr/share/nginx/html; # Nginxコンテナ内のデフォルトのドキュメントルート (存在しなくてもNginxは起動します)
         index index.html;
    }

    # HTTPからHTTPSへのリダイレクトは、証明書取得後に有効化
    # location / {
    #     return 301 https://$host$request_uri;
    # }
}

# ★★★ HTTPS設定 (ポート443) - Certbot証明書取得前はコメントアウト ★★★
# server {
#     listen 443 ssl;
#     listen [::]:443 ssl;
#     server_name your_domain.com www.your_domain.com;
#     ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
#     ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;
#     # ... その他のSSL設定 ...
#
#     # ここにアプリケーションや静的ファイルのルートを設定
#     # location / { ... }
# }

… (省略) …

“`

HTTPS設定ブロックをコメントアウトしたら、Nginxコンテナを起動します。

bash
docker-compose up -d nginx

docker ps コマンドでNginxコンテナが Up 状態になっていることを確認してください。
この時点で、ブラウザから http://your_domain.com にアクセスできるはずです(デフォルトのNginxページが表示されることが多いです)。.well-known/acme-challenge/test.txt のようなパスにファイルを作成し、ホスト側の ./data/certbot/www/test.txt にそのファイルを置いて、ブラウザからアクセスできるか確認すると、.well-known へのアクセスが正しくNginxコンテナの /var/www/certbot にマッピングされているか確認できます。

ステップ5: Certbotでの証明書取得

NginxがHTTPでポート80をリッスンしており、.well-known パスへのアクセスが /var/www/certbot ディレクトリにマッピングされていることを確認したら、Certbotを実行して証明書を取得します。

以下のコマンドをプロジェクトルートディレクトリ (my-web-app/) で実行します。

bash
docker-compose run --rm certbot certonly --webroot --webroot-path /var/www/certbot -d your_domain.com -d www.your_domain.com --email [email protected] --agree-tos --no-eff-email --staging

コマンドの詳細説明:

  • docker-compose run --rm certbot: docker-compose.yml で定義された certbot サービスを一時的に起動し、指定されたコマンドを実行します。--rm オプションは、コマンド実行後にコンテナを自動的に削除します。
  • certonly: 証明書の取得のみを行い、Nginxなどのウェブサーバーの設定変更は行いません(設定変更は手動で行います)。
  • --webroot: Webroot認証方式を使用します。これは、指定された --webroot-path にCertbotが一時ファイルを作成し、Let’s EncryptのサーバーがそのファイルをHTTP経由で取得してドメイン所有権を検証する方式です。Nginxの .well-known 設定と連携します。
  • --webroot-path /var/www/certbot: Webroot認証で使用するディレクトリを、Certbotコンテナ内の /var/www/certbot に指定します。これは docker-compose.yml でNginxと共有するためにマウントしたディレクトリです。
  • -d your_domain.com -d www.your_domain.com: 証明書を発行したいドメイン名を指定します。複数のドメイン名を指定することで、1つの証明書に複数のドメインを含めることができます(SAN証明書)。あなたのドメイン名に置き換えてください
  • --email [email protected]: 有効期限切れの通知などを受け取るメールアドレスを指定します。あなたのメールアドレスに置き換えてください
  • --agree-tos: Let’s Encryptの利用規約に同意します。
  • --no-eff-email: EFF (Electronic Frontier Foundation) とのメール共有を拒否します。任意ですが、通知だけ欲しい場合は指定します。
  • --staging: 最初は必ずこのオプションを付けてテスト実行することを強く推奨します。これは本番環境ではなくステージング環境で証明書を取得するオプションです。Let’s Encryptには証明書の発行に関するレートリミットがあり、テスト中にリミットに達してしまう可能性があります。ステージング環境での取得はレートリミットにカウントされません。テストが成功したら、このオプションを外して再度コマンドを実行し、本番の証明書を取得してください。

コマンドを実行すると、Certbotは対話形式で情報の入力を求める場合があります(メールアドレスの確認、利用規約への同意など)。指示に従って進めてください。

コマンドが成功すると、以下のような出力が表示されます。

“`
IMPORTANT NOTES:
– Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/your_domain.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/your_domain.com/privkey.pem
Your certificate will expire on 20XX-XX-XX. To obtain a new or
tweaked version of this certificate in the future, simply run
certbot again. To non-interactively renew all of your certificates,
run “certbot renew”
– If you like Certbot, consider supporting our work by:

Donating to EFF: https://eff.org/certbot/donate
Donating to ISRG / Let’s Encrypt: https://letsencrypt.org/donate/
“`

この出力に示されているパス (/etc/letsencrypt/live/your_domain.com/fullchain.pem, /etc/letsencrypt/live/your_domain.com/privkey.pem) が、Certbotコンテナ内で証明書が保存された場所です。このパスは、docker-compose.yml のボリュームマウント設定により、ホスト側の ./data/certbot/conf/live/your_domain.com/ ディレクトリに対応します。

ホスト側の ./data/certbot/conf/live/your_domain.com/ ディレクトリ内に、fullchain.pem, privkey.pem, chain.pem, cert.pem などのファイルが生成されていることを確認してください。

ステージング環境でのテストが成功したら、必ず --staging オプションを外して、本番環境の証明書を取得し直してください

bash
docker-compose run --rm certbot certonly --webroot --webroot-path /var/www/certbot -d your_domain.com -d www.your_domain.com --email [email protected] --agree-tos --no-eff-email

本番証明書が正常に取得されると、ホスト側の ./data/certbot/conf/live/your_domain.com/ ディレクトリ内のファイルが更新されます。

ステップ6: Nginxの設定更新と再起動

証明書が取得できたら、Nginxの設定ファイル (nginx/nginx.conf) を更新し、HTTPS設定を有効にします。

先ほどコメントアウトしたHTTPS設定の server ブロックのコメントアウトを解除します。そして、ssl_certificatessl_certificate_key のパスが、Certbotが生成した証明書ファイルのパスを正しく指していることを確認します。Certbotが生成するパスは、指定したドメイン名のディレクトリ (your_domain.com) の下に作成されます。

“`nginx

nginx.conf の内容 (HTTPS設定部分)

… (省略) …

# HTTP設定 (ポート80)
server {
    listen 80;
    listen [::]:80;
    server_name your_domain.com www.your_domain.com;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    # ★★★ HTTPからHTTPSへのリダイレクトを有効化 ★★★
    # .well-known 以外の全てのHTTPアクセスをHTTPSへリダイレクトします。
    location / {
         return 301 https://$host$request_uri;
    }
}

# ★★★ HTTPS設定 (ポート443) - コメントアウトを解除 ★★★
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name your_domain.com www.your_domain.com;

    # ★★★ Certbotで取得した正規の証明書パスを指定 ★★★
    # your_domain.com 部分はあなたのドメイン名に置き換えてください
    ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;

    # ★★★ 推奨SSL設定 ★★★ (必要に応じて調整)
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;

    # ★★★ ウェブサイトのコンテンツルートまたはリバースプロキシ設定 ★★★
    # 例: 静的ファイルを配信する場合
    location / {
        root /usr/share/nginx/html; # またはマウントした静的ファイルディレクトリ
        index index.html index.htm;
        try_files $uri $uri/ =404;
    }

    # 例: バックエンドのアプリケーションコンテナへリバースプロキシする場合
    # location / {
    #     proxy_pass http://your_backend_service_name:port;
    #     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;
    # }
}

… (省略) …

“`

設定ファイルを更新したら、Nginxコンテナを再起動して新しい設定を適用します。

“`bash
docker-compose restart nginx

または、一度停止して再起動

docker-compose down

docker-compose up -d nginx

“`

docker ps でNginxコンテナが正常に起動しているか確認します。エラーが発生した場合は、docker logs nginx コマンドでログを確認し、Nginx設定ファイルのエラーや証明書ファイルのパス間違いなどを修正してください。docker-compose exec nginx nginx -t コマンドで、コンテナ内でNginx設定ファイルの構文チェックを行うことも可能です。

ステップ7: HTTPS接続の確認

Nginxコンテナが新しい設定で正常に起動したら、ウェブサイトにHTTPSでアクセスできるか確認します。

  1. ブラウザでの確認: ウェブブラウザを開き、https://your_domain.com にアクセスします。アドレスバーに鍵マークが表示されていれば成功です。鍵マークをクリックすると、証明書の詳細(発行者、有効期限など)を確認できます。また、http://your_domain.com にアクセスした場合に、自動的に https にリダイレクトされることも確認してください。
  2. SSL Server Test (Qualys): Qualys SSL Labsが提供する SSL Server Test は、サーバーのSSL設定を詳細に分析し、セキュリティレベルを評価してくれる非常に有用なツールです。あなたのドメイン名を入力してテストを実行し、設定が適切か、脆弱性がないかなどを確認することを強く推奨します。目標はA+またはA評価です。

これで、DockerとNginx、Certbotを使ってウェブサイトをHTTPS化する基本的な手順は完了です。

証明書の自動更新設定

Let’s Encryptの証明書は有効期限が90日間です。手動で更新することも可能ですが、有効期限切れを防ぐために自動更新を設定するのが一般的です。Certbotは証明書の更新機能 (certbot renew) を持っており、これを定期的に実行するように設定します。

Certbotコンテナは、証明書更新時にもWebroot認証を使用するため、更新時にもNginxが稼働しており、.well-known パスへのアクセスが /var/www/certbot にマッピングされている必要があります。

証明書を自動更新するための方法はいくつか考えられますが、ここではホスト側のCronまたはSystemd timerを使って、Certbotコンテナを定期的に起動して更新コマンドを実行する方法を推奨します。

方法: Cron または Systemd Timer を使用する

ホスト側で、週に一度など定期的に実行されるタスクとして、以下のコマンドを登録します。

bash
docker-compose run --rm certbot renew --webroot -w /var/www/certbot --post-hook "docker-compose exec nginx nginx -s reload"

コマンドの詳細説明:

  • docker-compose run --rm certbot: Certbotコンテナを一時的に起動し、コマンドを実行します。
  • renew: Certbotに既存の証明書の更新を試みさせます。Certbotは有効期限が近い証明書(通常30日以内)のみを更新します。
  • --webroot -w /var/www/certbot: 更新時にもWebroot認証方式を使用し、そのパスを指定します。
  • --post-hook "docker-compose exec nginx nginx -s reload": 証明書の更新に成功した場合に実行されるフックコマンドです。docker-compose exec nginx nginx -s reload は、稼働中のNginxコンテナ内で nginx -s reload コマンドを実行し、Nginxの設定をリロードして新しい証明書を適用します。これにより、Nginxを停止することなく証明書を更新できます。

Cronでの設定例:

LinuxサーバーでCronを使用する場合、crontab -e コマンドでcrontabエディタを開き、以下の行を追加します。

“`crontab

毎週日曜日の午前3時30分に証明書更新を試みる

30 3 * * 0 cd /path/to/your/my-web-app && docker-compose run –rm certbot renew –webroot -w /var/www/certbot –post-hook “docker-compose exec nginx nginx -s reload” >> /var/log/certbot-renewal.log 2>&1
“`

/path/to/your/my-web-app は、docker-compose.yml ファイルが置かれているディレクトリの絶対パスに置き換えてください。ログ出力をリダイレクトしておくと、更新の成功・失敗を確認できます。

Systemd Timerでの設定例:

現代のLinuxシステムでは、CronよりもSystemd timerが推奨される場合があります。Systemd timerを使用する場合は、.service ファイルと .timer ファイルを作成します。

例: /etc/systemd/system/certbot-renewal.service

“`ini
[Unit]
Description=Certbot Renewal

[Service]
Type=oneshot
WorkingDirectory=/path/to/your/my-web-app # docker-compose.yml があるディレクトリ
ExecStart=/usr/local/bin/docker-compose run –rm certbot renew –webroot -w /var/www/certbot –post-hook “docker-compose exec nginx nginx -s reload”

Docker Compose コマンドのパスは環境によって異なる場合があります (/usr/bin/docker-compose など)

“`

例: /etc/systemd/system/certbot-renewal.timer

“`ini
[Unit]
Description=Run Certbot Renewal Weekly

[Timer]
OnCalendar=weekly
AccuracySec=1h # 多少のずれを許容する
Persistent=true # サービス実行中にシステムが停止した場合、起動後に実行する

[Install]
WantedBy=timers.target
“`

ファイルを保存したら、Systemdデーモンをリロードし、タイマーを有効化・開始します。

bash
sudo systemctl daemon-reload
sudo systemctl enable certbot-renewal.timer
sudo systemctl start certbot-renewal.timer

sudo systemctl list-timers でタイマーが登録されているか確認できます。

更新テスト:

自動更新設定が正しく動作するか確認するには、--dry-run オプション付きで更新コマンドを実行します。

bash
docker-compose run --rm certbot renew --dry-run --webroot -w /var/www/certbot --post-hook "echo 'Reload command would be executed here.'"

このコマンドは実際に証明書を更新するわけではなく、更新プロセスをシミュレーションします。エラーが出力されなければ、設定は概ね正しいと考えられます。--post-hook にはダミーのコマンドを指定しています。

高度な設定と応用

HTTP/2 の有効化

HTTP/2は、HTTP/1.1に比べてパフォーマンスが向上した新しいプロトコルです。HTTPS環境でのみ利用可能です。NginxでHTTP/2を有効化するには、HTTPS設定の listen ディレクティブに http2 パラメータを追加するだけです。

nginx
server {
listen 443 ssl http2; # http2 を追加
listen [::]:443 ssl http2; # IPv6 も http2 を追加
# ... その他の設定 ...
}

設定変更後はNginxコンテナを再起動またはリロードしてください。

リバースプロキシとして他のコンテナへルーティング

Nginxをリバースプロキシとして利用し、バックエンドで稼働する別のアプリケーションコンテナにリクエストを転送する場合、HTTPS設定の server ブロック内の location ディレクティブで proxy_pass を使用します。

“`nginx
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name your_domain.com;

ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;

# ... その他のSSL設定 ...

location / {
    # リクエストをバックエンドサービス (Docker Composeで定義したサービス名) へ転送
    # バックエンドサービスは通常、別のコンテナとして同一のDockerネットワーク上で稼働します
    proxy_pass http://your_backend_service_name:8080; # バックエンドサービスのサービス名とポートを指定
    # proxy_pass http://localhost:8080; # バックエンドがホストマシンで動いている場合など (非推奨)

    # バックエンドに正しい情報を引き渡すためのヘッダー設定
    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; # リクエストがHTTPSで来たことをバックエンドに伝える

    # WebSocket通信をサポートする場合
    # proxy_http_version 1.1;
    # proxy_set_header Upgrade $http_upgrade;
    # proxy_set_header Connection "upgrade";
}

# 例: 特定のパスだけ別のバックエンドへルーティング
# location /api/ {
#    proxy_pass http://your_api_service:3000;
#    # ... ヘッダー設定など ...
# }

}
“`

docker-compose.yml では、リバースプロキシされるバックエンドサービスとNginxサービスを同じネットワークに配置する必要があります。デフォルトでは、Docker Composeはサービスを同じユーザー定義ネットワークに配置するため、サービス名をホスト名として利用できます。

“`yaml
version: ‘3.8’

services:
nginx:
image: nginx:latest
ports:
– “80:80”
– “443:443”
volumes:
– ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
– ./data/certbot/conf:/etc/letsencrypt:ro
– ./data/certbot/www:/var/www/certbot:ro
depends_on: # Nginxがバックエンドに依存する場合
– your_backend_service_name
restart: always

certbot:
image: certbot/certbot
volumes:
– ./data/certbot/conf:/etc/letsencrypt
– ./data/certbot/www:/var/www/certbot
# command … (for run command)

your_backend_service_name: # バックエンドサービスの定義
image: your_backend_image # あなたのアプリケーションイメージ
# ports: # バックエンドのポートをホストに公開する必要はない (Nginxからアクセスするため)
# – “8080:8080” # これは外部公開用。Nginxからのアクセスだけなら不要。
expose: # 同一ネットワーク内の他のコンテナにポートを公開
– “8080”
# volumes: …
# environment: …
restart: always

networks: # カスタムネットワークを定義する場合 (オプション)

default:

driver: bridge

“`

複数のドメイン/サブドメインを扱う

1つのNginxインスタンスで複数のドメインやサブドメインのHTTPSを処理する場合、それぞれのドメインに対してCertbotで証明書を取得し、Nginx設定ファイルでそれぞれの server ブロックを定義します。

  • Certbotでの証明書取得: Certbotコマンドで -d オプションを繰り返し指定するか、複数のコマンドを分けて実行します。
    “`bash
    # 1つのコマンドで複数のドメインを取得 (SAN証明書)
    docker-compose run –rm certbot certonly –webroot –webroot-path /var/www/certbot -d example.com -d www.example.com -d blog.example.com –email …

    別のコマンドで別のドメインを取得 (別々の証明書)

    docker-compose run –rm certbot certonly –webroot –webroot-path /var/www/certbot -d another-domain.com –email …
    ``
    Certbotは、指定したドメイン名ごとに
    ./data/certbot/conf/live/以下にディレクトリを作成して証明書を保存します (例:example.com/,another-domain.com/)。
    * **Nginx設定**: 各ドメイン/サブドメインに対して、別々の
    serverブロックを定義します。server_name` ディレクティブでドメイン名を指定し、対応する証明書パスを指定します。

“`nginx

HTTP (ポート80) – 全てのドメインをHTTPSにリダイレクトしつつ .well-known を処理

server {
listen 80;
listen [::]:80;
server_name example.com www.example.com blog.example.com another-domain.com; # 全てのドメイン名をリスト

location /.well-known/acme-challenge/ {
    root /var/www/certbot;
}

# .well-known 以外の全てのHTTPアクセスを、アクセスされたドメイン名に応じてHTTPSへリダイレクト
location / {
    return 301 https://$host$request_uri;
}

}

HTTPS for example.com and www.example.com, blog.example.com

server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com blog.example.com;

# 該当ドメイン名の証明書パスを指定
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

# ... SSL設定、コンテンツルート or proxy_pass ...

}

HTTPS for another-domain.com

server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name another-domain.com;

# 別のドメイン名の証明書パスを指定
ssl_certificate /etc/letsencrypt/live/another-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/another-domain.com/privkey.pem;

# ... SSL設定、コンテンツルート or proxy_pass ...

}
“`

ワイルドカード証明書 (*.your_domain.com) の取得

サブドメインが多い場合、*.your_domain.com のようなワイルドカード証明書が便利です。ワイルドカード証明書を取得するには、Webroot認証ではなくDNSチャレンジが必要です。これは、DNSレコード (TXTレコード) を追加してドメイン所有権を証明する方法です。

DNSチャレンジは、CertbotのDNSプラグイン (certbot-dns-cloudflare, certbot-dns-route53など) を利用するのが一般的です。プラグインを使用する場合、APIキーなどをCertbotコンテナに渡して、Certbotが自動的にDNSレコードを追加・削除できるように設定する必要があります。

DNSチャレンジを使用する場合、Certbotコンテナは一時的にDNS設定を変更できる権限を持つ必要があります。これはセキュリティ上の考慮が必要です。また、DNS伝播に時間がかかる場合があるため、Webroot認証よりも時間がかかることがあります。

DNSチャレンジでのCertbotコマンド例 (Cloudflareプラグインの場合):

bash
docker-compose run --rm certbot certonly --dns-cloudflare --dns-cloudflare-credentials /path/to/cloudflare.ini -d your_domain.com -d *.your_domain.com --email ...

/path/to/cloudflare.ini はAPIキーなどが記述された設定ファイルで、これをCertbotコンテナにボリュームとしてマウントする必要があります。この方法はWebroot認証よりも複雑になるため、詳細はCertbotの公式ドキュメントや各DNSプラグインのドキュメントを参照してください。

トラブルシューティングガイド

手続き中に発生しうる一般的な問題とその解決策を示します。

  • Certbot 実行時のエラー:
    • Timeout during connect (likely firewall problem) または Connection refused:
      • 原因: ポート80または443 (Webroot認証の場合) が外部からアクセスできない。
      • 解決策: サーバーのファイアウォール (UFW, firewalld, iptablesなど) でポート80と443が許可されているか確認します。ルーターやクラウドプロバイダーのセキュリティグループ設定なども確認します。Nginxコンテナのポートマッピング (ports: - "80:80") が正しいか確認します。
    • DNS problem: NXDOMAIN または DNS problem: SERVFAIL:
      • 原因: 指定したドメイン名がサーバーのIPアドレスを正しく指していないか、DNS変更がまだ伝播していない。
      • 解決策: ドメイン名のAレコードがサーバーのグローバルIPアドレスを指しているか、DNS設定を確認します。dig your_domain.com A コマンドなどでDNSレコードを確認できます。DNS伝播には時間がかかることがあるため、しばらく待ってから再度試します。
    • The client lacks sufficient authorization:
      • 原因: Webroot認証で、Certbotが .well-known/acme-challenge/ ディレクトリにファイルを書き込めない、またはLet’s EncryptのサーバーがそのファイルをHTTP経由で取得できない。
      • 解決策:
        • docker-compose.ymlcertbot サービスで ./data/certbot/www:/var/www/certbot が正しくマウントされており、Certbotが書き込める権限があるか確認します(通常はデフォルトでOK)。
        • nginx.conf.well-known/acme-challenge ブロックで root /var/www/certbot; が正しく設定されているか確認します。
        • Nginxがポート80で正常に稼働しており、.well-known へのリクエストが /var/www/certbot にルーティングされているか確認します。Nginxのログ (docker logs nginx) を見て、.well-known へのアクセスが404になっていないか確認します。
        • SELinuxやAppArmorなどのOSレベルのセキュリティ設定がDockerやNginxのアクセスを妨害していないか確認します。
    • Too many certificates already issued:
      • 原因: 短期間に同じドメイン名に対して多くの証明書を発行しすぎ、Let’s Encryptのレートリミットに達した。
      • 解決策: テスト時は必ず --staging オプションを使用します。本番証明書が必要な場合は、レートリミットが解除されるまで待つか、別のドメイン名で試します。レートリミットの詳細はLet’s Encryptのドキュメントを確認してください。
  • Nginx コンテナ起動時のエラー:
    • bind() to 0.0.0.0:80 failed (98: Address already in use):
      • 原因: ホストマシンのポート80が、別のプロセス(他のウェブサーバーなど)によって使用されている。
      • 解決策: どのプロセスがポートを使用しているか特定し (sudo netstat -tulnp | grep 80)、そのプロセスを停止するか、Nginxのポートマッピングを変更します。
    • [emerg] cannot load certificate "/etc/letsencrypt/live/.../fullchain.pem": ...:
      • 原因: Nginx設定ファイルで指定された証明書ファイルまたは秘密鍵ファイルが存在しないか、Nginxコンテナがアクセスする権限がない。
      • 解決策: Certbotで証明書が正しく取得され、ホスト側の ./data/certbot/conf/live/your_domain.com/ ディレクトリにファイルが生成されているか確認します。nginx.conf のパス (ssl_certificate, ssl_certificate_key) が正しいか確認します。docker-compose.ymlnginx サービスの volumes 設定で ./data/certbot/conf:/etc/letsencrypt:ro が正しくマウントされているか確認します。
    • [emerg] invalid parameter "ssl" in ... など、設定ファイルの構文エラー:
      • 原因: nginx.conf ファイルの記述ミス。
      • 解決策: エラーメッセージの行番号を参考に、設定ファイルの記述を修正します。docker-compose exec nginx nginx -t コマンドでコンテナ内で構文チェックを行い、エラーの詳細を確認します。
  • HTTPSに接続できない、ブラウザで証明書エラーが出る:
    • 原因: NginxがHTTPSポート (443) をリッスンしていない、証明書の設定が間違っている、古い証明書を参照しているなど。
    • 解決策:
      • docker ps でNginxコンテナが稼働しており、ポート443がマッピングされているか確認します。
      • nginx.conf のHTTPS設定 (listen 443 ssl;) がコメントアウトされていないか、正しい証明書パスが指定されているか確認します。
      • Nginxコンテナを再起動して、新しい設定と証明書が読み込まれているか確認します。
      • SSL Server Test (Qualys) でサーバーのSSL設定を診断します。
  • HTTPからHTTPSへのリダイレクトがうまくいかない:
    • 原因: HTTP設定の server ブロックにリダイレクト設定が記述されていない、または間違っている。.well-known パス以外もリダイレクト対象に含まれているか確認。
    • 解決策: nginx.conf のポート80の server ブロックの location /return 301 https://$host$request_uri; が正しく記述されているか確認します。.well-known の location ブロックより後や、別の location ブロックに含まれていないか注意します。
  • 証明書の自動更新が失敗する:
    • 原因: Cron/Systemd timerの設定ミス、docker-compose.yml のパス間違い、Certbot実行時のネットワーク問題、Nginxのリロード失敗など。
    • 解決策: Cron/Systemd timerのログ (/var/log/certbot-renewal.log など) を確認します。手動で docker-compose run --rm certbot renew --dry-run ... を実行し、エラーメッセージを確認します。Certbot実行時にNginxが稼働しているか確認します。Nginxのリロードコマンド (docker-compose exec nginx nginx -s reload) が手動で実行できるか試します。

デバッグの際は、関係するコンテナのログ (docker logs <container_name>) を確認することが最も重要です。また、docker-compose exec <service_name> <command> を使って、コンテナ内で直接コマンドを実行し、ファイルシステムや設定を確認することも役立ちます。

まとめ

この記事では、DockerとNginx、Let’s EncryptのCertbotを使用して、ウェブサイトをHTTPS化する詳細な手順を解説しました。

  1. HTTPS化の重要性と、Docker、Nginx、Certbotを組み合わせるメリットを確認しました。
  2. 前提知識として、関連する基本的な技術概念を説明しました。
  3. HTTPS化のアプローチとして、外部CertbotコンテナとVolume共有による方法を選択し、その理由を説明しました。
  4. 手順を進めるための必要なもの環境構築について準備しました。
  5. 実践手順として、以下のステップを詳細に解説しました。
    • プロジェクトディレクトリの準備
    • Nginx設定ファイル (nginx.conf) の作成と、HTTP設定、HTTPS設定、Let’s Encrypt認証用設定の記述
    • Docker Composeファイル (docker-compose.yml) の作成と、Nginx・Certbotサービスの定義、Volumeマウント設定
    • Certbot認証のためにNginxをHTTP設定のみで起動
    • Certbotコンテナを使用して証明書を取得(テスト環境での --staging 実行を推奨)
    • Nginx設定ファイルを更新し、取得した証明書パスを指定してHTTPS設定を有効化
    • Nginxコンテナを再起動して設定を適用
    • ブラウザやSSL Server TestでHTTPS接続とセキュリティ設定を確認
  6. 証明書の自動更新設定として、CronまたはSystemd timerを使ってCertbotコンテナを定期実行する方法と、更新後にNginxをリロードする --post-hook の設定を説明しました。
  7. 応用として、HTTP/2の有効化、リバースプロキシ設定、複数ドメインの扱い方について触れました。
  8. 最後に、手続き中に発生しうるトラブルシューティングのためのガイドを提供しました。

これらの手順を踏むことで、Docker環境で安全かつ自動更新されるHTTPSウェブサイトを構築できます。HTTPS化はウェブサイトの信頼性を高め、訪問者に安心感を与え、SEOにも良い影響を与えます。ぜひこのガイドを参考に、あなたのウェブサイトをHTTPS化してください。

この詳細な手順が、あなたのウェブサイトのセキュリティ向上に役立つことを願っています。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール