Skip to main content
Control Plane Server is a self-hosted service. This page covers production deployment options, configuration, and scaling. The quickstart Docker Compose file is suitable for teams up to ~20 active users. For production use, add persistent volumes and point to an external Postgres database.

Production compose file

# docker-compose.prod.yml
version: "3.9"

services:
  langship:
    image: lyzrcore/langship:latest
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgresql://user:pass@postgres:5432/langship
      REDIS_URL: redis://redis:6379
      SECRET_KEY: ${SECRET_KEY}         # generate with: openssl rand -hex 32
      LANGSHIP_BASE_URL: https://langship.yourcompany.com
    depends_on:
      - postgres
      - redis
    volumes:
      - langship-data:/app/data
    restart: always

  collector:
    image: lyzrcore/langship-collector:latest
    ports:
      - "4317:4317"    # OTLP gRPC
      - "4318:4318"    # OTLP HTTP
    environment:
      LANGSHIP_SERVER_URL: http://langship:3000
    restart: always

  postgres:
    image: postgres:15
    environment:
      POSTGRES_DB: langship
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres-data:/var/lib/postgresql/data
    restart: always

  redis:
    image: redis:7-alpine
    volumes:
      - redis-data:/data
    restart: always

volumes:
  langship-data:
  postgres-data:
  redis-data:
Start:
SECRET_KEY=$(openssl rand -hex 32) \
POSTGRES_USER=langship \
POSTGRES_PASSWORD=$(openssl rand -hex 16) \
docker compose -f docker-compose.prod.yml up -d

Running database migrations

After first start or on upgrade:
docker compose exec langship langship-server migrate

Kubernetes

For larger deployments or teams that already run Kubernetes, use the Helm chart:
helm repo add langship https://lyzrcore.github.io/langship-helm
helm repo update

helm install langship langship/langship \
  --namespace langship \
  --create-namespace \
  --set config.secretKey="$(openssl rand -hex 32)" \
  --set postgresql.enabled=true \
  --set redis.enabled=true

Custom values

Create values.yaml:
replicaCount: 2

config:
  baseUrl: "https://langship.yourcompany.com"
  secretKey: "your-secret-key"

postgresql:
  enabled: false               # use external Postgres
  external:
    host: "your-postgres-host"
    database: "langship"
    username: "langship"
    password: "your-password"

redis:
  enabled: true

ingress:
  enabled: true
  className: nginx
  hosts:
    - host: langship.yourcompany.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: langship-tls
      hosts:
        - langship.yourcompany.com

collector:
  enabled: true
  replicaCount: 2
Apply:
helm upgrade --install langship langship/langship \
  --namespace langship \
  -f values.yaml

Environment variables

VariableRequiredDescription
DATABASE_URLYesPostgreSQL connection string
REDIS_URLYesRedis connection string
SECRET_KEYYes32-byte hex secret for session signing
LANGSHIP_BASE_URLYesPublic URL of the server (used in webhook callbacks)
SMTP_HOSTNoSMTP server for email notifications
SMTP_PORTNoSMTP port (default 587)
SMTP_USERNoSMTP username
SMTP_PASSWORDNoSMTP password
OTEL_FORWARD_URLNoForward traces to an additional OTLP endpoint
MAX_TRACE_RETENTION_DAYSNoAuto-delete traces older than N days (default: 90)

Upgrading

# Docker Compose
docker compose pull
docker compose up -d
docker compose exec langship langship-server migrate

# Kubernetes
helm repo update
helm upgrade langship langship/langship --namespace langship -f values.yaml
Always run migrations after upgrading. Migrations are backward-compatible; the server handles rolling upgrades without downtime.

Backups

Back up the Postgres database on a regular schedule:
pg_dump -h localhost -U langship langship | gzip > langship-backup-$(date +%Y%m%d).sql.gz
Control Plane does not store credentials, API keys, or OAuth tokens; it stores only traces, datasets, and eval results.

Connecting your SDK to a self-hosted server

Point the SDK at your server URL:
langship.init(
    endpoint="https://langship.yourcompany.com",
    api_key="your-api-key",    # generated in the Control Plane dashboard
    project="my-agent"
)
Or via environment variables:
export LANGSHIP_ENDPOINT=https://langship.yourcompany.com
export LANGSHIP_API_KEY=your-api-key
export LANGSHIP_PROJECT=my-agent
When environment variables are set, langship.init() with no arguments picks them up automatically.