Deploy¶
GitHub Actions → VPS (auto-deploy)¶
After CI succeeds on main, .github/workflows/deploy.yml SSHs to the VPS and deploys into /home/smdg/agentbi.
Required repository secrets: VPS_HOST, VPS_USER, VPS_SSH_KEY.
Production stack (docker-compose.prod.yml):
- No public host ports for API/UI/DB/Redis
- Frontend joins Traefik network
agentops-edge - HTTPS via file route in
$TRAEFIK_DIR/agentbi.ymlwhenAGENTBI_DOMAINis set - Images tagged
agentbi-api:<git-sha>/agentbi-frontend:<git-sha>(IMAGE_TAG)
Manual run: Actions → Deploy to VPS → Run workflow.
First-time VPS setup¶
```bash cd /home/smdg/agentbi # after first clone by Actions, or git clone manually cp .env.production.example .env
Set strong POSTGRES_PASSWORD, REDIS_PASSWORD, SECRET_KEY, ADMIN_PASSWORD¶
Set AGENTBI_DOMAIN and CORS_ORIGINS=https://$AGENTBI_DOMAIN¶
DNS A-record → VPS (see https://github.com/valera7623/AgentBI/blob/main/deploy/DNS.md)¶
chmod +x deploy.sh scripts/.sh scripts/vps/.sh export COMPOSE_FILE=docker-compose.prod.yml ./deploy.sh ```
deploy.sh phases:
- Pre-checks — clean git (or
SKIP_GIT_CLEAN=1on Actions),requirements-lock.txt - Build API before migrate (so Alembic sees new revisions)
- Pre-migrate Postgres backup (gzip, keep last 7) — abort if backup fails
alembic upgrade head+ verify schema head- Start stack with SHA-tagged images, write
VERSION, health +/api/v1/version
Useful flags: ./deploy.sh --help, --skip-backup, --run-tests, --allow-dirty.
Isolated demo stand (AgentOps pattern)¶
Demo data must never land in the production Postgres. AgentBI follows AgentOps:
| Surface | Stack |
|---|---|
https://agentbi.online |
api → timescaledb (prod) |
https://demo.agentbi.online |
api-demo → postgres-demo (isolated volume) |
```bash
On the VPS .env — merge from .env.demo (keep SEED_DEMO_DATA=false for prod)¶
AGENTBI_DEMO_DOMAIN=demo.agentbi.online CORS_ORIGINS=https://agentbi.online,https://demo.agentbi.online
DNS A-record demo.agentbi.online → VPS¶
COMPOSE_FILE=docker-compose.prod.yml ./deploy.sh COMPOSE_FILE=docker-compose.prod.yml ./scripts/run_demo_data.sh ```
docker-compose.prod.yml hard-disables DEMO_USER_ENABLED / DEMO_SEED_ON_START on the prod api service. The overlay docker-compose.demo.yml enables them only on api-demo.
Verify:
```bash curl -sf https://$AGENTBI_DOMAIN/api/v1/health/ready curl -sf https://$AGENTBI_DOMAIN/api/v1/version
or without DNS yet:¶
docker exec agentbi-api curl -sf http://localhost:8000/api/v1/health/ready ```
Backups & restore¶
Pre-migrate backups run automatically from deploy.sh. Manual / cron:
```bash ./scripts/backup_postgres.sh --help
cron (daily 02:15):¶
15 2 * * * cd /home/smdg/agentbi && ./scripts/backup_postgres.sh >>/var/log/agentbi-backup.log 2>&1¶
```
Files: ./backups/backup_YYYYMMDD_HHMMSS[_SHA].dump.gz (pg_dump -Fc + gzip). Rotation keeps the last 7. Copy off-host (e.g. /home/smdg/backups-offsite).
```bash ./scripts/restore_postgres.sh --file backups/backup_YYYYMMDD_HHMMSS.dump.gz
type "restore" to confirm¶
```
Rollback¶
bash
./scripts/rollback.sh --sha "$(cat VERSION.prev)" # previous image tags
./scripts/rollback.sh --sha <sha> --restore backups/….gz # image + DB
Requires local images agentbi-api:<sha> / agentbi-frontend:<sha> from a prior deploy.
VPS ops (shared host)¶
Same VM also runs AgentOps / AegisAI. Host helpers live in scripts/vps/:
```bash
Install docker prune cron (user smdg, docker group — no root)¶
./scripts/vps/install_vps_ops.sh
Cron (example):¶
15 2 * * * agentbi backup¶
15 3 * * * /home/smdg/bin/docker-prune-safe¶
Safe prune: stopped containers, dangling images, old build cache — never volumes¶
/home/smdg/bin/docker-prune-safe
One-time 2G swapfile (swappiness=10) — needs sudo:¶
sudo /home/smdg/bin/setup-swapfile swapon --show && free -h ```
Tenant domains¶
Two different fields on tenants:
| Field | Purpose | UI |
|---|---|---|
allowed_email_domains |
Google SSO email → tenant mapping (unique across tenants) | Users → Organizations |
custom_domain |
Vanity hostname for future routing (unique, optional) | Settings → Domain |
custom_domain is DB-only — DNS / Traefik / Let's Encrypt are manual.
Stripe return URLs¶
bash
STRIPE_SUCCESS_URL=https://$AGENTBI_DOMAIN/src/pages/settings.html?billing=success
STRIPE_CANCEL_URL=https://$AGENTBI_DOMAIN/src/pages/settings.html?billing=cancel
Defaults (if unset) use SSO_FRONTEND_URL / SSO_PUBLIC_BASE_URL + the same paths.
Paid plans (pro / business) unlock features only while subscription_status is active or trialing; otherwise entitlements fall back to free. enterprise is assigned by super_admin and is not gated on Stripe status.
Sentry & alerts¶
- Set
SENTRY_DSN(+ optionalSENTRY_SEND_DEFAULT_PII,SENTRY_TRACES_SAMPLE_RATE). - Events tagged
release=agentbi@<GIT_SHA>,environment=<APP_ENV>. - Unhandled exceptions and HTTP 5xx are captured.
Recommended Sentry alerts: error spike, new issue → Slack/email, regression after new release. Optional uptime check on GET /api/v1/health/ready.
Dependencies & CI¶
- Production/CI install from
requirements-lock.txt(uv pip compile requirements.txt -o requirements-lock.txt). ./scripts/check_lockfile.shmust pass in CI.- Coverage gate: ≥ 55% (
--cov-fail-under=55); HTML artifact uploaded from CI. Stretch goal: 70%.
Local development¶
bash
cp .env.example .env
docker compose up --build -d
curl http://localhost:8000/api/v1/health/ready
curl http://localhost:8000/api/v1/version
TimescaleDB¶
Default images use PostgreSQL 15. Hypertables enable only when the Timescale extension is present.
yaml
image: timescale/timescaledb:latest-pg15
Otherwise AgentBI runs on plain Postgres (supported for production SaaS).