背景
1つのVMインスタンス内に複数のWEBアプリケーションがデプロイされている状況で、これを docker-compose で構築しております。また、専用ドメインを取得し jwilder/nginx-proxy(Dockerイメージ)を使ってサブドメインを分けてそれぞれのアプリケーションにリクエストを転送しております。
今までは jrcs/letsencrypt-nginx-proxy-companion というDockerイメージを利用して、そのDockerコンテナ内で Letsencrypt のSSL証明書を取得していました。
しかし、各WEBアプリケーション(Dockerコンテナ、サブドメ)ごとにSSL証明書を発行していたため、Letsencryptの制限に引っかかってしまいました。
対策として、jrcs/letsencrypt-nginx-proxy-companion の利用をやめ、VMインスタンスにCertbotを導入しワイルドカードSSL証明書を取得して対応したのでそのメモ。
参考にした記事
- https://certbot.eff.org/instructions?ws=nginx&os=ubuntufocal&tab=wildcard
- https://certbot-dns-google.readthedocs.io/en/stable/
Certbotインストール
サーバーは Ubuntu 18.04
sudo snap install core; sudo snap refresh core
sudo apt-get remove certbot
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-google →これはGCPのDNSを使っている場合のプラグイン
GCPサービスアカウント作成&アタッチ
「IAM > サービスアカウント」にて専用のサービスアカウントを作成する、その時のロールは dns.admin(dns管理者)
上記サービスアカウントをVMインスタンスにアタッチする。
SSL証明書を発行
ワイルドカードSSL証明書を作成する
$ sudo certbot certonly \
--dns-google \
-d *.example.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for *.example.com
Waiting 60 seconds for DNS changes to propagate
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/example.com/privkey.pem
This certificate expires on 2023-07-24.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nginx-proxy(Dockerコンテナ)へ反映
SSL証明書をnginx-proxyに読み込ませるため docker-compose.yml を修正
nginx-proxy:
image: jwilder/nginx-proxy
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./docker-configs/nginx-proxy/certs:/etc/nginx/certs →ここを追加
cd docker-configs/nginx-proxy/certs
Certbotで作成したワイルドカードSSL証明書をコピーし、nginx-proxyに読み込ませる
sudo cp /etc/letsencrypt/live/example.com/fullchain.pem ./example.com.crt
sudo cp /etc/letsencrypt/live/example.com/privkey.pem ./example.com.key
Dockerコンテナを再起動
docker-compose down && docker-compose up -d
nginx-proxyは /etc/nginx/certs 配下の <ホスト名>.crt と <ホスト名>.key を見つけると自動的に使うようになっている。
ここまででSSL証明書が反映されhttpsで通信できるはず。
自動更新設定
まずはSSL証明書更新のシュミレーション
# 自動更新シュミレーション(--dry-runは実際には更新しないシュミレーションを意味する)
sudo certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Account registered.
Simulating renewal of an existing certificate for *.example.com
Waiting 60 seconds for DNS changes to propagate
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/example.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
シェルスクリプト作成
rootユーザーで実行する想定
sudo vim /home/admin/renew_ssl_certs.sh
#!/bin/bash
# Renew the ssl cert.
certbot renew
# Copy the ssl cert to the folder that the nginx-proxy can read.
cd /home/admin/docker-configs/nginx-proxy/certs
cp /etc/letsencrypt/live/example.com/fullchain.pem ./example.com.crt
cp /etc/letsencrypt/live/example.com/privkey.pem ./example.com.key
# Restart docker containers to apply the new ssl cert.
cd /home/admin
docker-compose down --remove-orphans && docker-compose up -d
rootユーザーのCRONとして登録
sudo crontab -e
—-----------------------------------------------------------
00 01 26 * * /home/admin/copy_ssl_certs.sh
数分後に実行してみてログを確認する
sudo less /var/log/syslog
—-----------------------------------------------------------
Apr 26 00:59:01 **** cron[958]: (root) RELOAD (crontabs/root)
Apr 26 01:00:01 **** CRON[2226]: (root) CMD (/home/admin/copy_ssl_certs.sh)
Apr 26 01:00:01 **** systemd[1]: Started snap.certbot.certbot.225709fe-f47d-43ac-81ce-e978a985b56d.scope.