# AWS Lightsail へのデプロイ このアプリを AWS Lightsail の「インスタンス」(Ubuntu VPS)上で、Docker Compose を使って動かす手順。 SQLite・ローカルナレッジベース・Discord Bot・APScheduler がすべて 1 プロセス(バックエンドコンテナ)内で常駐するため、 Lightsail Containers(マネージドコンテナサービス)よりも、状態を持てる通常のインスタンス構成の方が相性が良い。 ## 構成 ``` Internet │ :80 / :443 ▼ [caddy コンテナ] Let's Encrypt証明書の自動取得・更新、HTTP→HTTPSリダイレクト │ :80(コンテナ間通信のみ、ホストには公開しない) ▼ [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) / [Caddyfile](../Caddyfile) ## 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)** と **443 (HTTPS)** を許可(Caddyの証明書取得とHTTPS配信に両方必要。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-化caddy)と合わせて運用すること。 ## 4. ビルド & 起動 ```bash docker compose build docker compose up -d docker compose logs -f backend # 起動ログ確認(Ctrl+C で抜ける。プロセスは動き続ける) ``` `docker-compose.yml`にはCaddyが含まれており、80/443番ポートはCaddyが受け持つ(`frontend`は直接公開しない)。 Caddyfileにはドメイン名を設定する前提のため、動作確認は静的IPへの直接アクセスではなく [6. HTTPS化](#6-https-化caddy)の手順でドメイン経由で行うこと。 停止・再起動・更新の運用コマンド: ```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 化(Caddy) [Caddy](https://caddyserver.com/) をリバースプロキシとして`frontend`の手前に置き、証明書の取得・更新を 自動化する(Let's Encrypt、ACME HTTP-01 チャレンジ)。手動でのcertbot操作は不要。 構成: ``` Internet │ :80 / :443 ▼ [caddy コンテナ] ← Let's Encrypt証明書の自動取得・更新、HTTP→HTTPSリダイレクト │ :80 (コンテナ間通信、ホストには公開しない) ▼ [frontend コンテナ] nginx(静的配信 + backendへのAPIプロキシ) ▼ [backend コンテナ] ``` `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. 常駐タスクについて APScheduler(天気通知など)と Discord Bot は `backend` コンテナ起動時(FastAPI の `lifespan`)に単一プロセス内で動く。 `restart: unless-stopped` を設定しているため、インスタンス再起動やコンテナクラッシュ時も自動的に立ち上がる。 複数インスタンス/複数コンテナへのスケールアウトは想定していない(SQLite・APScheduler・Discord Bot が単一プロセス前提のため)。 ## コスト目安 - Lightsail インスタンス 2GB プラン: 約 $10/月(固定IP・80/443 の転送量込み) - LLM API 利用料(OpenAI / Anthropic / Bedrock)は別途従量課金