Self-Hosting

Deploy Syntropic137 on your own infrastructure, from bare metal to Kubernetes

Deployment Architecture

Syntropic137 runs as a set of Docker services connected through a shared network:

Quick Start with Docker Compose

npx @syntropic137/setup init

The setup wizard handles everything: Docker validation, secret generation, API key configuration, image pulls, and starting the stack. See Getting Started for the full walkthrough.

The dashboard will be available at http://localhost:8137.

Services

ServicePortDescription
api8000FastAPI backend: REST API, SSE
gateway80nginx reverse proxy + React dashboard frontend
event-store50051gRPC event sourcing server
event-collector8080High-throughput event ingestion
timescaledb5432PostgreSQL + TimescaleDB for events and metrics
redis6379Caching, pub/sub, projection store
minio9000S3-compatible artifact storage

Workspace Isolation

Each agent execution runs in an isolated Docker workspace with a two-phase security model:

Setup Phase: Secrets are available briefly to configure credential helpers. Raw tokens are cleared before the agent starts.

Agent Phase: A claude phase runs with its Anthropic credential, ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN, as its only runtime secret. A codex phase runs with an empty agent environment, its credential having been staged to ~/.codex/auth.json during provisioning. CODEX_AUTH_JSON is a deployment variable, not something the agent sees. Git operations use cached credentials from the setup phase.

AppArmor hosts (Codex workspaces)

On a Linux host whose Docker daemon enforces AppArmor (Ubuntu 24.04 and most Debian/Ubuntu servers; docker info lists name=apparmor under Security Options), Codex workspaces run under the AppArmor profile agentic-codex-sandbox: Docker's default profile with its blanket deny mount, replaced by only the mounts the Codex sandbox (bubblewrap) performs. The workspace refuses to start until that profile is loaded, and the execution fails with the provision reason apparmor_profile_not_loaded naming the fix.

Load it once on the Docker host. It is persisted under /etc/apparmor.d, so it loads again at every boot:

# From a repository checkout (also run automatically by `just selfhost-up`):
just apparmor-setup

# Without a checkout, copy the profile shipped in the running API image:
docker exec syn137-api python -c \
  "from agentic_isolation import codex_sandbox_apparmor_profile_path as p; print(p().read_text(), end='')" \
  | sudo tee /etc/apparmor.d/agentic-codex-sandbox >/dev/null
sudo apparmor_parser -r /etc/apparmor.d/agentic-codex-sandbox

just selfhost-update re-runs this step on every update, before restarting services. On an npx install, re-run the two commands above after each update.

Workspace image after an update

.env.example carries the default workspace image digest, and a SYN_WORKSPACE_DOCKER_IMAGE value in .env overrides the built-in default. just selfhost-update replaces a value that is a default shipped by an older release with the new default and prints the change; any other value is treated as your own override and left alone. The API also logs a warning at startup when the configured image is an older shipped default. On an npx install, remove the variable from .env (or set it to the new digest) after updating. Hosts without AppArmor (macOS, Docker Desktop) need nothing; just apparmor-setup skips them. The profile adds no capabilities, never uses apparmor=unconfined, and leaves host sysctls alone.

Environment Variables

VariableDefaultDescription
APP_ENVIRONMENTdevelopmentEnvironment mode (development, production)
TIMESCALEDB_HOSTlocalhostTimescaleDB hostname
TIMESCALEDB_PORT5432TimescaleDB port
REDIS_URLredis://localhost:6379Redis connection URL
MINIO_ENDPOINTlocalhost:9000MinIO S3 endpoint
MINIO_ACCESS_KEYMinIO access key
MINIO_SECRET_KEYMinIO secret key
GITHUB_APP_IDGitHub App ID for webhook triggers
GITHUB_APP_PRIVATE_KEYGitHub App private key (PEM)
ANTHROPIC_API_KEYAPI key for claude phases. CLAUDE_CODE_OAUTH_TOKEN takes priority when both are set
CODEX_AUTH_JSONFull contents of a Codex ~/.codex/auth.json. Required for codex phases, unused by claude phases

Scaling Options

Single Server (Self-Host)

Recommended for 10–100 concurrent agents:

  • 4+ CPU cores, 8GB+ RAM (16GB recommended)
  • 500GB NVMe storage
  • Docker with workspace pooling (10–50 containers)

Multi-Server

For 100–1,000 concurrent agents, run multiple Syntropic137 instances behind a load balancer:

Kubernetes

For 1,000+ concurrent agents with auto-scaling:

  • Use Kata Containers runtime for workspace isolation
  • HPA with 70% CPU target, 3–20 replicas
  • PersistentVolume for artifact storage

Authentication

Gateway credentials

The nginx gateway uses HTTP Basic Auth to protect external access. During npx @syntropic137/setup init, a strong random password (~256 bits of entropy) is generated automatically and stored in ~/.syntropic137/.env.

The setup wizard never prints the password to the terminal. Retrieve it from ~/.syntropic137/.env when needed:

# View password
grep SYN_API_PASSWORD ~/.syntropic137/.env | cut -d= -f2

# Copy to clipboard (macOS)
grep SYN_API_PASSWORD ~/.syntropic137/.env | cut -d= -f2 | pbcopy

# Set env vars for the syn CLI
export SYN_API_USER=admin
export SYN_API_PASSWORD=$(grep SYN_API_PASSWORD ~/.syntropic137/.env | cut -d= -f2)

To rotate credentials (generates a new password and restarts the stack):

npx @syntropic137/setup credentials rotate

Port model

The gateway exposes two ports with different auth policies:

PortAuthUsed by
80NoneDocker health checks, internal service traffic, local dev (localhost:8137)
8081Basic AuthCloudflare Tunnel, any external access

If you use Cloudflare Tunnel, your tunnel config must route to http://gateway:8081 (not localhost:8137). The setup wizard enforces this: npx @syntropic137/setup tunnel will exit with an error if SYN_API_PASSWORD is not set.

See the Tunnels guide for full setup instructions.

Tunnels (Optional)

For secure external access and GitHub Actions webhook delivery, set up a tunnel. Syntropic137 includes built-in Cloudflare Tunnel support via a Docker Compose profile.

See the Tunnels guide for setup instructions.

Secrets

Infrastructure secrets (database, Redis, MinIO) are stored as chmod 600 files and mounted via Docker Compose's secrets mechanism, never baked into image layers. Application-level API keys (e.g. ANTHROPIC_API_KEY) are supplied via environment variables.

See Secrets Management for details on how secrets work and optional 1Password integration.

Syntropic137 Docs v0.33.1 · Last updated March 2026

On this page