#author("2021-02-11T04:19:09+00:00","","") #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(){{ ## 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>)