157 lines
5.5 KiB
Markdown
157 lines
5.5 KiB
Markdown
# Production deployment and maintenance
|
|
|
|
This file is the operational source of truth for the current Jyotisha demo deployment.
|
|
|
|
## Current production
|
|
|
|
| Item | Value |
|
|
| --- | --- |
|
|
| Public domain | `https://jyotisha.chat` |
|
|
| DNS | Spaceship nameservers (`launch1.spaceship.net`, `launch2.spaceship.net`) |
|
|
| Server | Hong Kong VPS, Ubuntu 22.04 x86_64 |
|
|
| Public host | `103.117.123.53` |
|
|
| SSH | port `22000`, public-key authentication only |
|
|
| Capacity | 1 vCPU / 2 GB RAM / 40 GB disk / 5 Mbps |
|
|
| App directory | `/opt/jyotisha-app` |
|
|
| Environment file | `/opt/jyotisha-app/.env.production` (`0600`) |
|
|
| Source repository | `https://github.com/jesse-ux/Jyotisha.git` |
|
|
| Supabase project | `vtvnfqmonbfuxmqkqdlc` |
|
|
|
|
This machine is suitable for a client demo and low concurrency. Supabase and the model provider stay managed externally; do not self-host them on this VPS.
|
|
|
|
## Architecture
|
|
|
|
```text
|
|
Spaceship DNS
|
|
-> Caddy :80/:443
|
|
-> web:3000 (Next.js + Mastra, Docker-private)
|
|
-> api:5200 (Python Jyotish API, Docker-private)
|
|
-> Swiss Ephemeris / local engine
|
|
-> VedAstro gateway with local fallback
|
|
-> Supabase Cloud
|
|
-> external OpenAI-compatible model API
|
|
```
|
|
|
|
Only Caddy publishes host ports. Ports `3000` and `5200` must remain private.
|
|
|
|
## DNS and Supabase Auth
|
|
|
|
Spaceship resource records:
|
|
|
|
```text
|
|
A @ 103.117.123.53
|
|
CNAME www jyotisha.chat
|
|
```
|
|
|
|
Supabase Authentication URL Configuration:
|
|
|
|
```text
|
|
Site URL: https://jyotisha.chat
|
|
Redirect URLs: https://jyotisha.chat/**
|
|
https://www.jyotisha.chat/**
|
|
```
|
|
|
|
Before changing Caddy to the domain, verify the authoritative DNS result:
|
|
|
|
```bash
|
|
dig +short @launch1.spaceship.net A jyotisha.chat
|
|
```
|
|
|
|
It must return `103.117.123.53`. Caddy provisions and renews HTTPS automatically after DNS resolves.
|
|
|
|
## Production environment
|
|
|
|
`.env.production` combines the backend and frontend server variables. Required groups:
|
|
|
|
```dotenv
|
|
SITE_ADDRESS=https://jyotisha.chat
|
|
JYOTISH_API_BASE=http://api:5200
|
|
|
|
NEXT_PUBLIC_SUPABASE_URL=...
|
|
NEXT_PUBLIC_SUPABASE_ANON_KEY=...
|
|
SUPABASE_SERVICE_ROLE_KEY=...
|
|
ADMIN_EMAILS=...
|
|
|
|
# Either OpenAI:
|
|
OPENAI_API_KEY=...
|
|
MASTRA_MODEL=...
|
|
|
|
# Or an OpenAI-compatible provider:
|
|
LLM_BASE_URL=...
|
|
LLM_API_KEY=...
|
|
LLM_MODEL=...
|
|
|
|
# Optional VedAstro official upstream; local fallback remains available:
|
|
VEDASTRO_API_ENDPOINT=...
|
|
VEDASTRO_API_KEY=...
|
|
```
|
|
|
|
Never commit `.env.production`, `SUPABASE_SERVICE_ROLE_KEY`, model keys, user JWTs, SSH private keys or passwords. `NEXT_PUBLIC_SUPABASE_ANON_KEY` is intentionally public; authorization is enforced by Supabase RLS and server-side checks.
|
|
|
|
## Connect and inspect
|
|
|
|
```bash
|
|
ssh -p 22000 root@103.117.123.53
|
|
cd /opt/jyotisha-app
|
|
COMPOSE='docker compose --env-file .env.production -f deploy/docker-compose.server.yml'
|
|
$COMPOSE ps
|
|
$COMPOSE logs --tail=100 api web caddy
|
|
free -h
|
|
docker stats --no-stream
|
|
```
|
|
|
|
The server has a persistent 2 GB `/swapfile`. UFW permits only SSH `22000/tcp`, HTTP `80/tcp`, HTTPS `443/tcp`, and the pre-existing WireGuard `51820/udp` rule.
|
|
|
|
## Deploy an update from the maintainer Mac
|
|
|
|
The GitHub repository is private and the VPS does not currently have a GitHub deploy key. Deploy the tracked tree without copying local secrets:
|
|
|
|
```bash
|
|
cd /Users/jesse/Downloads/Copse/astrology/yinduzhanxing
|
|
git status --short --branch
|
|
git archive --format=tar.gz --output=/tmp/jyotisha.tar.gz HEAD
|
|
scp -P 22000 /tmp/jyotisha.tar.gz root@103.117.123.53:/tmp/jyotisha.tar.gz
|
|
ssh -p 22000 root@103.117.123.53 \
|
|
'cd /opt/jyotisha-app && tar -xzf /tmp/jyotisha.tar.gz && rm -f /tmp/jyotisha.tar.gz && docker compose --env-file .env.production -f deploy/docker-compose.server.yml up -d --build'
|
|
```
|
|
|
|
`git archive` does not include ignored `.env` files. Extraction preserves `/opt/jyotisha-app/.env.production`.
|
|
|
|
## Verification
|
|
|
|
```bash
|
|
curl -fsS https://jyotisha.chat/login >/dev/null
|
|
curl -fsS -o /dev/null -w '%{http_code}\n' https://jyotisha.chat/api/account
|
|
```
|
|
|
|
The second command should return `401` while logged out. Verify the private Python API from inside the web container:
|
|
|
|
```bash
|
|
ssh -p 22000 root@103.117.123.53 \
|
|
'cd /opt/jyotisha-app && docker compose --env-file .env.production -f deploy/docker-compose.server.yml exec -T web node -e "fetch(\"http://api:5200/api/health\").then(async r=>{console.log(r.status); console.log(await r.text())})"'
|
|
```
|
|
|
|
Expected: HTTP `200`, `"status": "ok"`, and `"swisseph_available": true`. Public access to `103.117.123.53:5200` must fail.
|
|
|
|
Then manually verify: OTP login, onboarding/profile persistence, chat-session persistence, code redemption, admin code generation, streaming response, one-credit charge, and refund on failure before the first output chunk.
|
|
|
|
## Common operations
|
|
|
|
```bash
|
|
# Restart without rebuilding
|
|
docker compose --env-file .env.production -f deploy/docker-compose.server.yml up -d
|
|
|
|
# Rebuild only the web container
|
|
docker compose --env-file .env.production -f deploy/docker-compose.server.yml up -d --build web caddy
|
|
|
|
# Rebuild only the Python API
|
|
docker compose --env-file .env.production -f deploy/docker-compose.server.yml up -d --build api
|
|
|
|
# Follow logs
|
|
docker compose --env-file .env.production -f deploy/docker-compose.server.yml logs -f --tail=100 api web caddy
|
|
```
|
|
|
|
## Optional Railway deployment
|
|
|
|
Railway is not the current production target. If needed, create `web` and `api` services from the same repository using `deploy/railway-web.Dockerfile` and `deploy/railway-api.Dockerfile`; keep `api` private and set the web service's `JYOTISH_API_BASE` to Railway's private API hostname.
|