Production Deployment
This guide covers deploying ByteBrew Engine on a VPS with proper TLS, process management, backups, and monitoring. The target stack is Ubuntu + Docker Compose + Caddy (reverse proxy with automatic Let’s Encrypt SSL).
VPS setup
Section titled “VPS setup”Requirements
Section titled “Requirements”- Ubuntu 22.04+ (or any Linux with Docker support)
- 2+ GB RAM (4 GB recommended for engine + PostgreSQL + Ollama)
- Docker and Docker Compose installed
- A domain name pointed to your server’s IP (e.g.,
engine.yourdomain.com)
Initial setup
Section titled “Initial setup”# Update systemapt update && apt upgrade -y
# Install Dockercurl -fsSL https://get.docker.com | shsystemctl enable docker
# Install Caddyapt install -y debian-keyring debian-archive-keyring apt-transport-httpscurl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpgcurl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.listapt update && apt install -y caddyDocker Compose for production
Section titled “Docker Compose for production”Create /opt/bytebrew/docker-compose.yml:
services: engine: image: bytebrew/engine:latest ports: - "127.0.0.1:8443:8443" # Only bind to localhost (Caddy proxies) environment: - DATABASE_URL=postgresql://bytebrew:${DB_PASSWORD}@postgres:5432/bytebrew - BYTEBREW_AUTH_MODE=local - BYTEBREW_JWT_KEYS_DIR=/var/lib/bytebrew/keys - LLM_API_KEY=${LLM_API_KEY:-} volumes: - keys-data:/var/lib/bytebrew/keys extra_hosts: - "host.docker.internal:host-gateway" # For Ollama on host depends_on: db-migrate: condition: service_completed_successfully restart: unless-stopped healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://localhost:8443/api/v1/health"] interval: 10s timeout: 5s retries: 3 start_period: 20s
db-migrate: image: bytebrew/engine-migrations:latest depends_on: postgres: condition: service_healthy environment: - LIQUIBASE_COMMAND_URL=jdbc:postgresql://postgres:5432/bytebrew - LIQUIBASE_COMMAND_USERNAME=bytebrew - LIQUIBASE_COMMAND_PASSWORD=${DB_PASSWORD} - LIQUIBASE_COMMAND_CHANGELOG_FILE=migrations/db.changelog-master.yaml command: update restart: "no"
postgres: image: pgvector/pgvector:pg16 environment: - POSTGRES_USER=bytebrew - POSTGRES_PASSWORD=${DB_PASSWORD} - POSTGRES_DB=bytebrew volumes: - pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U bytebrew -d bytebrew"] interval: 5s timeout: 3s retries: 5 restart: unless-stopped
volumes: pgdata: keys-data:Create /opt/bytebrew/.env:
# Authentication (required)BYTEBREW_AUTH_MODE=local # Use 'local' for single-node; 'external' for multi-replicaDB_PASSWORD=another-secure-password
# OptionalLLM_API_KEY=sk-your-api-key # Referenced in agent model configsSet restrictive permissions on the file: chmod 600 /opt/bytebrew/.env.
Caddy reverse proxy
Section titled “Caddy reverse proxy”Caddy provides automatic HTTPS with Let’s Encrypt certificates. No manual certificate management required.
Create /etc/caddy/Caddyfile:
engine.yourdomain.com { # API endpoint handle /api/* { reverse_proxy localhost:8443 }
# Webhook endpoints handle /webhooks/* { reverse_proxy localhost:8443 }
# Admin Dashboard handle /admin* { reverse_proxy localhost:8443 }
# Default: API handle { reverse_proxy localhost:8443 }}# Reload Caddysystemctl reload caddy
# Verify TLScurl https://engine.yourdomain.com/api/v1/healthSSL/TLS
Section titled “SSL/TLS”Caddy handles TLS automatically:
- Obtains a Let’s Encrypt certificate on first request.
- Renews certificates automatically before expiration.
- Redirects HTTP to HTTPS by default.
- Supports HTTP/2 out of the box.
No additional configuration needed. Just ensure port 80 and 443 are open in your firewall:
ufw allow 80/tcpufw allow 443/tcpsystemd service (optional)
Section titled “systemd service (optional)”If you want Docker Compose managed by systemd for automatic start on boot:
Create /etc/systemd/system/bytebrew.service:
[Unit]Description=ByteBrew EngineAfter=docker.serviceRequires=docker.service
[Service]Type=oneshotRemainAfterExit=yesWorkingDirectory=/opt/bytebrewExecStart=/usr/bin/docker compose up -dExecStop=/usr/bin/docker compose down
[Install]WantedBy=multi-user.targetsystemctl daemon-reloadsystemctl enable bytebrewsystemctl start bytebrewDatabase backup strategy
Section titled “Database backup strategy”Automated daily backups
Section titled “Automated daily backups”Create /opt/bytebrew/backup.sh:
#!/bin/bashBACKUP_DIR="/opt/bytebrew/backups"TIMESTAMP=$(date +%Y%m%d_%H%M%S)mkdir -p "$BACKUP_DIR"
# Dump the databasedocker compose -f /opt/bytebrew/docker-compose.yml exec -T postgres \ pg_dump -U bytebrew bytebrew | gzip > "$BACKUP_DIR/bytebrew_$TIMESTAMP.sql.gz"
# Keep last 30 daysfind "$BACKUP_DIR" -name "*.sql.gz" -mtime +30 -delete
echo "Backup completed: bytebrew_$TIMESTAMP.sql.gz"chmod +x /opt/bytebrew/backup.sh
# Add to crontab (daily at 3 AM)echo "0 3 * * * /opt/bytebrew/backup.sh" | crontab -Restoring from backup
Section titled “Restoring from backup”gunzip -c backups/bytebrew_20250319_030000.sql.gz | \ docker compose exec -T postgres psql -U bytebrew bytebrewMonitoring
Section titled “Monitoring”Health endpoint polling
Section titled “Health endpoint polling”The /api/v1/health endpoint is unauthenticated and designed for monitoring:
# Simple health check scriptcurl -sf http://localhost:8443/api/v1/health > /dev/null || echo "ByteBrew Engine is DOWN"UptimeRobot / Uptime Kuma
Section titled “UptimeRobot / Uptime Kuma”Point your monitoring service at:
https://engine.yourdomain.com/api/v1/healthExpected response: HTTP 200 with {"status":"ok"}.
Log monitoring
Section titled “Log monitoring”# Follow engine logsdocker compose -f /opt/bytebrew/docker-compose.yml logs -f engine
# Last 100 linesdocker compose -f /opt/bytebrew/docker-compose.yml logs engine --tail 100Resource monitoring
Section titled “Resource monitoring”# Container resource usagedocker stats bytebrew-engine-1 bytebrew-postgres-1Helm Chart (Kubernetes)
Section titled “Helm Chart (Kubernetes)”For Kubernetes deployments, ByteBrew provides a Helm chart that packages the engine (Deployment, Service, Ingress, PVC, Secret) and wires an external PostgreSQL of your choice.
A ready-to-adapt values.example.yaml lives inside the chart folder — copy it, fill the fields marked <REQUIRED>, and install.
# Clone the repogit clone https://github.com/syntheticinc/bytebrewcd bytebrew/engine/deploy/helm
# Copy the example and edit with your domain, PG endpoint, LLM keycp bytebrew/values.example.yaml values.yaml$EDITOR values.yaml
# Dry-run to validate template renderinghelm template bytebrew ./bytebrew -f values.yaml
# Installhelm install bytebrew ./bytebrew -f values.yaml
# Upgrade in place after a new releasehelm upgrade bytebrew ./bytebrew -f values.yamlImage tag
Section titled “Image tag”Pin image.tag to the specific release you validated in staging (e.g. "2.0.0") rather than latest — that makes rollback straightforward (helm rollback bytebrew <rev>) and freezes the admin SPA bundle that ships inside the image.
Single-replica requirement (local auth mode)
Section titled “Single-replica requirement (local auth mode)”replicaCount: 1 is enforced when config.auth.mode: "local" — the Ed25519 keypair is persisted on a single PVC and cannot be shared across pods. For horizontal scaling, switch to config.auth.mode: "external" and provide a pre-generated public key via ConfigMap/Secret (multi-replica safe).
TLS via cert-manager
Section titled “TLS via cert-manager”The example values ship with the annotation commented out. To enable cert-manager-managed Let’s Encrypt certificates, uncomment the annotation in values.yaml and install cert-manager + your ClusterIssuer first:
ingress: annotations: cert-manager.io/cluster-issuer: letsencrypt-prod tls: - secretName: bytebrew-tls hosts: - bytebrew.example.comKey Helm values
Section titled “Key Helm values”| Value | Default | Description |
|---|---|---|
replicaCount | 1 | Number of engine replicas. |
image.tag | latest | Engine image tag. |
postgresql.enabled | true | Deploy PostgreSQL as a subchart. Set to false for external DB. |
postgresql.external.host | — | External PostgreSQL host (when postgresql.enabled=false). |
postgresql.external.password | — | External PostgreSQL password. |
config.auth.mode | local | Auth mode: local (single-node, auto-generated keypair) or external (multi-replica, pre-provisioned key). |
config.auth.jwtKeysPath | /var/lib/bytebrew/keys | PVC mount path for keypair storage (local mode only). |
config.auth.jwtPublicKeyPath | — | Path to public key file (external mode only). |
ingress.enabled | false | Enable Kubernetes Ingress. |
ingress.hosts[0].host | — | Hostname for the Ingress rule. |
serviceMonitor.enabled | false | Create a Prometheus ServiceMonitor (requires prometheus-operator). |
Prometheus Metrics (EE)
Section titled “Prometheus Metrics (EE)”The engine exposes Prometheus-compatible metrics at the /metrics endpoint. This is an Enterprise Edition feature.
Available metrics
Section titled “Available metrics”| Metric | Type | Labels | Description |
|---|---|---|---|
bytebrew_http_requests_total | Counter | method, path, status | Total HTTP requests by method, path, and status code. |
bytebrew_http_request_duration_seconds | Histogram | method, path | HTTP request latency in seconds. |
bytebrew_active_sessions | Gauge | — | Number of currently active chat sessions. |
bytebrew_tool_calls_total | Counter | tool_name, status | Total tool invocations by name and outcome. |
bytebrew_llm_requests_total | Counter | provider, model | Total LLM API calls by provider and model. |
bytebrew_llm_request_duration_seconds | Histogram | provider, model | LLM API call latency in seconds. |
Scraping
Section titled “Scraping”# Manual checkcurl http://localhost:8443/metricsKubernetes ServiceMonitor
Section titled “Kubernetes ServiceMonitor”If you use the Prometheus Operator, enable the ServiceMonitor in the Helm chart:
serviceMonitor: enabled: true interval: 15s labels: release: prometheus # Must match your Prometheus selectorOr create a ServiceMonitor manually:
apiVersion: monitoring.coreos.com/v1kind: ServiceMonitormetadata: name: bytebrew-engine labels: release: prometheusspec: selector: matchLabels: app: bytebrew-engine endpoints: - port: http path: /metrics interval: 15sGrafana dashboard
Section titled “Grafana dashboard”Import the metrics into a Grafana dashboard to monitor:
- Request rate and latency (
bytebrew_http_requests_total,bytebrew_http_request_duration_seconds) - Active sessions (
bytebrew_active_sessions) - Tool call success/failure rates (
bytebrew_tool_calls_total) - LLM provider latency and usage (
bytebrew_llm_requests_total,bytebrew_llm_request_duration_seconds)
Security checklist
Section titled “Security checklist”- Set
BYTEBREW_AUTH_MODE=localin.env(orexternalfor multi-replica) -
keys-datavolume persists across restarts (do NOT use ephemeral storage) - Access Admin Dashboard at
https://engine.yourdomain.com/adminto create first admin user - Use strong, unique
DB_PASSWORD -
.envfile haschmod 600 - Only
127.0.0.1port binding (Caddy handles external access) - Firewall allows only ports 80, 443, and SSH (22)
- HTTPS enforced (Caddy auto-manages Let’s Encrypt certificates)
- API keys use
${VAR}in YAML, never hardcoded - Create scoped API tokens instead of sharing admin JWTs
- Automated database backups running (daily snapshots of
pgdatavolume) - Monitor HMAC key rotation schedule (90-day window for metering secrets)