docs: record production deployment and maintenance
This commit is contained in:
+130
-36
@@ -1,62 +1,156 @@
|
||||
# Railway deployment
|
||||
# Production deployment and maintenance
|
||||
|
||||
Create services named `web` and `api` from this repository. Leave both **Root Directory** and **Start Command** empty; the Dockerfiles bind `0.0.0.0` and read `$PORT`.
|
||||
This file is the operational source of truth for the current Jyotisha demo deployment.
|
||||
|
||||
| Service | Required variable | Healthcheck Path |
|
||||
| --- | --- | --- |
|
||||
| `web` | `RAILWAY_DOCKERFILE_PATH=/deploy/railway-web.Dockerfile` | `/login` |
|
||||
| `api` | `RAILWAY_DOCKERFILE_PATH=/deploy/railway-api.Dockerfile` | `/api/health` |
|
||||
## Current production
|
||||
|
||||
## `api` variables
|
||||
| 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` |
|
||||
|
||||
```dotenv
|
||||
PORT=5200
|
||||
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
|
||||
```
|
||||
|
||||
`PORT` is set explicitly so the web service can reference the private API port. Railway healthchecks and the container command use the same value. No public API domain or legacy `jyotish-app/` service is needed.
|
||||
Only Caddy publishes host ports. Ports `3000` and `5200` must remain private.
|
||||
|
||||
## `web` variables
|
||||
## DNS and Supabase Auth
|
||||
|
||||
Required:
|
||||
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
|
||||
JYOTISH_API_BASE=http://${{api.RAILWAY_PRIVATE_DOMAIN}}:${{api.PORT}}
|
||||
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=...
|
||||
|
||||
For AI responses, configure either:
|
||||
|
||||
```dotenv
|
||||
# Either OpenAI:
|
||||
OPENAI_API_KEY=...
|
||||
MASTRA_MODEL=openai/gpt-5-mini
|
||||
```
|
||||
MASTRA_MODEL=...
|
||||
|
||||
or an OpenAI-compatible provider:
|
||||
|
||||
```dotenv
|
||||
# Or an OpenAI-compatible provider:
|
||||
LLM_BASE_URL=...
|
||||
LLM_API_KEY=...
|
||||
LLM_MODEL=...
|
||||
# LLM_PROVIDER_ID=third-party
|
||||
|
||||
# Optional VedAstro official upstream; local fallback remains available:
|
||||
VEDASTRO_API_ENDPOINT=...
|
||||
VEDASTRO_API_KEY=...
|
||||
```
|
||||
|
||||
`ADMIN_EMAILS=admin@example.com,ops@example.com` is required to use `/admin/codes`. Generate a public domain only for `web`.
|
||||
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.
|
||||
|
||||
|
||||
## After the first deploy
|
||||
|
||||
1. Add the generated `web` domain to Supabase Auth **Site URL** and **Redirect URLs**.
|
||||
2. Open `/login`, sign in with an address listed in `ADMIN_EMAILS`, then verify `/admin/codes`.
|
||||
3. Keep `api` private; verify its `/api/health` from Railway logs or the `web` service.
|
||||
|
||||
## Small VPS deployment
|
||||
|
||||
For a single low-traffic server, keep Supabase managed and run only the Web and API services:
|
||||
## Connect and inspect
|
||||
|
||||
```bash
|
||||
docker compose --env-file .env.production -f deploy/docker-compose.server.yml up -d --build
|
||||
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
|
||||
```
|
||||
|
||||
Set `SITE_ADDRESS=http://SERVER_IP` for initial HTTP testing. Replace it with the production domain after DNS resolves; Caddy will then provision HTTPS automatically.
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user