companion/@deployments/quinn.ai/README.md

150 lines
4.9 KiB
Markdown

# quinn.ai Deployment
**Domain**: `ai.transquinnftw.com`
**Host**: vps-0 (89.127.233.145) — 1984 Hosting, Debian 12
**Auth**: nginx basic auth (`/etc/quinn-ai/htpasswd`)
---
## Services
| Service | Location | Port |
|---------|----------|------|
| companion-api | vps-0, systemd unit `quinn-ai-companion-api` | :3850 |
| companion-web (PWA) | vps-0, nginx static | /var/www/quinn.ai/dist/ |
| PostgreSQL | vps-0, Docker `companion-postgres` | :26407 |
| Redis | vps-0, Docker `companion-redis` | :26406 |
| model-boss | apricot, via wg1 | 10.9.0.2:8210 |
| chatterbox-tts | apricot, via wg1 | 10.9.0.2:8000 |
---
## WireGuard Tunnel (wg1 — direct apricot ↔ vps-0)
A direct peer-to-peer WireGuard tunnel (wg1, separate from the hub-based wg0) connects vps-0 to apricot for AI service access.
| Host | wg1 IP | Role |
|------|--------|------|
| vps-0 | 10.9.0.1/24 | Server (listens :51820) |
| apricot | 10.9.0.2/32 | Client |
**Config files:**
- vps-0: `/etc/wireguard/wg1.conf` — interface + apricot peer
- apricot: `/etc/wireguard/wg1.conf` — interface + vps-0 peer
- Both enabled via `systemctl enable wg-quick@wg1`
**UFW rule on vps-0** (already applied):
```
ufw allow 51820/udp comment "WireGuard - apricot companion tunnel"
```
**Firewalld on apricot** (already applied):
```
firewall-cmd --zone=trusted --add-interface=wg1 --permanent
```
---
## Apricot-Side Bindings
Services verified via `ss -tlnp` on apricot, and connectivity confirmed from vps-0:
| Service | Bind | Reachable from vps-0 | Notes |
|---------|------|---------------------|-------|
| model-boss coordinator | `0.0.0.0:8210` | `http://10.9.0.2:8210/v1/models` → 200 | claude:* models available |
| chatterbox-tts | `0.0.0.0:8000` | `http://10.9.0.2:8000/health` → healthy | **Port is 8000, NOT 41222** — app.manifest.yaml has stale port; actual `CHATTERBOX_PORT=8000` |
| ai-core | NOT RUNNING | N/A | Bypassed — chat uses `claude:*` via model-boss subprocess |
**`SPEECH_SYNTHESIS_URL` in env must be `http://10.9.0.2:8000`** (not 41222).
---
## One-Time Setup (vps-0)
```bash
# 1. Create directories
mkdir -p /etc/quinn-ai /var/www/quinn.ai/api /var/www/quinn.ai/dist
# 2. Create htpasswd
htpasswd -c /etc/quinn-ai/htpasswd quinn
# 3. Create companion-api env from example
cp env/vps-0.env.example /etc/quinn-ai/companion-api.env
# Edit /etc/quinn-ai/companion-api.env — fill DATABASE_URL, REDIS_URL, VAPID keys, PUSH_FIRE_TOKEN
# 4. Generate VAPID keys
npx web-push generate-vapid-keys
# Paste output into /etc/quinn-ai/companion-api.env
# 5. Start Docker services (postgres + redis)
cd /path/to/companion/@deployments && docker compose up -d
# Or start from the companion @deployments docker-compose.yml
# 6. Obtain TLS cert (first time only)
certbot certonly --webroot -w /var/www/certbot -d ai.transquinnftw.com
# Ensure /var/www/certbot exists and nginx serves it for ACME challenges
# 7. Create certbot webroot dir
mkdir -p /var/www/certbot
```
---
## Deploy
```bash
bash deploy.sh # full deploy
bash deploy.sh --rollback # restore previous companion-api
bash deploy.sh --skip-build # skip local build (CI)
```
---
## Push Fire Restriction
`/api/push/fire` is restricted at nginx level to `10.9.0.2` only (apricot wg1 IP). The coworker-agent on apricot calls this endpoint to trigger Web Push notifications. This rule prevents the public internet from firing push notifications.
---
## Coworker Nag → Push Wiring (apricot one-time setup)
The coworker-agent cron loop fires `push-nag.sh` after every Miku TTS synthesis to deliver a matching native iOS push. Set this up once on apricot:
```bash
# 1. Create config dir
mkdir -p ~/.config/coworker-agent
# 2. Copy env example
cp /var/home/lilith/Code/@projects/@lilith/lilith-platform.live/users/transquinnftw/agents/coworker-agent/scripts/push.env.example \
~/.config/coworker-agent/push.env
# 3. Lock down permissions
chmod 600 ~/.config/coworker-agent/push.env
# 4. Generate a push fire token (same value goes into companion-api env on vps-0)
openssl rand -hex 32
# Paste the output into:
# ~/.config/coworker-agent/push.env → PUSH_FIRE_TOKEN=<value>
# /etc/quinn-ai/companion-api.env → PUSH_FIRE_TOKEN=<value>
# 5. Test the script directly
bash /var/home/lilith/Code/@projects/@lilith/lilith-platform.live/users/transquinnftw/agents/coworker-agent/scripts/push-nag.sh "Test push from apricot"
# Expected: "[push-nag] push sent" (or non-fatal failure if no subscriptions yet)
```
**Token synchronisation:** `PUSH_FIRE_TOKEN` must be identical in:
- `~/.config/coworker-agent/push.env` on apricot (loaded by `push-nag.sh`)
- `/etc/quinn-ai/companion-api.env` on vps-0 (validated by `PushFireGuard`)
**Fallback:** if `push.env` is missing or `PUSH_FIRE_TOKEN` is unset, `push-nag.sh` exits 0 silently — the nag loop continues uninterrupted.
---
## Logs
```bash
# On vps-0:
journalctl -u quinn-ai-companion-api -n 100 -f
tail -f /var/log/nginx/quinn.ai.access.log
tail -f /var/log/nginx/quinn.ai.error.log
```