Windows certbotでLet's Encryptの証明書を新規取得及び自動更新、 Flask を cheroot で https(TLS/SSL) 公開するメモ。

# 環境
Windows 11 Pro
Python  3.12.5
pip     24.2
certbot 2.11.0
flask   2.1.5
cheroot 10.0.1

# certbot インストール
```bat
> pip install certbot
> where certbot
C:\Users\admin\.pyenv\pyenv-win\shims\certbot
C:\Users\admin\.pyenv\pyenv-win\shims\certbot.bat
```

# ポート開放およびファイアーウォール
port 80
port 443

ポート未使用確認
```bat
REM ポート〇 確認
> netstat -ano | findstr 0.0.0.0:80
> netstat -ano | findstr 0.0.0.0:443
REM PID確認
tasklist /FI "PID eq <プロセスID>"
REM 強制終了
taskkill /PID <プロセスID> /F

REM IIS 稼働確認と停止
> iisreset /status 
> iisreset /stop 
```

# <font color="#ff0000">**管理者権限**</font>でDNS-01チャレンジでワイルドカード証明書を取得する
`*example.com` のようなワイルドカード証明書を取得するには [DNS-01チャレンジ](https://letsencrypt.org/ja/docs/challenge-types/) を使用する必要があるようだ。
この記事の通りにやってみる。
[Let's EncryptのDNS-01チャレンジでのSSL証明書更新（手動）](https://qiita.com/gbgb-ojisan/items/be8a35270a84b6b7ca2e)

```管理者権限：ワイルドカード証明書を取得するコマンド.bat
> certbot certonly --manual --server https://acme-v02.api.letsencrypt.org/directory --preferred-challenges dns -d *.example.com -d example.com -m webmaster@example.com --agree-tos

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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: N ← 入力

Account registered.
Requesting a certificate for *.example.com and example.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name:

_acme-challenge.example.com.

with the following value:

LKnLeFrAs3Kq_G0eRCAMxgFThash6Xyl3vAQIjO0k3M

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue   ※ Enter 押したらダメ！
```





**★ DNS レコードの追加を行う**
[https://www.onamae.com/domain/navi/dns_controll/input](https://www.onamae.com/domain/navi/dns_controll/input)

列名 : ホスト名	TYPE	TTL	VALUE	優先	状態	削除

ホスト名：_acme-challenge
TYPE：TXT
TTL：3600
VALUE：SVnekx2jayDaOfu-1laxvCdnzJWrFgaytHfzw7GFDooCI
状態：有効

追加が終わって数分？数十分？（反映にどのくらいかかるか不明）
反映されているかチェックURL
`https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.example.com`
反映されていれば Enter 押す。
```DNS再登録.bat
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name:

_acme-challenge.example.com.

with the following value:

gSPCf0BatD9K7YdtjbqDNyQdgatEdWLq-XAWc_FXss

(This must be set up in addition to the previous challenges; do not remove,
replace, or undo the previous challenge tasks yet. Note that you might be
asked to create multiple distinct TXT records with the same name. This is
permitted by DNS standards.)

Before continuing, verify the TXT record has been deployed. Depending on the DNS
provider, this may take some time, from a few seconds to multiple minutes. You can
check if it has finished deploying with aid of online tools, such as the Google
Admin Toolbox: https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.example.com.
Look for one or more bolded line(s) below the line ';ANSWER'. It should show the
value(s) you've just added.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
```
※ DNS再登録が出ない場合もある。
<font color="#ff0000">**【重要】**</font>
もう1度★を繰り返す。
<font color="#ff0000">以前の値は消さないで追加する。</font>

https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.example.com
にアクセスして値が **【２つ】** 反映されているか確認する。
反映されていれば Enter
```bat
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Successfully received certificate.
Certificate is saved at: C:\Certbot\live\example.com\fullchain.pem
Key is saved at:         C:\Certbot\live\example.com\privkey.pem
This certificate expires on 2024-12-29.
These files will be updated when the certificate renews.

NEXT STEPS:
- This certificate will not be renewed automatically. Autorenewal of --manual certificates requires the use of an authentication hook script (--manual-auth-hook) but one was not provided. To renew this certificate, repeat this same certbot command before the certificate's expiry date.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
```
これで成功！`C:\Certbot` を確認してみる。

```証明書情報表示コマンド.bat
> certbot certificates
```

# 証明書の手動更新
[証明書取得制限](https://letsencrypt.org/ja/docs/rate-limits/)があるのでまずテストで実行するのが吉
```【テスト】証明書更新コマンド.bat
> certbot renew --dry-run
```
```証明書更新コマンド.bat
> certbot renew
```
※ renew 実行すると有効期限まで残り30日以下なら更新する。
```強制的に証明書更新コマンド.bat
> certbot --force-renewal
```
※ [証明書取得制限](https://letsencrypt.org/ja/docs/rate-limits/)があるので乱用注意

# タスクスケジューラーに登録して毎日実行
<font color="#ff0000">**管理者権限で実行するように登録**</font>
```update_ca.bat
certbot renew
```

# cherootでhttps公開
<font color="#ff0000">管理者権限で実行する</font>
```main.py
from flask import Flask
from cheroot.wsgi import Server as WSGIServer
from cheroot.ssl.builtin import BuiltinSSLAdapter

domain   = 'example.com'
ssl_dir  = f'C:\\Certbot\\archive\\{domain}'
key_pem  = os.path.join(ssl_dir, 'privkey1.pem')
cert_pem = os.path.join(ssl_dir, 'cert1.pem')

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World! This is a Flask app running on Waitress with HTTPS enabled.'

if __name__ == '__main__':
    server = WSGIServer(('0.0.0.0', 443), app)
    server.ssl_adapter = BuiltinSSLAdapter(cert_pem, key_pem)
    try:
        server.start()
    except KeyboardInterrupt:
        server.stop()
```
# ポート開放確認
power shell
```bat
Test-NetConnection -ComputerName 192.168.0.200 -Port 443
Test-NetConnection -ComputerName example.com -Port 80
```

# 参考

[^1][^2][^3][^4][^5][^6]

[^1]:[Let’s Encrypt ドキュメント](https://letsencrypt.org/ja/docs/)
[^2]:[Certbot ドキュメント](https://eff-certbot.readthedocs.io/en/latest/index.html)
[^3]:[Let's Encrypt 総合ポータル コマンド解説](https://free-ssl.jp/command/#non-interactive)
[^4]:[certbot(Letsecnrypt)コマンド・オプションを真面目に理解する](https://qiita.com/s-katsumata/items/629222b24113d7a49b79)
[^5]:[Let 's Encrypt サイトデバッグ](https://letsdebug.net/)
[^6]:[相手が信頼できることを確かめる「サーバー証明書」とは？](https://xtech.nikkei.com/it/article/COLUMN/20071012/284426/)