Let's Encrypt による SSL 証明書の発行と適用

ここでは Let's Encrypt による SSL 証明書の発行と適用の手順について説明します。

注意: この手順ではインターネットからホストサーバの HTTP 80番ポートにアクセスできる必要がありますので、ご注意ください。

証明書の自動発行のための ACME クライアントとしては、certbot コンテナ を利用します。 なお、certbot の詳細な使い方については本ドキュメントでは省略します。公式ドキュメント を参照してください。

SSL 証明書の発行と適用までの流れは以下のようになります。

  1. 証明書を配置する ssl ディレクトリ配下に letsencrypt というディレクトリを作成して、そこに ACME クライアントである certbot で SSL 証明書の発行を行ないます。
  2. letsencrypt ディレクトリ配下に発行された SSL 証明書ファイルと秘密鍵ファイルを、ssl ディレクトリの server.crtserver.key からシンボリックリンクで参照させるようにします。
  3. これにより、各コンテナは Let's Encrypt より発行された SSL 証明書を適用できることになります。

※ 以降の説明で ${ドメイン名} とある部分は SSL 証明書を発行したい対象のドメイン名 (FQDN) に置き換えてください。

SSL 証明書の新規発行

ホストサーバ上で各コンテナが停止している状態で、以下のように certbot を用いてスタンドアローンモードで証明書を発行します。

$ docker run -it --rm -p 80:80 \
  -v "$(readlink -m ../../../ssl/letsencrypt/etc):/etc/letsencrypt" \
  -v "$(readlink -m ../../../ssl/letsencrypt/var/lib):/var/lib/letsencrypt" \
  -v "$(readlink -m ../../../ssl/letsencrypt/var/log):/var/log/letsencrypt" \
  certbot/certbot certonly --standalone \
  --preferred-challenges=http \
  • このときインターネートからホストサーバの HTTP 80番ポートにアクセスできる必要があることに注意してください。
  • また、nginx コンテナが起動していると80番ポートを利用していてエラーになるため、すべてのコンテナを停止した状態で実施することをお勧めします。
  • 以後のやりとりの詳細は certbot のバージョンによって変わる可能性があります。

certbot certonly コマンドを実行すると、登録するメールアドレスを尋ねられますので入力してください。 メールアドレスの登録をスキップする場合はそのままエンターを押してください(SSL証明書は発行されます)。

Enter email address or hit Enter to skip.
 (Enter 'c' to cancel): 

ACME サーバーに登録するには利用規約に同意する必要があります。 利用規約に同意するかどうかを「Do you agree?」と尋ねていますので、同意する場合は Y と入力してください。 同意しない場合は N と入力してください(SSL証明書は発行されずにコマンドが終了します)。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at:
https://letsencrypt.org/documents/LE-SA-v1.5-February-24-2025.pdf
You must agree in order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: 

メールアドレスを入力している場合、Certbotを開発している非営利団体である Electronic Frontier Foundation (EFF) とあなたのメールアドレスを共有してもよいかを尋ねていますので、同意する場合は Y と入力してください。共有を望まない場合は N と入力してください(SSL証明書は発行されます)。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: 

最後に SSL 証明書を発行する対象のドメイン名を尋ねられますので入力してください。

Please enter the domain name(s) you would like on your certificate (comma and/or
space separated) (Enter 'c' to cancel):

ここまでの入力が完了すると SSL 証明書の発行手続きが開始されます。 無事に SSL 証明書が発行されると、証明書が fullchain.pem に、秘密鍵が privkey.pem に保存されます。

Requesting a certificate for ${ドメイン名}

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/${ドメイン名}/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/${ドメイン名}/privkey.pem
This certificate expires on YYYY-MM-DD.
These files will be updated when the certificate renews.

NEXT STEPS:
- The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for instructions.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

なお、上記のような入力・確認手順を省略したい場合は、certbot certonly コマンドに例えば以下のようにオプションを追加して実行してください。

--agree-tos --no-eff-email -m "${メールアドレス}" -d "${ドメイン名}"

これらのオプションは以下を意味します。また、メールアドレスやドメイン名は実際の値に置き換えてください。

  • --agree-tos: 利用規約に合意する
  • --no-eff-email: EFF にメールアドレスは共有しない
  • -m: メールアドレスの指定(${メールアドレス} の部分は実際のメールアドレスに置き換えてください)
  • -d: ドメイン名の指定(${ドメイン名} の部分は実際のドメイン名に置き換えてください)

SSL 証明書の適用

certbot で Let's Encrypt より SSL 証明書の発行に成功した場合、letsencrypt/etc/live/${ドメイン名}/ ディレクトリ配下に SSL 証明書と秘密鍵ファイルが保存されています。 これらのファイルを nginx/rabbitmq コンテナから参照できるように、以下のようにシンボリックリンクを張ります。

$ ln -s -f ./letsencrypt/etc/live/${ドメイン名}/fullchain.pem ../../../ssl/server.crt 
$ ln -s -f ./letsencrypt/etc/live/${ドメイン名}/privkey.pem ../../../ssl/server.key

注意: ここで、既存の SSL 証明書と秘密鍵をシンボリックリンクで置き換えていることに注意してください。既存のファイルを残しておきたい場合は、事前に別の場所にバックアップするなどしてください。

各コンテナを起動すると Let's Encrypt より発行された SSL 証明書が適用されているはずですので、Web ブラウザで kompira サーバに HTTPS アクセスして確認してみてください。

なお、この手順は初回発行時に必要になりますが、以下で説明する「SSL 証明書の更新」の際には不要です。

SSL 証明書の更新

SSL 証明書には有効期限があり(Let's Encrypt の場合は通常 90 日間)、有効期限が切れる前に更新する必要があります。 certbot には発行済みの SSL 証明書を更新する renew というコマンドがあり、以下のように certbot コンテナを利用して SSL 証明書を更新することができます。

$ docker run -it --rm \
  -v "$(readlink -m ../../../ssl/letsencrypt/etc):/etc/letsencrypt" \
  -v "$(readlink -m ../../../ssl/letsencrypt/var/lib):/var/lib/letsencrypt" \
  -v "$(readlink -m ../../../ssl/letsencrypt/var/log):/var/log/letsencrypt" \
  certbot/certbot renew

重要: これでホスト上の SSL 証明書ファイルと秘密鍵ファイルは更新されますが、各コンテナに対して「更新した SSL 証明書の再適用」を実施することを忘れないようにしてください。

なお、certbot で SSL 証明書を更新しようとしても、現在適用している SSL 証明書の有効期限がまだ十分に(30日以上)残っているときは、以下のように Certificate not yet due for renewal というメッセージが表示されて SSL 証明書の更新はスキップされます。

    :
Processing
/etc/letsencrypt/renewal/ドメイン名
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Certificate not yet due for renewal

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The following certificates are not due for renewal yet:
  /etc/letsencrypt/live/ドメイン名/fullchain.pem expires on 2025-07-29 (skipped)
No renewals were attempted.

有効期限が残っていても SSL 証明書を強制的に更新したいときは、certbot に --force-renewal オプションを付けて実行してください。

$ docker run -it --rm \
  -v "$(readlink -m ../../../ssl/letsencrypt/etc):/etc/letsencrypt" \
  -v "$(readlink -m ../../../ssl/letsencrypt/var/lib):/var/lib/letsencrypt" \
  -v "$(readlink -m ../../../ssl/letsencrypt/var/log):/var/log/letsencrypt" \
  certbot/certbot renew --force-renewal