- Add a password-protected /api/settings endpoint (HTTP Basic auth, backend/app/core/auth.py) backed by a DB-stored allowlist of connection settings (OPENAI_API_KEY, ANTHROPIC_API_KEY, AWS creds, OLLAMA_API_BASE, TAVILY_API_KEY, LOCAL_KB_EMBEDDING_MODEL). Saved values override .env and apply immediately via os.environ, so Lightsail deployments no longer need SSH + `.env` edits to rotate keys. Values are always returned masked to the frontend. - Replace ModelSelector.vue's hardcoded model list with a DB-backed /api/models CRUD API (read is public, writes reuse the settings password) so the chat model dropdown can be edited from the GUI; seed it once with the previous hardcoded presets on first boot. - Fix local_knowledge.py reading LOCAL_KB_EMBEDDING_MODEL once at import time instead of per-call, which would have silently ignored GUI/DB overrides for the embedding model. - Add SettingsPanel.vue (API keys + model management UI) and document the new SETTINGS_PASSWORD env var in .env.example and the Lightsail deploy guide. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
182 lines
8.5 KiB
Markdown
182 lines
8.5 KiB
Markdown
# AWS Lightsail へのデプロイ
|
||
|
||
このアプリを AWS Lightsail の「インスタンス」(Ubuntu VPS)上で、Docker Compose を使って動かす手順。
|
||
SQLite・ローカルナレッジベース・Discord Bot・APScheduler がすべて 1 プロセス(バックエンドコンテナ)内で常駐するため、
|
||
Lightsail Containers(マネージドコンテナサービス)よりも、状態を持てる通常のインスタンス構成の方が相性が良い。
|
||
|
||
## 構成
|
||
|
||
```
|
||
Internet
|
||
│ :80 / :443
|
||
▼
|
||
[frontend コンテナ] nginx
|
||
├─ 静的ファイル (Vue ビルド成果物) を配信
|
||
└─ /chat, /api, /memory, /logs, /health を backend にリバースプロキシ
|
||
│
|
||
▼
|
||
[backend コンテナ] FastAPI (uvicorn)
|
||
└─ SQLite (playchat.db) / knowledge_base を Docker Volume に永続化
|
||
```
|
||
|
||
`frontend/src/api/client.ts` はすべて相対パスで API を呼ぶ実装になっているため、
|
||
本番でも frontend と backend を同一オリジン(nginx 経由)で配信すれば CORS 設定は事実上不要。
|
||
|
||
リポジトリには以下を追加済み:
|
||
|
||
- [backend/Dockerfile](../backend/Dockerfile)
|
||
- [frontend/Dockerfile](../frontend/Dockerfile) / [frontend/nginx.conf](../frontend/nginx.conf)
|
||
- [docker-compose.yml](../docker-compose.yml)
|
||
|
||
## 1. Lightsail インスタンスの作成
|
||
|
||
1. Lightsail コンソール → 「インスタンスの作成」
|
||
2. プラットフォーム: **Linux/Unix**、設計図: **OS のみ → Ubuntu 22.04 LTS**
|
||
3. プラン: **2GB RAM / 1vCPU($10/月)以上を推奨**
|
||
(フロントエンドの `npm run build` (vue-tsc) はビルド時にメモリを食うため、1GB プランだと OOM で失敗することがある)
|
||
4. インスタンス名を付けて作成
|
||
|
||
作成後、インスタンス詳細ページの「ネットワーキング」タブで:
|
||
|
||
- **静的 IP をアタッチ**(再起動してもIPが変わらないようにする。ドメインを使う場合は必須)
|
||
- ファイアウォールで **80 (HTTP)** と、HTTPS を使うなら **443** を許可(22/SSH はデフォルトで開いている)
|
||
|
||
## 2. SSH 接続 & Docker のインストール
|
||
|
||
Lightsail コンソールの「接続」タブからブラウザ SSH で入るか、ダウンロードした鍵で接続する。
|
||
|
||
```bash
|
||
sudo apt update && sudo apt upgrade -y
|
||
|
||
# Docker 公式インストールスクリプト
|
||
curl -fsSL https://get.docker.com | sudo sh
|
||
sudo usermod -aG docker $USER
|
||
newgrp docker
|
||
|
||
# Docker Compose Plugin の確認(get.docker.com で入る場合が多い)
|
||
docker compose version
|
||
```
|
||
|
||
## 3. リポジトリの取得と設定
|
||
|
||
リポジトリは自前の Git サーバー(`colc-git.duckdns.org`、Gitea/Forgejo系)でホストしている。
|
||
DuckDNS 経由の公開IPで、HTTPS(443)・SSH(22) とも外部から到達可能なので、Lightsail インスタンスからも
|
||
VPN 等は不要で直接クローンできる。認証方法は以下のどちらか。
|
||
|
||
### 方法A: SSH デプロイキー(推奨・pull専用なら安全)
|
||
|
||
```bash
|
||
ssh-keygen -t ed25519 -C "lightsail-playchat" -f ~/.ssh/id_ed25519 -N ""
|
||
cat ~/.ssh/id_ed25519.pub
|
||
```
|
||
|
||
表示された公開鍵を colc-git.duckdns.org 側のリポジトリ設定の **Deploy Keys** に **Read only** で登録してから:
|
||
|
||
```bash
|
||
git clone git@colc-git.duckdns.org:colcaroli/playchat.git
|
||
cd playchat
|
||
```
|
||
|
||
### 方法B: HTTPS + アクセストークン
|
||
|
||
colc-git.duckdns.org 側で個人アクセストークン(PAT)を発行し:
|
||
|
||
```bash
|
||
git clone https://colc-git.duckdns.org/colcaroli/playchat.git
|
||
cd playchat
|
||
# Username / Password 入力を求められたら、Password 欄に発行したトークンを入力
|
||
```
|
||
|
||
トークンをキャッシュしたい場合は `git config credential.helper cache`(メモリに一時保存。
|
||
`store` は平文保存になるため非推奨)。
|
||
|
||
### .env の設定
|
||
|
||
```bash
|
||
cp backend/.env.example backend/.env
|
||
nano backend/.env # APIキーやモデル名など本番用の値を設定
|
||
```
|
||
|
||
`backend/.env` で最低限確認する項目:
|
||
|
||
| 変数 | 本番での指針 |
|
||
|---|---|
|
||
| `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` | 使うプロバイダーのキーを設定 |
|
||
| `DEFAULT_MODEL` | 使いたいモデル名 |
|
||
| `CORS_ORIGINS` | `http://<静的IP>` またはドメイン(nginx が同一オリジンで配信するので基本は素通りするが念のため合わせておく) |
|
||
| `DATABASE_URL` | **編集不要**(`docker-compose.yml` が `/app/data/playchat.db` に上書きし、Docker Volume に永続化する) |
|
||
| `DISCORD_BOT_TOKEN` 等 | Discord Bot / 通知機能を使うなら設定。不要なら空のままでよい(未設定時は該当機能が無効) |
|
||
| `SETTINGS_PASSWORD` | GUIの「設定」画面(後述)を使うなら必ず設定する。未設定だと設定画面は403で拒否される |
|
||
|
||
`backend/.env` はコンテナに `env_file` として渡され、Git 管理対象外(`.gitignore` 済み)なので直接編集してよい。
|
||
|
||
### GUIからのAPIキー管理
|
||
|
||
初回起動後は、`OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / AWS認証情報などをSSHで`.env`を編集し直さなくても、
|
||
アプリ右上の「設定」ボタン(`SETTINGS_PASSWORD` によるBasic認証で保護)から変更できる。GUIで保存した値は
|
||
SQLite(`AppSetting`テーブル、`backend_data`ボリュームで永続化)に保存され、`.env`の値より優先される。
|
||
|
||
**注意:** このパスワード保護は簡易的なものであり、HTTP平文通信の場合はBasic認証の資格情報がネットワーク上に
|
||
そのまま流れてしまう。この機能を使うなら[6. HTTPS化](#6-https-化ドメインがある場合)と合わせて運用すること。
|
||
|
||
## 4. ビルド & 起動
|
||
|
||
```bash
|
||
docker compose build
|
||
docker compose up -d
|
||
docker compose logs -f backend # 起動ログ確認(Ctrl+C で抜ける。プロセスは動き続ける)
|
||
```
|
||
|
||
ブラウザで `http://<静的IP>/` にアクセスして動作確認する。
|
||
|
||
停止・再起動・更新の運用コマンド:
|
||
|
||
```bash
|
||
docker compose ps # 状態確認
|
||
docker compose restart backend # backend だけ再起動
|
||
git pull && docker compose up -d --build # コード更新を反映
|
||
```
|
||
|
||
## 5. 永続化されるデータ
|
||
|
||
`docker-compose.yml` は以下を Named Volume にしている(`docker compose down` してもデータは消えない。`docker compose down -v` は消えるので注意):
|
||
|
||
- `backend_data` … `playchat.db`(会話履歴・メモリ)
|
||
- `backend_knowledge_base` … `knowledge_base/`(Web検索で蓄積したナレッジ含む)
|
||
|
||
バックアップ例:
|
||
|
||
```bash
|
||
docker compose exec backend sqlite3 /app/data/playchat.db ".backup /app/data/backup.db"
|
||
docker cp $(docker compose ps -q backend):/app/data/backup.db ./playchat-backup-$(date +%F).db
|
||
```
|
||
|
||
インスタンスごとのバックアップとしては、Lightsail の「スナップショット」機能(自動スナップショット設定可)も併用すると安心。
|
||
|
||
## 6. HTTPS 化(ドメインがある場合)
|
||
|
||
ドメインの A レコードを Lightsail の静的 IP に向けた上で、ホスト側で certbot を使い証明書を取得し、
|
||
`frontend` コンテナへ読み取り専用でマウントする。
|
||
|
||
```bash
|
||
sudo apt install -y certbot
|
||
docker compose stop frontend # 80番ポートを一時的に空ける
|
||
sudo certbot certonly --standalone -d your-domain.example.com
|
||
docker compose start frontend
|
||
```
|
||
|
||
`frontend/nginx.conf` に 443 用のサーバーブロックを追記し、`docker-compose.yml` の `frontend` サービスに
|
||
`443:443` のポートマッピングと `/etc/letsencrypt` のボリュームマウントを追加する(証明書更新時は `docker compose restart frontend` が必要。
|
||
`certbot renew` の `--deploy-hook` に登録しておくと自動化できる)。この構成に変更したい場合は改めて対応する。
|
||
|
||
## 7. 常駐タスクについて
|
||
|
||
APScheduler(天気通知など)と Discord Bot は `backend` コンテナ起動時(FastAPI の `lifespan`)に単一プロセス内で動く。
|
||
`restart: unless-stopped` を設定しているため、インスタンス再起動やコンテナクラッシュ時も自動的に立ち上がる。
|
||
複数インスタンス/複数コンテナへのスケールアウトは想定していない(SQLite・APScheduler・Discord Bot が単一プロセス前提のため)。
|
||
|
||
## コスト目安
|
||
|
||
- Lightsail インスタンス 2GB プラン: 約 $10/月(固定IP・80/443 の転送量込み)
|
||
- LLM API 利用料(OpenAI / Anthropic / Bedrock)は別途従量課金
|