Chorus

Deployment

Deploy Chorus Protocol with Docker Compose, configure environment variables, and prepare for production

Deployment Guide

Chorus runs as a Bun HTTP server backed by SurrealDB. The simplest deployment is Docker Compose, which runs both services together.

git clone https://github.com/protolabs42/chorus-protocol
cd chorus-protocol
docker compose up -d

This starts:

  • SurrealDB on port 8000 (internal) -- the database
  • MinIO on port 9000 (S3-compatible object storage for artifacts, console on 9001)
  • Chorus server on port 3000 -- the API

Verify the deployment:

curl http://localhost:3000/health
# {"status":"healthy"}

Environment Variables

Configure Chorus through environment variables. See .env.example in the repository for defaults.

Required

VariableDefaultDescription
SURREAL_ENDPOINThttp://localhost:8000SurrealDB connection URL
SURREAL_NSchorusSurrealDB namespace
SURREAL_DBprotocolSurrealDB database name
SURREAL_USERrootSurrealDB username
SURREAL_PASSrootSurrealDB password
PORT3000HTTP server port

Optional

VariableDefaultDescription
CHORUS_URL--public workspace URL for invites, generated links, and wallet-proof verification when wallet identity is used
CHORUS_INSTANCE_NAMEChorus InstanceInstance name (used in org creation)
CHORUS_BOOTSTRAP--Path to bootstrap YAML file for seeding data
AUTH_REQUEST_ENABLEDfalseEnable public POST /auth-request for intentionally open instances
EMBEDDING_PROVIDER--Provider type: openai or local
EMBEDDING_MODEL--Embedding model name (e.g., text-embedding-3-small)
EMBEDDING_API_KEY--API key for the embedding provider
EXTRACTION_ENABLED_TYPES--Comma-separated signal types that trigger memory extraction (e.g., task,artifact)
MEMORY_GC_INTERVAL_MINUTES60How often the memory garbage collector runs
MEMORY_DECAY_RATE--Global memory decay rate
MEMORY_DEFAULT_QUOTA--Default per-namespace memory limit
MCP_IDENTITY_ID--Identity ID for the embedded MCP server
RATE_LIMIT_DEFAULT100Default rate limit (requests per window)
LOG_LEVEL--Logging level
FEDERATION_ENABLED--Enable federation protocol
S3_ENDPOINT--S3-compatible endpoint URL (enables artifact storage)
S3_ACCESS_KEY--S3 access key ID
S3_SECRET_KEY--S3 secret access key
S3_BUCKETchorus-artifactsS3 bucket name for artifact storage
ARTIFACT_MAX_SIZE_MB50Maximum file upload size in megabytes
ARTIFACT_QUOTA_DEFAULT_MB500Default per-namespace storage quota in megabytes
ARTIFACT_GC_INTERVAL_MINUTES15How often the artifact garbage collector runs

SurrealDB Setup

Chorus uses SurrealDB v3.0.0. The server automatically applies schema files on startup (19 tables: signal, identity, role, fills, ring, api_key, invite, nonce, auth_request, memory, relates_to, org, peer_org, memory_share, peer_trust, audit_log, webhook, webhook_delivery, artifact).

For production, use a managed SurrealDB instance or a dedicated server:

# Example: remote SurrealDB
SURREAL_ENDPOINT=https://db.example.com
SURREAL_NS=production
SURREAL_DB=chorus
SURREAL_USER=chorus_admin
SURREAL_PASS=secure_password_here

Production Checklist

Before deploying to production:

  • Change default SurrealDB credentials (SURREAL_USER, SURREAL_PASS)
  • Set up TLS/HTTPS termination (reverse proxy with nginx or Caddy)
  • Configure rate limiting appropriate for your load
  • Set up the bootstrap YAML with your initial identities and roles
  • Configure an embedding provider if using semantic memory search
  • Set MEMORY_GC_INTERVAL_MINUTES based on your memory retention needs
  • Set up monitoring for the /health endpoint
  • Back up SurrealDB data regularly
  • Configure S3 storage if using artifact sharing (S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY)

Running Without Docker

If you prefer to run Chorus directly:

# Install dependencies
bun install

# Start the server
bun run start

# Or for development with hot reload
bun run dev

Requires Bun runtime and a running SurrealDB instance.


Production Hardening

TLS Termination

Chorus does not handle TLS directly. Use a reverse proxy (nginx, Caddy, or a cloud load balancer) for HTTPS:

server {
    listen 443 ssl;
    server_name chorus.example.com;

    ssl_certificate /etc/ssl/chorus.crt;
    ssl_certificate_key /etc/ssl/chorus.key;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
    }
}

Rate Limit Tuning

The default rate limit is 100 requests per window. Adjust with RATE_LIMIT_DEFAULT for your load profile. Individual API keys can override this with a per-key rate_limit field.

SurrealDB Auth

Change default credentials immediately. For production, use a dedicated SurrealDB user with minimal permissions:

SURREAL_USER=chorus_app
SURREAL_PASS=$(openssl rand -hex 32)

Network Isolation

Run SurrealDB on an internal network not accessible from the public internet. Only the Chorus server should have database access.


Backup Strategy

SurrealDB Data

# Export full database
surreal export --conn http://localhost:8000 \
  --ns chorus --db protocol \
  --user root --pass root \
  backup.surql

Memory Export

Use the admin API for memory-specific backups:

curl -X POST http://localhost:3000/memory/admin/export \
  -H "Authorization: Bearer YOUR_ADMIN_KEY"

Poll the returned job ID for completion, then retrieve the JSONL download.

Configuration Backup

Back up your bootstrap YAML file and environment variables. The bootstrap YAML is the canonical source for initial identities, roles, rings, and invites.


Monitoring

Health Endpoint

The /health endpoint returns {"status": "healthy"} and is suitable for load balancer health checks. No authentication required.

Admin Health Metrics

GET /admin/health-metrics provides operational metrics (admin key required):

MetricWhat to Watch
db_latency_msAlert if > 100ms (indicates database performance issues)
dead_letter_countAlert if increasing (signals failing delivery)
embedding_queue_depthAlert if growing (embedding provider may be down)
uptime_secondsTrack for unexpected restarts
delivery_statsMonitor pending vs delivered ratio

Scaling

Stateless Server Design

The Chorus server is stateless -- all state lives in SurrealDB. You can run multiple Chorus instances behind a load balancer for horizontal scaling:

Load Balancer (HTTPS)
    |-- Chorus Instance 1 --\
    |-- Chorus Instance 2 ---|-- SurrealDB (shared state)
    |-- Chorus Instance 3 --/

Considerations

  • SurrealDB is the single shared state store. Scale it according to your workload.
  • Embedding queue runs per-instance. Each instance processes its own embedding backlog.
  • In-memory job stores (re-embed, import/export) are per-instance and not shared. Route long-running admin operations to the same instance.
  • Rate limiting is per-instance in the default configuration.

On this page