Vetrix Docs

Docker Deployment

Vetrix ships as a minimal Alpine-based Docker image. This guide covers single-server deployment using Docker Compose.

Prerequisites

  • Docker 24+ with BuildKit
  • Docker Compose v2 (docker compose, not docker-compose)
  • A domain name (or use localhost for local testing)

Quick start (local)

# 1. Clone the repository or download a release tarball
git clone https://github.com/your-org/vetrix
cd vetrix

# 2. Generate secrets
export JWT_SECRET=$(openssl rand -hex 32)
export POSTGRES_PASSWORD=$(openssl rand -hex 24)
export SECRET_ENC_KEY=$(openssl rand -hex 32)

# 3. Start services
docker compose up -d

# 4. Wait for readiness
until curl -sf http://localhost:3000/api/v1/ready; do sleep 2; done

# 5. Create the admin account (first-run wizard)
curl -X POST http://localhost:3000/api/v1/setup \
     -H 'Content-Type: application/json' \
     -d '{"username":"admin","email":"admin@example.com","password":"CHANGE_ME"}'

Automated single-server install

The scripts/install.sh script handles Docker installation, secret generation, systemd unit creation, and first-run in one step:

curl -fsSL https://raw.githubusercontent.com/your-org/vetrix/main/scripts/install.sh \
  | VETRIX_DOMAIN=git.example.com bash

Environment variables

Variable Required Description
DATABASE_URL Yes PostgreSQL DSN, e.g. postgres://vetrix:pass@db:5432/vetrix?sslmode=disable
JWT_SECRET Yes ≥32-char random string for token signing
SECRET_ENC_KEY Required once any webhook / encrypted backup / admin secret is stored 64-char hex string (32 bytes) for encrypting credentials at rest. Startup refuses to boot when this is unset or malformed and any dependent row exists; a brand-new install may boot without it (with a loud WARN) but will not accept new secrets until it is configured.
POSTGRES_PASSWORD Yes (Compose) PostgreSQL password (used by the db service)
SERVER_PORT No Override HTTP port (default: 3000)
SSH_PORT No Override SSH port (default: 2222)
GIT_REPO_ROOT No Path for bare repositories (default: /data/repositories)

Volumes

Mount Purpose
/data/repositories Bare git repositories
/data/ssh SSH host key (auto-generated on first start)

Mount a persistent volume at /data to survive container restarts.

Building the image

# Build server image (default target)
docker build -t vetrix:latest .

# Build worker image (CI/CD runner)
docker build --target worker -t vetrix-worker:latest .

# Multi-arch build
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t vetrix:latest \
  --push .

Upgrading

Vetrix applies pending database migrations automatically on startup. To upgrade:

docker compose pull
docker compose up -d

The server will run migrations before accepting traffic. The readiness probe at /api/v1/ready returns 503 until migrations complete.

Health probes

Endpoint Type Returns
GET /api/v1/health Liveness 200 always
GET /api/v1/ready Readiness 200 when DB reachable, 503 otherwise

Production hardening checklist

  • Set external_url in app.toml to your public HTTPS URL
  • Terminate TLS in front of Vetrix (nginx, Traefik, or a load balancer)
  • Restrict port 3000 to the reverse proxy; do not expose it publicly
  • Use a dedicated PostgreSQL instance (not the Compose db service) for production
  • Back up /data/repositories and the PostgreSQL database on a schedule
  • Rotate JWT_SECRET periodically (invalidates existing tokens — users must re-login)