docker-compose.selfhost.yml
Rama main · réplica de lectura del repositorio original.
# Self-host Sotto from pre-built public images (no source, no build).
# The curl|bash installer (scripts/install.sh) writes .env and runs this.
#
# docker compose -f docker-compose.selfhost.yml up -d
#
# Images are published by .github/workflows/oss-image.yml. Postgres and Redis
# are pulled from public registries.
name: sotto
services:
postgres:
image: pgvector/pgvector:pg17
environment:
POSTGRES_USER: sotto
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}
POSTGRES_DB: sotto
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -h 127.0.0.1 -U sotto -d sotto']
interval: 5s
timeout: 5s
retries: 12
networks: [sotto-network]
restart: unless-stopped
redis:
image: redis:7-alpine
command: ['redis-server', '--appendonly', 'yes']
volumes:
- redisdata:/data
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
interval: 5s
timeout: 5s
retries: 12
networks: [sotto-network]
restart: unless-stopped
web:
image: ghcr.io/affromero/sotto-web:${SOTTO_IMAGE_TAG:-latest}
env_file: [.env]
environment:
NODE_ENV: production
HOSTNAME: '0.0.0.0'
BYOK_ENCRYPTION_KEY: ${BYOK_ENCRYPTION_KEY:?Set BYOK_ENCRYPTION_KEY in .env}
SOTTO_CREDENTIAL_SYNC_DIR: /run/cli-credentials
CLAUDE_HOME: /home/sotto/.claude
CODEX_HOME: /home/sotto/.codex
SIDEDOOR_EXECUTION_DIR: /app/apps/web/.sotto/runtime/executions
ports:
- '127.0.0.1:${WEB_PORT:-3000}:3000'
volumes:
- storage:/app/apps/web/.sotto/storage
- executions:/app/apps/web/.sotto/runtime
- cli-credentials:/run/cli-credentials
- agent-home:/home/sotto/.claude
- agent-codex-home:/home/sotto/.codex
depends_on:
postgres: { condition: service_healthy }
redis: { condition: service_healthy }
credential-sync: { condition: service_healthy }
healthcheck:
test:
[
'CMD',
'wget',
'--no-verbose',
'--tries=1',
'--spider',
'http://127.0.0.1:3000/api/v1/health',
]
interval: 30s
timeout: 10s
retries: 5
start_period: 40s
networks: [sotto-network]
restart: unless-stopped
workers:
image: ghcr.io/affromero/sotto-workers:${SOTTO_IMAGE_TAG:-latest}
env_file: [.env]
environment:
NODE_ENV: production
SOTTO_CREDENTIAL_SYNC_DIR: /run/cli-credentials
CLAUDE_HOME: /home/sotto/.claude
CODEX_HOME: /home/sotto/.codex
SIDEDOOR_EXECUTION_DIR: /app/apps/web/.sotto/runtime/executions
volumes:
- storage:/app/apps/web/.sotto/storage
- executions:/app/apps/web/.sotto/runtime
- cli-credentials:/run/cli-credentials
- agent-home:/home/sotto/.claude
- agent-codex-home:/home/sotto/.codex
depends_on:
postgres: { condition: service_healthy }
redis: { condition: service_healthy }
credential-sync: { condition: service_healthy }
networks: [sotto-network]
restart: unless-stopped
credential-sync:
image: alpine:3.22
network_mode: none
read_only: true
tmpfs: [/tmp]
volumes:
- cli-credentials:/credential-sync
- ${HOME}/.claude:/host-claude:ro
- ${HOME}/.codex:/host-codex:ro
- ./sync-cli-credentials.sh:/usr/local/bin/sync-cli-credentials:ro
command: ['/bin/sh', '/usr/local/bin/sync-cli-credentials']
healthcheck:
test: ['CMD', 'test', '-f', '/credential-sync/ready']
interval: 2s
timeout: 1s
retries: 15
restart: unless-stopped
volumes:
# The agent CLI rotates its OAuth refresh token in place and retires the old
# one, so its credentials file has to outlive the container.
agent-home:
agent-codex-home:
pgdata:
redisdata:
storage:
executions:
cli-credentials:
networks:
sotto-network: