#mynavi();
#setlinebreak(on);
* 概要 [#l1d48087]
#html(<div class="pl10">)
Let's Encrypt の SSL証明書を自動更新する手順のメモ。
[環境/要件など]
・nginx は docker で動作させている。
・nginx を止めずに自動更新を行いたい。
Let's Encrypt の SSL証明書を取得/更新する場合、Certbot を使用する事になるが、上記の環境/要件を満たす為に以下の通り構成する。
・更新には Certbot の webroot プラグインを使用する。(standaloneではなく)
・アクセストークンの確認用リクエストも nginx で受け付ける。(リダイレクト等の対象にしない)
・トークンの確認用リクエスト時には webroot ディレクトリ配下に出力されるトークンを参照できるように nginx を設定しておく。
尚、当記事の内容は Azure の VM を使用して行った為、何箇所か japaneast.cloudapp.azure.com 等の記述がある為、別環境で行う場合は適宜読み替える。
#html(</div>)
* 目次 [#m8e94704]
#contents
-- 関連
* 作業ディレクトリ作成/移動 [#vaa723d9]
#html(<div class="pl10">)
#myterm2(){{
sudo mkdir /containers
sudo chmod 777 /containers
cd /containers
}}
#html(</div>)
* dockerインストール [#ub534fa0]
#html(<div class="pl10">)
setup_docker.sh
#mycode2(){{
#!/bin/bash
apt-get update
apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io
curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
}}
インストール実行
#myterm2(){{
sudo bash setup_docker.sh
}}
docker周りの起動設定など
#myterm2(){{
# カレントユーザをdockerグループに所属させておく
sudo usermod -aG docker azureuser
# 起動設定
sudo update-rc.d docker defaults
# 起動設定確認
ls -l /etc/rc?.d/*docker
}}
いったんログアウトして再ログインする。
※dockerグループへの所属を反映させた状態にする。
#html(</div>)
* SSL証明書取得 [#e9af4db1]
#html(<div class="pl10">)
ssl_cert_create.sh
#mycode2(){{
#!/bin/bash
domain=`hostname`.japaneast.cloudapp.azure.com
docker run -p 80:80 \
-v `pwd`/letsencrypt:/etc/letsencrypt \
-v `pwd`/letsencrypt/logs:/var/log/letsencrypt \
-v `pwd`/www:/var/www \
certbot/certbot certonly \
--standalone
--register-unsafely-without-email \
--non-interactive --agree-tos \
--force-renewal \
--renew-by-default \
-d ${domain}
aft=`sudo ls -l ./letsencrypt/live/${domain}/`
echo "## cert ##"
echo "$aft"
}}
先にフォルダを作っておく
#myterm2(){{
mkdir letsencrypt
mkdir www
}}
実行
#myterm2(){{
bash ssl_cert_create.sh
:
:
## cert ##
total 20
-rw-r--r-- 1 root root 692 Feb 11 03:26 README
lrwxrwxrwx 1 root root 63 Feb 11 03:26 cert.pem -> ../../archive/xxxxxxxx.japaneast.cloudapp.azure.com/cert1.pem
lrwxrwxrwx 1 root root 64 Feb 11 03:26 chain.pem -> ../../archive/xxxxxxxx.japaneast.cloudapp.azure.com/chain1.pem
lrwxrwxrwx 1 root root 68 Feb 11 03:26 fullchain.pem -> ../../archive/xxxxxxxx.japaneast.cloudapp.azure.com/fullchain1.pem
lrwxrwxrwx 1 root root 66 Feb 11 03:26 privkey.pem -> ../../archive/xxxxxxxx.japaneast.cloudapp.azure.com/privkey1.pem
}}
#html(</div>)
* docker コンテナ作成 [#j0ce9c96]
#html(<div class="pl10">)
** docker-compose.yml 作成 [#ldf27dfb]
#html(<div class="pl10">)
docker-compose.yml
#mycode2(){{
version: "3"
services:
grafana:
image: grafana/grafana:7.3.7
hostname: grafana
container_name: grafana
ports:
- "3000:3000"
environment:
GF_SERVER_ROOT_URL: "https://{サーバ名}.japaneast.cloudapp.azure.com"
GF_SECURITY_ADMIN_PASSWORD: "admin"
volumes:
- ./grafana/lib:/var/lib/grafana
- ./grafana/log:/var/log/grafana
# - ./grafana.ini/etc/grafana/grafana.ini
# :
nginx:
image: nginx:latest
hostname: nginx
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx_default.conf:/etc/nginx/conf.d/default.conf
- ./letsencrypt:/etc/letsencrypt
- ./www:/var/www
}}
#html(</div>)
** nginx設定ファイル作成 [#k2609f78]
#html(<div class="pl10">)
nginx_default.conf
#mycode2(){{
upstream backend {
server grafana:3000;
}
# http
server{
listen 80;
listen [::]:80;
server_name {サーバ名}.japaneast.cloudapp.azure.com;
# アクセストークン確認用リクエストの場合は、https にリダイレクトしない
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /var/www;
}
location / {
return 301 https://$host$request_uri;
}
}
# https
server{
listen 443 ssl;
listen [::]:443 ssl;
server_name {サーバ名}.japaneast.cloudapp.azure.com;
ssl_certificate /etc/letsencrypt/live/{サーバ名}.japaneast.cloudapp.azure.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{サーバ名}.japaneast.cloudapp.azure.com/privkey.pem;
location / {
proxy_pass http://backend;
}
}
}}
#html(</div>)
** コンテナ起動 [#b031fe8b]
#html(<div class="pl10">)
コンテナ起動
#myterm2(){{
docker-compose up -d
}}
#html(</div>)
#html(</div>)
* 自動更新の設定 [#z6197cb7]
#html(<div class="pl10">)
** 証明書更新用の処理を作成 [#x926df0d]
#html(<div class="pl10">)
ssl_cert_update.sh
#mycode2(){{
#!/bin/bash
cd /containers
domain=`hostname`.japaneast.cloudapp.azure.com
certbot_cmd=certonly
domain_arg="-d ${domain}"
if [ -e ./letsencrypt/live/${domain}/cert.pem ]; then
certbot_cmd=renew
domain_arg=
fi
bef=`sudo ls -l ./letsencrypt/live/${domain}/`
docker ps
docker run --rm \
-v `pwd`/letsencrypt:/etc/letsencrypt \
-v `pwd`/letsencrypt/logs:/var/log/letsencrypt \
-v `pwd`/www:/var/www \
certbot/certbot $certbot_cmd \
--webroot \
-w /var/www \
--register-unsafely-without-email \
--non-interactive --agree-tos \
--force-renewal \
--renew-by-default \
$domain_arg
aft=`sudo ls -l ./letsencrypt/live/${domain}/`
echo "## before ##"
echo "$bef"
echo "## after ##"
echo "$aft"
docker restart nginx
docker ps
}}
権限付与
#myterm2(){{
chmod 755 ssl_cert_update.sh
}}
#html(</div>)
#html(</div>)
* cronの設定 [#ve9bb2cc]
#html(<div class="pl10">)
毎月1日の0時に実行する場合
#myterm2(){{
sudo crontab -e
0 0 1 * * /containers/ssl_cert_update.sh 2>&1 >>/containers/ssl_cert_update.log
}}
実行時のログサンプル
#myterm2(){{
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fc95f0b03d9c grafana/grafana:7.3.7 "/run.sh" 15 minutes ago Up 15 minutes 0.0.0.0:3000->3000/tcp grafana
9fc2e7149baa nginx:latest "/docker-entrypoint.…" 26 minutes ago Up 15 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/xxxxxxxx.japaneast.cloudapp.azure.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Renewing an existing certificate for xxxxxxxx.japaneast.cloudapp.azure.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/xxxxxxxx.japaneast.cloudapp.azure.com/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all renewals succeeded:
/etc/letsencrypt/live/xxxxxxxx.japaneast.cloudapp.azure.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
## before ##
total 20
-rw-r--r-- 1 root root 692 Feb 11 03:26 README
lrwxrwxrwx 1 root root 63 Feb 11 03:26 cert.pem -> ../../archive/xxxxxxxx.japaneast.cloudapp.azure.com/cert1.pem
lrwxrwxrwx 1 root root 64 Feb 11 03:26 chain.pem -> ../../archive/xxxxxxxx.japaneast.cloudapp.azure.com/chain1.pem
lrwxrwxrwx 1 root root 68 Feb 11 03:26 fullchain.pem -> ../../archive/xxxxxxxx.japaneast.cloudapp.azure.com/fullchain1.pem
lrwxrwxrwx 1 root root 66 Feb 11 03:26 privkey.pem -> ../../archive/xxxxxxxx.japaneast.cloudapp.azure.com/privkey1.pem
## after ##
total 20
-rw-r--r-- 1 root root 692 Feb 11 03:26 README
lrwxrwxrwx 1 root root 63 Feb 11 04:04 cert.pem -> ../../archive/xxxxxxxx.japaneast.cloudapp.azure.com/cert2.pem
lrwxrwxrwx 1 root root 64 Feb 11 04:04 chain.pem -> ../../archive/xxxxxxxx.japaneast.cloudapp.azure.com/chain2.pem
lrwxrwxrwx 1 root root 68 Feb 11 04:04 fullchain.pem -> ../../archive/xxxxxxxx.japaneast.cloudapp.azure.com/fullchain2.pem
lrwxrwxrwx 1 root root 66 Feb 11 04:04 privkey.pem -> ../../archive/xxxxxxxx.japaneast.cloudapp.azure.com/privkey2.pem
nginx
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fc95f0b03d9c grafana/grafana:7.3.7 "/run.sh" 19 minutes ago Up 19 minutes 0.0.0.0:3000->3000/tcp grafana
9fc2e7149baa nginx:latest "/docker-entrypoint.…" 30 minutes ago Up Less than a second 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx
}}
#html(</div>)