DB-VPS bootstrap
Sets up the dedicated database VPS that hosts PostgreSQL, Redis, MinIO, and Kafka behind the provider’s private network. App-VPS workers and api-server connect via the private IP — public ports are never opened.
When to run
- First time the DB-VPS is being provisioned.
- After a host rebuild — bootstrap is idempotent; existing state under
/var/lib/tracium-db/is preserved.
Prerequisites
- Fresh VPS in the same private-network as the App-VPS, ≥4 GB RAM (8 GB recommended once pgvector and Kafka log dirs grow).
- Provider’s private IPs known:
APP_VPS_PRIVATE_IP,DB_VPS_PRIVATE_IP. - Docker engine +
docker composev2 plugin installed. - An unprivileged user with the
dockergroup (e.g.belkanov). - SSH access on a non-default port (this runbook assumes 222).
Step 1 — copy artefacts to the host
From your workstation, sync the compose file and the bootstrap script to the DB-VPS:
scp -P 222 \
deploy/docker/docker-compose.prod-db-infra.yml \
belkanov@<db-vps-host>:/tmp/
scp -P 222 \
deploy/production-runtime/bin/bootstrap-db-vps.sh \
belkanov@<db-vps-host>:/tmp/Step 2 — run the bootstrap script
ssh -p 222 belkanov@<db-vps-host>
sudo /tmp/bootstrap-db-vps.sh /home/belkanovThe script:
- Creates
/var/lib/tracium-db/{postgres,redis,minio,kafka,compose}/. - Pre-sets ownership so first-time container starts don’t trip on bind-mount permissions (PG=UID 999, Kafka/MinIO=UID 1000).
- Generates
/var/lib/tracium-db/compose/.envwith a freshKAFKA_CLUSTER_IDand leaves placeholders for passwords + private IPs. Skips the write if.envalready exists. - Prints the firewall (
ufw) rules to copy-paste.
Step 3 — populate .env
Edit /var/lib/tracium-db/compose/.env. Required fields:
POSTGRES_PASSWORD=<openssl rand -base64 32 | tr -d '\n='>
POSTGRES_BIND_ADDR=<DB_VPS_PRIVATE_IP>
REDIS_BIND_ADDR=<DB_VPS_PRIVATE_IP>
MINIO_ROOT_USER=<≥8 chars>
MINIO_ROOT_PASSWORD=<≥32 chars>
MINIO_BIND_ADDR=<DB_VPS_PRIVATE_IP>
KAFKA_ADVERTISED_HOST=<DB_VPS_PRIVATE_IP>
KAFKA_BIND_ADDR=<DB_VPS_PRIVATE_IP>
# KAFKA_CLUSTER_ID was generated by the script — do not change it.Tune POSTGRES_SHARED_BUFFERS / POSTGRES_EFFECTIVE_CACHE_SIZE per
VPS RAM (see deploy/production-runtime/db-vps/.env.example).
Step 4 — bring the stack up
sudo install -m 0644 /tmp/docker-compose.prod-db-infra.yml \
/var/lib/tracium-db/compose/docker-compose.yml
cd /var/lib/tracium-db/compose
docker compose up -d
docker compose psAll services must report healthy (or started for the *-init jobs).
# verify private-only binding (must be DB_VPS_PRIVATE_IP, never 0.0.0.0)
ss -tlnp | grep -E ':(5432|6379|9000|9092)\b'Step 5 — open firewall
On the DB-VPS:
APP_VPS_IP=<app-vps-private-ip>
sudo ufw allow from "$APP_VPS_IP" to any port 5432 proto tcp comment 'tracium PG'
sudo ufw allow from "$APP_VPS_IP" to any port 6379 proto tcp comment 'tracium Redis'
sudo ufw allow from "$APP_VPS_IP" to any port 9000 proto tcp comment 'tracium MinIO'
sudo ufw allow from "$APP_VPS_IP" to any port 9092 proto tcp comment 'tracium Kafka'
sudo ufw allow 222/tcp
sudo ufw default deny
sudo ufw enableStep 6 — verify from App-VPS
From the App-VPS (ssh -p 222 belkanov@tracium.ru):
# Postgres reachable
PGPASSWORD=$POSTGRES_PASSWORD psql -h $DB_VPS_PRIVATE_IP -U tracium -d tracium -c '\dx'
# expect 'vector' extension once migrations have been applied
# Redis reachable
redis-cli -h $DB_VPS_PRIVATE_IP ping
# MinIO reachable
curl -fsS "http://$DB_VPS_PRIVATE_IP:9000/minio/health/live"
# Kafka reachable
docker run --rm apache/kafka:3.9.0 \
/opt/kafka/bin/kafka-topics.sh \
--bootstrap-server $DB_VPS_PRIVATE_IP:9092 \
--listStep 7 — run migrations
From the App-VPS, point goose at the DB-VPS PG and apply the schema:
GOOSE_DRIVER=postgres \
GOOSE_DBSTRING="host=$DB_VPS_PRIVATE_IP user=tracium password=$POSTGRES_PASSWORD dbname=tracium sslmode=disable" \
goose -dir backend/migrations upStep 8 — activate App-VPS workers
Edit /home/belkanov/apps/tracium/shared/tracium-deploy.env:
POSTGRES_HOST=<DB_VPS_PRIVATE_IP>
POSTGRES_PORT=5432
REDIS_URL=redis://<DB_VPS_PRIVATE_IP>:6379/0
S3_ENDPOINT=http://<DB_VPS_PRIVATE_IP>:9000
KAFKA_BROKERS=<DB_VPS_PRIVATE_IP>:9092Then enable the with-db profile on App-VPS:
cd /home/belkanov/apps/tracium/active
COMPOSE_PROFILES=with-db docker compose -f docker-compose.prod-bluegreen.yml up -dbackend-checks and deploy-production should turn green on the next
pipeline once the workers are up.
Backups (post-launch, week 1)
| What | Where | How |
|---|---|---|
| PG | DB-VPS | pg_dump tracium cron daily, retention 14d |
| MinIO | DB-VPS | rsync /var/lib/tracium-db/minio weekly |
| Kafka | DB-VPS | log dir snapshot weekly (Kafka is event-log, not SOR) |
.env | DB-VPS | manual copy to encrypted store after each rotation |
Rollback
The bootstrap script never deletes data — re-running it is safe. To fully tear down (loses all data):
cd /var/lib/tracium-db/compose
docker compose down
sudo rm -rf /var/lib/tracium-db/See also
deploy/docker/docker-compose.prod-db-infra.yml— the stack itself.deploy/production-runtime/db-vps/.env.example— env template.deploy/production-runtime/bin/bootstrap-db-vps.sh— the script invoked above.- Production environment — App-VPS topology this stack pairs with.
- Live supplier contour — depends on this stack being live before any real-supplier ingest can run.