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
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:
A @ 103.117.123.53
CNAME www jyotisha.chat
Supabase Authentication URL Configuration:
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:
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:
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
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:
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
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:
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
# 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.