(備忘)Dify - 証明書期限切れで「保護されていない通信」となった話(Let's Encrypt)

補足:
わたしはセルフホストでLet‘s Encryptを使ってhttps化しています。
Xserver VPSのアプリイメージからhttps化されている場合はXserverの実装に依存しますので、この限りではありません。(もしかしたら証明書自動更新のしくみが備わっているのかもしれません)

はじめに


0.9.1 fix-1 への更新後、Difyにhttps接続したところ「保護されていない通信」となってしまうという事象が発生。

「保護されていない通信」

一瞬「あれ?バージョンアップで何か失敗したかな?」となったが、動作自体に問題はなし。確認していくうちに証明書の期限が切れていることが原因と分かる。

保護されてない通信から「証明書の詳細」
すでに有効期限を過ぎている

証明書更新にあたり、以下のサイトを参考にさせていだきました。

状態の確認

まずはコマンドで証明書の期限を確認
Statusが「INVALID: EXPIRED」

$ sudo certbot certificates
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
  Certificate Name: xxxxxxxxxxxxxxxxxx
    Serial Number: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Key Type: ECDSA
    Domains: xxxxxxxxxxxxxxxxxx
    Expiry Date: 2024-10-09 11:40:15+00:00 (INVALID: EXPIRED)
    Certificate Path: /etc/letsencrypt/live/xxxxxxxxxxxxxxxxxx/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/xxxxxxxxxxxxxxxxxx/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

証明書の更新

テスト実行

dry-runオプションを付けたテスト実行を実施したところ、エラーとなる。
補足:証明書更新を複数回失敗すると一時的に更新できない状態になるらしいので、まずdry-runで確認してます。

$ sudo certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/xxxxxxxxxxxx.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Simulating renewal of an existing certificate for xxxxxxxxxxxx

Certbot failed to authenticate some domains (authenticator: nginx). The Certificate Authority reported these problems:
  Domain: xxxxxxxxxxxx
  Type:   connection
  Detail: xxxxxxxxxxxx: Fetching http://xxxxxxxxxxxx/.well-known/acme-challenge/xxxxxxxxxxxx: Timeout during connect (likely firewall problem)

Hint: The Certificate Authority failed to verify the temporary nginx configuration changes made by Certbot. Ensure the listed domains point to this nginx server and that it is accessible from the internet.

Failed to renew certificate xxxxxxxxxxxx with error: Some challenges have failed.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
All simulated renewals failed. The following certificates could not be renewed:
  /etc/letsencrypt/live/xxxxxxxxxxxx/fullchain.pem (failure)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 renew failure(s), 0 parse failure(s)
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.

certbotのバージョンを確認してみたが、最新の状態(バージョンの問題)ではなさそう。

$ sudo apt-get update
Hit:1 https://download.docker.com/linux/ubuntu noble InRelease
Get:2 http://nova.clouds.archive.ubuntu.com/ubuntu noble InRelease [256 kB]
Hit:3 http://security.ubuntu.com/ubuntu noble-security InRelease
Get:4 http://nova.clouds.archive.ubuntu.com/ubuntu noble-updates InRelease [126 kB]
Get:5 http://nova.clouds.archive.ubuntu.com/ubuntu noble-backports InRelease [126 kB]
Get:6 http://nova.clouds.archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages [542 kB]
Get:7 http://nova.clouds.archive.ubuntu.com/ubuntu noble-updates/universe amd64 Packages [386 kB]
Fetched 1436 kB in 3s (448 kB/s)
Reading package lists... Done
$ certbot --version
certbot 2.9.0
$ sudo apt-get update certbot
E: The update command takes no arguments
$ sudo apt install --only-upgrade certbot
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
certbot is already the newest version (2.9.0-1).
0 upgraded, 0 newly installed, 0 to remove and 139 not upgraded.
$ certbot --version
certbot 2.9.0

こちらのサイトから、証明書更新は80番ポートを使用することを確認

VPSのポートフィルタールールにひっかかっていたもよう。いつもhttpsでそのままつないでいるのですっかり忘れる。

おまえかー!(可変IPなのにIPでフィルターするというめんどくさいことをしてます)

 80番ポートを解放後にあらためてテスト実行。今度はエラーなく完了。

$ sudo certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/xxxxxxxxxxxx.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Simulating renewal of an existing certificate for xxxxxxxxxxxx

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The following simulated renewals succeeded:
  /etc/letsencrypt/live/xxxxxxxxxxxx/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0 renew failure(s), 0 parse failure(s)
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.

証明書更新の実行

更新コマンドをポチ。問題なく完了。

$ sudo certbot renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/xxxxxxxxxxxx.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Renewing an existing certificate for xxxxxxxxxxxx
Reloading nginx server after certificate renewal

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all renewals succeeded:
  /etc/letsencrypt/live/xxxxxxxxxxxx/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Difyの接続でも「保護されていない通信」が出なくなりました。

証明書更新後の状態

証明書自動更新設定

90日毎にこれをやるのも面倒なので、以下を参考にCronで自動更新の設定を実施。

はじめて設定するので、エディタの選択から。
使い慣れた vim.basic を選択。

$ sudo crontab -u root -e
no crontab for root - using an empty one

Select an editor.  To change later, run 'select-editor'.
  1. /bin/nano        <---- easiest
  2. /usr/bin/vim.basic
  3. /usr/bin/vim.tiny
  4. /bin/ed

Choose 1-4 [1]: 2

参考サイトと同様に、毎月1日のAM4時に更新コマンドをたたく設定。

# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').
#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h  dom mon dow   command

00 04 01 * * certbot renew

これで同様の事象が出ることはなくなったはず。
(来月に実地確認の予定)


この記事が気に入ったらサポートをしてみませんか?