Updates & Maintenance
tvaras updates are delivered as Docker images and gated by your license. Updates are automatic via cron, or can be triggered manually.
How Updates Work
The update.sh script on your VM handles the entire update process:
- Validates your license key against
tvaras.ai - Obtains a short-lived Docker registry token
- Pulls the latest image from
ghcr.io - Syncs
docker-compose.prod.ymlfrom the image (compose-level changes ship with each release; a timestamped backup of your previous file is kept) - Performs a zero-downtime rollover of the app service
- Logs out from the registry
If your license is expired or revoked, the script exits without pulling — your existing installation continues running on the last pulled version.
Zero-Downtime Rollover
Since v0.108.0, updates do not take the app down — not even briefly:
- A new app container starts alongside the running one.
- It must pass a content-verified readiness probe (
/health/ready: database reachable, full route table registered, version readable) before anything changes. If it never turns healthy, it is removed and the old container keeps serving — a failed update cannot take your installation down. - Once healthy, traffic flows to both containers for a few seconds (nginx resolves the app per request via Docker DNS), then the old container is retired with a graceful 60-second drain. Open chats reconnect automatically.
- Background workers (schedules, task runner, syncs) run on exactly one container at a time via a database leader lock, so nothing double-fires during the overlap.
nginx configuration changes ship inside the image and are applied with an in-place re-render and graceful reload — no dropped connections.
Automatic Updates
The recommended setup is a cron job that checks for updates every 30 minutes:
*/30 * * * * cd /root/data-bot && ./update.sh >> /var/log/dbt-update.log 2>&1
If no new image is available, docker pull is a no-op and nothing is restarted.
Manual Updates
cd /root/data-bot && sudo ./update.sh
Viewing Update Logs
# Recent update log
cat /var/log/dbt-update.log
# Application logs (the app service is named tvaras-backend since v0.108.0)
cd /root/data-bot && docker compose logs tvaras-backend --tail 50
# All container statuses
docker ps
Maintenance Tasks
Restarting services
cd /root/data-bot
docker compose -f docker-compose.prod.yml restart tvaras-backend
(For an update without downtime, prefer ./update.sh — a plain restart briefly stops the app.)
Viewing logs
# Follow logs in real-time
cd /root/data-bot && docker compose logs -f tvaras-backend
# Filter by conversation
docker logs $(docker ps -q -f label=com.docker.compose.service=tvaras-backend) 2>&1 | grep '[conv=abc123'
SSL certificate renewal
Certbot auto-renews via systemd timer. To manually renew:
certbot renew
docker compose -f docker-compose.prod.yml restart nginx
Database backup
docker exec dbt-postgres pg_dump -U dbt dbt_assistant > backup_$(date +%Y%m%d).sql
Disk usage
# Docker volumes
docker system df -v
# Clean unused images (also runs automatically every 6h)
docker image prune -f
Rollback
If an update causes issues, you can roll back to a previous image by specifying its SHA tag:
# List available image tags
docker images ghcr.io/vej-ai/data-bot
# Run a specific version
DBT_IMAGE=ghcr.io/vej-ai/data-bot:abc1234 docker compose -f docker-compose.prod.yml up -d
What Gets Updated
| Component | Auto-updated | Notes |
|---|---|---|
| Application code | Yes | Inside Docker image |
| Frontend | Yes | Built into image |
| Database schema | Yes | Migrations run on startup |
docker-compose.prod.yml | Yes | Synced from the image on every update (backup kept) |
| Nginx config | Yes | Ships inside the image; applied with a graceful reload |
update.sh | No | Lives on host; deliberately never self-updates |
.env | No | Your configuration; never touched |