2026-10-23 12:09:07 -07:00

102 lines
4.0 KiB
YAML

networks:
# Service-to-service traffic (postgres <-> backend <-> frontend) and outbound egress.
internal:
driver: bridge
traefik:
external: true
name: ${TRAEFIK_NETWORK:-traefik}
services:
postgres:
image: pgvector/pgvector:pg17
restart: unless-stopped
environment:
POSTGRES_DB: multica
POSTGRES_USER: ${POSTGRES_USER:-multica}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set}
networks:
- internal
volumes:
- ${POSTGRES_DATA_DIR:-./data/postgres}:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-multica} -d multica"]
interval: 5s
timeout: 5s
retries: 5
# Official image. Its entrypoint runs `migrate up` before starting the server.
# Version is pinned to match the multica CLI on the host; see README "Versioning".
backend:
image: ghcr.io/multica-ai/multica-backend:v0.6.5
restart: unless-stopped
environment:
APP_ENV: production
PORT: "8080"
DATABASE_URL: postgres://${POSTGRES_USER:-multica}:${POSTGRES_PASSWORD}@postgres:5432/multica?sslmode=disable
JWT_SECRET: ${JWT_SECRET:?JWT_SECRET must be set - openssl rand -hex 32}
FRONTEND_ORIGIN: ${FRONTEND_ORIGIN:?FRONTEND_ORIGIN must be set}
CORS_ALLOWED_ORIGINS: ${FRONTEND_ORIGIN}
MULTICA_APP_URL: ${FRONTEND_ORIGIN}
MULTICA_PUBLIC_URL: ${MULTICA_PUBLIC_URL:-}
GOOGLE_REDIRECT_URI: ${FRONTEND_ORIGIN}/auth/callback
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}
GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}
RESEND_API_KEY: ${RESEND_API_KEY:-}
RESEND_FROM_EMAIL: ${RESEND_FROM_EMAIL:-noreply@multica.ai}
SMTP_HOST: ${SMTP_HOST:-}
SMTP_PORT: ${SMTP_PORT:-25}
SMTP_USERNAME: ${SMTP_USERNAME:-}
SMTP_PASSWORD: ${SMTP_PASSWORD:-}
SMTP_FROM_EMAIL: ${SMTP_FROM_EMAIL:-}
SMTP_TLS: ${SMTP_TLS:-}
ALLOW_SIGNUP: ${ALLOW_SIGNUP:-true}
ALLOWED_EMAILS: ${ALLOWED_EMAILS:-}
ALLOWED_EMAIL_DOMAINS: ${ALLOWED_EMAIL_DOMAINS:-}
DISABLE_WORKSPACE_CREATION: ${DISABLE_WORKSPACE_CREATION:-false}
MULTICA_VCS_INTEGRATION_ENABLED: "true"
MULTICA_VCS_SECRET_KEY: ${MULTICA_VCS_SECRET_KEY:-}
DO_NOT_TRACK: ${DO_NOT_TRACK:-}
networks:
- internal
- traefik
volumes:
- ${UPLOADS_DATA_DIR:-./data/uploads}:/app/data/uploads
# Loopback only, for the multica agent daemon on this host.
ports:
- "127.0.0.1:${BACKEND_HOST_PORT:-8080}:8080"
depends_on:
postgres:
condition: service_healthy
labels:
- "traefik.enable=true"
- "traefik.docker.network=${TRAEFIK_NETWORK:-traefik}"
- "traefik.http.services.multica-backend.loadbalancer.server.port=8080"
# On the traefik network only so traefik can reach /ws; everything else
# goes through the frontend.
# Next.js rewrites proxy /api, /auth, /uploads to the backend, but not
# websockets, so /ws on the main host must go straight to the backend.
- "traefik.http.routers.multica-ws.rule=Host(`${FRONTEND_HOST}`) && (Path(`/ws`) || PathPrefix(`/ws/`))"
- "traefik.http.routers.multica-ws.entrypoints=websecure"
- "traefik.http.routers.multica-ws.tls.certresolver=let-sencrypt"
- "traefik.http.routers.multica-ws.service=multica-backend"
# Official image. Proxies API calls to REMOTE_API_URL at runtime.
frontend:
image: ghcr.io/multica-ai/multica-web:v0.6.5
restart: unless-stopped
environment:
HOSTNAME: "0.0.0.0"
REMOTE_API_URL: http://backend:8080
networks:
- internal
- traefik
depends_on:
- backend
labels:
- "traefik.enable=true"
- "traefik.docker.network=${TRAEFIK_NETWORK:-traefik}"
- "traefik.http.routers.multica-web.rule=Host(`${FRONTEND_HOST}`)"
- "traefik.http.routers.multica-web.entrypoints=websecure"
- "traefik.http.routers.multica-web.tls.certresolver=lets-encrypt"
- "traefik.http.services.multica-web.loadbalancer.server.port=3000"