Skip to content

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).

  • 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)
Terminal window
# Update system
apt update && apt upgrade -y
# Install Docker
curl -fsSL https://get.docker.com | sh
systemctl enable docker
# Install Caddy
apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
apt update && apt install -y caddy

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:

Terminal window
# Authentication (required)
BYTEBREW_AUTH_MODE=local # Use 'local' for single-node; 'external' for multi-replica
DB_PASSWORD=another-secure-password
# Optional
LLM_API_KEY=sk-your-api-key # Referenced in agent model configs

Set restrictive permissions on the file: chmod 600 /opt/bytebrew/.env.

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
}
}
Terminal window
# Reload Caddy
systemctl reload caddy
# Verify TLS
curl https://engine.yourdomain.com/api/v1/health

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:

Terminal window
ufw allow 80/tcp
ufw allow 443/tcp

If you want Docker Compose managed by systemd for automatic start on boot:

Create /etc/systemd/system/bytebrew.service:

[Unit]
Description=ByteBrew Engine
After=docker.service
Requires=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/bytebrew
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
[Install]
WantedBy=multi-user.target
Terminal window
systemctl daemon-reload
systemctl enable bytebrew
systemctl start bytebrew

Create /opt/bytebrew/backup.sh:

#!/bin/bash
BACKUP_DIR="/opt/bytebrew/backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"
# Dump the database
docker 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 days
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +30 -delete
echo "Backup completed: bytebrew_$TIMESTAMP.sql.gz"
Terminal window
chmod +x /opt/bytebrew/backup.sh
# Add to crontab (daily at 3 AM)
echo "0 3 * * * /opt/bytebrew/backup.sh" | crontab -
Terminal window
gunzip -c backups/bytebrew_20250319_030000.sql.gz | \
docker compose exec -T postgres psql -U bytebrew bytebrew

The /api/v1/health endpoint is unauthenticated and designed for monitoring:

Terminal window
# Simple health check script
curl -sf http://localhost:8443/api/v1/health > /dev/null || echo "ByteBrew Engine is DOWN"

Point your monitoring service at:

https://engine.yourdomain.com/api/v1/health

Expected response: HTTP 200 with {"status":"ok"}.

Terminal window
# Follow engine logs
docker compose -f /opt/bytebrew/docker-compose.yml logs -f engine
# Last 100 lines
docker compose -f /opt/bytebrew/docker-compose.yml logs engine --tail 100
Terminal window
# Container resource usage
docker stats bytebrew-engine-1 bytebrew-postgres-1

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.

Terminal window
# Clone the repo
git clone https://github.com/syntheticinc/bytebrew
cd bytebrew/engine/deploy/helm
# Copy the example and edit with your domain, PG endpoint, LLM key
cp bytebrew/values.example.yaml values.yaml
$EDITOR values.yaml
# Dry-run to validate template rendering
helm template bytebrew ./bytebrew -f values.yaml
# Install
helm install bytebrew ./bytebrew -f values.yaml
# Upgrade in place after a new release
helm upgrade bytebrew ./bytebrew -f values.yaml

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).

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.com
ValueDefaultDescription
replicaCount1Number of engine replicas.
image.taglatestEngine image tag.
postgresql.enabledtrueDeploy PostgreSQL as a subchart. Set to false for external DB.
postgresql.external.hostExternal PostgreSQL host (when postgresql.enabled=false).
postgresql.external.passwordExternal PostgreSQL password.
config.auth.modelocalAuth mode: local (single-node, auto-generated keypair) or external (multi-replica, pre-provisioned key).
config.auth.jwtKeysPath/var/lib/bytebrew/keysPVC mount path for keypair storage (local mode only).
config.auth.jwtPublicKeyPathPath to public key file (external mode only).
ingress.enabledfalseEnable Kubernetes Ingress.
ingress.hosts[0].hostHostname for the Ingress rule.
serviceMonitor.enabledfalseCreate a Prometheus ServiceMonitor (requires prometheus-operator).

The engine exposes Prometheus-compatible metrics at the /metrics endpoint. This is an Enterprise Edition feature.

MetricTypeLabelsDescription
bytebrew_http_requests_totalCountermethod, path, statusTotal HTTP requests by method, path, and status code.
bytebrew_http_request_duration_secondsHistogrammethod, pathHTTP request latency in seconds.
bytebrew_active_sessionsGaugeNumber of currently active chat sessions.
bytebrew_tool_calls_totalCountertool_name, statusTotal tool invocations by name and outcome.
bytebrew_llm_requests_totalCounterprovider, modelTotal LLM API calls by provider and model.
bytebrew_llm_request_duration_secondsHistogramprovider, modelLLM API call latency in seconds.
Terminal window
# Manual check
curl http://localhost:8443/metrics

If you use the Prometheus Operator, enable the ServiceMonitor in the Helm chart:

values.yaml
serviceMonitor:
enabled: true
interval: 15s
labels:
release: prometheus # Must match your Prometheus selector

Or create a ServiceMonitor manually:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: bytebrew-engine
labels:
release: prometheus
spec:
selector:
matchLabels:
app: bytebrew-engine
endpoints:
- port: http
path: /metrics
interval: 15s

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)
  • Set BYTEBREW_AUTH_MODE=local in .env (or external for multi-replica)
  • keys-data volume persists across restarts (do NOT use ephemeral storage)
  • Access Admin Dashboard at https://engine.yourdomain.com/admin to create first admin user
  • Use strong, unique DB_PASSWORD
  • .env file has chmod 600
  • Only 127.0.0.1 port 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 pgdata volume)
  • Monitor HMAC key rotation schedule (90-day window for metering secrets)