Add Caddy for automatic HTTPS in front of the frontend/backend stack

Caddy now owns ports 80/443 and reverse-proxies to the frontend
container (which was publishing 80 itself, conflicting with Caddy),
handling Let's Encrypt certificate issuance/renewal automatically.
Fix the Caddyfile's upstream name (it referenced a nonexistent "app"
service instead of "frontend") and update the Lightsail deploy guide's
HTTPS section to match this setup instead of the old manual-certbot
approach.
This commit is contained in:
2026-08-18 21:22:53 +09:00
parent db98677838
commit 20cb449f76
3 changed files with 66 additions and 15 deletions
+48 -15
View File
@@ -10,6 +10,9 @@ Lightsail Containers(マネージドコンテナサービス)よりも、状
Internet
│ :80 / :443
▼
[caddy コンテナ] Let's Encrypt証明書の自動取得・更新、HTTP→HTTPSリダイレクト
│ :80(コンテナ間通信のみ、ホストには公開しない)
▼
[frontend コンテナ] nginx
├─ 静的ファイル (Vue ビルド成果物) を配信
└─ /chat, /api, /memory, /logs, /health を backend にリバースプロキシ
@@ -26,7 +29,7 @@ Internet
- [backend/Dockerfile](../backend/Dockerfile)
- [frontend/Dockerfile](../frontend/Dockerfile) / [frontend/nginx.conf](../frontend/nginx.conf)
- [docker-compose.yml](../docker-compose.yml)
- [docker-compose.yml](../docker-compose.yml) / [Caddyfile](../Caddyfile)
## 1. Lightsail インスタンスの作成
@@ -39,7 +42,7 @@ Internet
作成後、インスタンス詳細ページの「ネットワーキング」タブで:
- **静的 IP をアタッチ**(再起動してもIPが変わらないようにする。ドメインを使う場合は必須)
- ファイアウォールで **80 (HTTP)** と、HTTPS を使うなら **443** を許可(22/SSH はデフォルトで開いている)
- ファイアウォールで **80 (HTTP)** と **443 (HTTPS)** を許可(Caddyの証明書取得とHTTPS配信に両方必要。22/SSH はデフォルトで開いている)
## 2. SSH 接続 & Docker のインストール
@@ -117,7 +120,7 @@ nano backend/.env # APIキーやモデル名など本番用の値を設定
SQLite(`AppSetting`テーブル、`backend_data`ボリュームで永続化)に保存され、`.env`の値より優先される。
**注意:** このパスワード保護は簡易的なものであり、HTTP平文通信の場合はBasic認証の資格情報がネットワーク上に
そのまま流れてしまう。この機能を使うなら[6. HTTPS化](#6-https-化ドメインがある場合)と合わせて運用すること。
そのまま流れてしまう。この機能を使うなら[6. HTTPS化](#6-https-化caddy)と合わせて運用すること。
## 4. ビルド & 起動
@@ -127,7 +130,9 @@ docker compose up -d
docker compose logs -f backend # 起動ログ確認(Ctrl+C で抜ける。プロセスは動き続ける)
```
ブラウザで `http://<静的IP>/` にアクセスして動作確認する。
`docker-compose.yml`にはCaddyが含まれており、80/443番ポートはCaddyが受け持つ(`frontend`は直接公開しない)。
Caddyfileにはドメイン名を設定する前提のため、動作確認は静的IPへの直接アクセスではなく
[6. HTTPS化](#6-https-化caddy)の手順でドメイン経由で行うこと。
停止・再起動・更新の運用コマンド:
@@ -153,21 +158,49 @@ docker cp $(docker compose ps -q backend):/app/data/backup.db ./playchat-backup-
インスタンスごとのバックアップとしては、Lightsail の「スナップショット」機能(自動スナップショット設定可)も併用すると安心。
## 6. HTTPS 化(ドメインがある場合)
## 6. HTTPS 化(Caddy)
ドメインの A レコードを Lightsail の静的 IP に向けた上で、ホスト側で certbot を使い証明書を取得し、
`frontend` コンテナへ読み取り専用でマウントする。
[Caddy](https://caddyserver.com/) をリバースプロキシとして`frontend`の手前に置き、証明書の取得・更新を
自動化する(Let's Encrypt、ACME HTTP-01 チャレンジ)。手動でのcertbot操作は不要。
```bash
sudo apt install -y certbot
docker compose stop frontend # 80番ポートを一時的に空ける
sudo certbot certonly --standalone -d your-domain.example.com
docker compose start frontend
構成:
```
Internet
│ :80 / :443
▼
[caddy コンテナ] ← Let's Encrypt証明書の自動取得・更新、HTTP→HTTPSリダイレクト
│ :80 (コンテナ間通信、ホストには公開しない)
▼
[frontend コンテナ] nginx(静的配信 + backendへのAPIプロキシ)
▼
[backend コンテナ]
```
`frontend/nginx.conf` に 443 用のサーバーブロックを追記し、`docker-compose.yml` の `frontend` サービスに
`443:443` のポートマッピングと `/etc/letsencrypt` のボリュームマウントを追加する(証明書更新時は `docker compose restart frontend` が必要。
`certbot renew` の `--deploy-hook` に登録しておくと自動化できる)。この構成に変更したい場合は改めて対応する。
`frontend`はもう80番ポートをホストに公開せず(`expose`のみ)、代わりに`caddy`が80/443を受けて
`frontend`へ内部転送する。ルートの [Caddyfile](../Caddyfile) にドメインを設定する:
```
your-domain.example.com {
reverse_proxy frontend:80
}
```
前提条件:
- ドメインの A レコード(IPv4)を Lightsail の静的 IP に向けておく(DuckDNS等の無料動的DNSでも可)
- Lightsail ファイアウォールで **443 (HTTPS)** を許可([1. Lightsail インスタンスの作成](#1-lightsail-インスタンスの作成)で追加済みのはず)
起動すると、Caddyがドメイン名を見て自動的にACMEチャレンジ(ポート80経由)で証明書を取得し、
以後は自動更新される。証明書は`caddy_data`ボリュームに永続化されるので、`docker compose down`
(`-v`無し)では消えない。
```bash
docker compose up -d
docker compose logs -f caddy # 証明書取得ログを確認("certificate obtained successfully" 等)
```
`https://your-domain.example.com/` にアクセスして確認する。
## 7. 常駐タスクについて