何が起きたか
Docker のボリューム設定を修正する際に、誤ってボリュームを削除してしまった。
その結果、Thruster がキャッシュしていた Let's Encrypt の証明書が消失。再起動時に証明書を再取得しようとしたが、レートリミットに引っかかって HTTPS が使えなくなった。
Let's Encrypt のレートリミット
| 制限 | 内容 |
|---|---|
| 同一ドメインへの証明書発行 | 7 日間で 5 回まで |
| 失敗したリクエスト | カウントされない |
| 更新(同じ証明書) | 制限なし |
つまり、短期間に証明書を何度も新規発行すると制限がかかる。
今回は、ボリューム削除 → コンテナ再起動を繰り返したことで、証明書の新規発行が複数回発生してしまった。
Thruster の証明書キャッシュ
Thruster(Rails 8 のデフォルト HTTP プロキシ)は、Let's Encrypt の証明書を自動で取得・管理してくれる。
証明書は ./storage/thruster に保存される(デフォルト)。
/rails/storage/ ← ボリュームでマウントすべき場所
└── thruster/
└── (証明書ファイル)
このディレクトリを永続化しないと、コンテナ再起動のたびに証明書を再取得することになる。
正しい compose.yaml の設定
services:
web:
volumes:
- storage_data:/rails/storage # ← これが重要
volumes:
storage_data:
/rails/storage を名前付きボリュームでマウントすることで:
- SQLite のデータが永続化される
- Thruster の証明書キャッシュも永続化される
- コンテナを再起動しても証明書を再取得しなくて済む
復旧方法
レートリミットにかかったら、1 週間待つしかない。
その間の選択肢:
| 選択肢 | メリット | デメリット |
|---|---|---|
| HTTP で公開 | すぐ動く | セキュリティ警告 |
| 待つ | 何もしなくていい | アクセスできない |
| ALB + ACM に移行 | レートリミットなし | 月 $20 程度のコスト |
今回は、あまり慣れていない個人開発でセキュリティにも懸念があるし、すぐに公開したい需要もなかったので安全策を取って HTTPS 復活まで待つことにした。
そのため、いったん EC2 インスタンスは停止して、動作確認はすべてローカルで行うことに。
EC2 停止時の注意
復旧を待つ間、EC2 を停止しておくとコスト節約になる。
| 状態 | EC2 課金 | Elastic IP 課金 |
|---|---|---|
| 起動中 | あり | あり(2024 年 2 月〜) |
| 停止中 | なし | あり |
注意: Elastic IP はインスタンス停止中でも課金される(約 $0.005/時 = $3.6/月)。
ただし、ボリュームはインスタンス停止しても消えないので、再起動後にレートリミットが解除されていれば HTTPS は復活する。
学び
- ボリュームの削除は慎重に...(特にキャッシュ系で消したらまずいものがないか調べてから)
- 証明書のキャッシュ場所や Let's Encrypt のレート制限について理解しておく