mirror of
https://github.com/multica-ai/multica.git
synced 2026-08-03 11:10:23 +02:00
Chat auto-titling and chat follow-up suggestions are gated on the server-side LLM layer, which reads MULTICA_LLM_API_KEY / MULTICA_LLM_BASE_URL through os.Getenv. The self-host compose file enumerates backend environment explicitly and has no env_file, and those three vars were not in the list — so setting them in .env did nothing, the container never saw them, and the layer was off on every compose deployment regardless of configuration. .env.example documents them, which made it look configurable. That was survivable while quick actions were generated by the daemon's own provider pass, which needed no server key. MUL-5573 moved generation server- side and removed the daemon path, so on those deployments the feature stopped appearing entirely rather than degrading. Adds the passthrough, and one startup line reporting whether the layer is enabled. Every consumer degrades silently by design, so without that line an unset key is indistinguishable from a broken feature — which is exactly how this surfaced. Helm already supports it through the operator-managed Secret; values.yaml now says so instead of leaving it undocumented. Co-authored-by: multica-agent <github@multica.ai>
170 lines
8.2 KiB
YAML
170 lines
8.2 KiB
YAML
# Self-hosting Docker Compose — starts PostgreSQL, backend, and frontend.
|
|
#
|
|
# Services bind to 127.0.0.1 only. For cross-machine or public access, front
|
|
# them with a reverse proxy (Caddy / nginx / Cloudflare Tunnel) that terminates
|
|
# TLS and forwards to 127.0.0.1:8080 (backend) and 127.0.0.1:3000 (frontend).
|
|
# Do NOT change these bindings to 0.0.0.0 — Docker bypasses host firewalls
|
|
# (UFW/iptables) by default, so the raw ports would be exposed to the internet
|
|
# with the default JWT_SECRET and Postgres credentials. See:
|
|
# apps/docs/content/docs/self-host-quickstart.mdx
|
|
#
|
|
# Usage:
|
|
# cp .env.example .env
|
|
# # Edit .env — change JWT_SECRET at minimum
|
|
# docker compose -f docker-compose.selfhost.yml up -d
|
|
#
|
|
# Frontend: http://localhost:${FRONTEND_PORT:-3000}
|
|
# Backend: http://localhost:${BACKEND_PORT:-${API_PORT:-${SERVER_PORT:-${PORT:-8080}}}}
|
|
#
|
|
# The published values above are HOST ports; the containers always listen on
|
|
# 8080 / 3000 internally, so changing them never needs a rebuild. PORT is the
|
|
# variable to edit; BACKEND_PORT, API_PORT and SERVER_PORT are optional aliases
|
|
# that override it in that order. Keep this alias order identical to Makefile
|
|
# and scripts/local-env.sh. The web dev fallback intentionally omits PORT
|
|
# because Next uses that variable for its own frontend listener.
|
|
#
|
|
# Note that *which source* wins differs per entry point — Compose lets the
|
|
# calling environment outrank this file, while make lets the included env file
|
|
# outrank the environment. Nothing re-derives the published port from the inputs
|
|
# any more: `make selfhost` (via scripts/selfhost-wait.sh) and both installers
|
|
# read it back with `docker compose port`, so the health check and the printed
|
|
# URL always match what was actually published.
|
|
|
|
name: multica
|
|
|
|
services:
|
|
postgres:
|
|
image: pgvector/pgvector:pg17
|
|
environment:
|
|
POSTGRES_DB: ${POSTGRES_DB:-multica}
|
|
POSTGRES_USER: ${POSTGRES_USER:-multica}
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-multica}
|
|
volumes:
|
|
- pgdata:/var/lib/postgresql/data
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test:
|
|
[
|
|
"CMD-SHELL",
|
|
"pg_isready -U ${POSTGRES_USER:-multica} -d ${POSTGRES_DB:-multica}",
|
|
]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
backend:
|
|
image: ${MULTICA_BACKEND_IMAGE:-ghcr.io/multica-ai/multica-backend}:${MULTICA_IMAGE_TAG:-latest}
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
ports:
|
|
- "127.0.0.1:${BACKEND_PORT:-${API_PORT:-${SERVER_PORT:-${PORT:-8080}}}}:8080"
|
|
volumes:
|
|
- backend_uploads:/app/data/uploads
|
|
environment:
|
|
DATABASE_URL: postgres://${POSTGRES_USER:-multica}:${POSTGRES_PASSWORD:-multica}@postgres:5432/${POSTGRES_DB:-multica}?sslmode=disable
|
|
PORT: "8080"
|
|
METRICS_ADDR: ${METRICS_ADDR:-}
|
|
JWT_SECRET: ${JWT_SECRET:-change-me-in-production}
|
|
FRONTEND_ORIGIN: ${FRONTEND_ORIGIN:-http://localhost:3000}
|
|
CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:-}
|
|
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_TLS: ${SMTP_TLS:-}
|
|
SMTP_TLS_INSECURE: ${SMTP_TLS_INSECURE:-false}
|
|
SMTP_EHLO_NAME: ${SMTP_EHLO_NAME:-}
|
|
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}
|
|
GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}
|
|
GOOGLE_REDIRECT_URI: ${GOOGLE_REDIRECT_URI:-http://localhost:3000/auth/callback}
|
|
S3_BUCKET: ${S3_BUCKET:-}
|
|
S3_REGION: ${S3_REGION:-us-west-2}
|
|
AWS_ENDPOINT_URL: ${AWS_ENDPOINT_URL:-}
|
|
S3_USE_PATH_STYLE: ${S3_USE_PATH_STYLE:-}
|
|
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-}
|
|
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-}
|
|
ATTACHMENT_DOWNLOAD_MODE: ${ATTACHMENT_DOWNLOAD_MODE:-auto}
|
|
ATTACHMENT_DOWNLOAD_URL_TTL: ${ATTACHMENT_DOWNLOAD_URL_TTL:-30m}
|
|
CLOUDFRONT_DOMAIN: ${CLOUDFRONT_DOMAIN:-}
|
|
CLOUDFRONT_KEY_PAIR_ID: ${CLOUDFRONT_KEY_PAIR_ID:-}
|
|
CLOUDFRONT_PRIVATE_KEY: ${CLOUDFRONT_PRIVATE_KEY:-}
|
|
COOKIE_DOMAIN: ${COOKIE_DOMAIN:-}
|
|
APP_ENV: ${APP_ENV:-production}
|
|
MULTICA_DEV_VERIFICATION_CODE: ${MULTICA_DEV_VERIFICATION_CODE:-}
|
|
MULTICA_APP_URL: ${MULTICA_APP_URL:-http://localhost:3000}
|
|
MULTICA_SHUTDOWN_HOLD_DURATION: ${MULTICA_SHUTDOWN_HOLD_DURATION:-}
|
|
ALLOW_SIGNUP: ${ALLOW_SIGNUP:-true}
|
|
ALLOWED_EMAILS: ${ALLOWED_EMAILS:-}
|
|
ALLOWED_EMAIL_DOMAINS: ${ALLOWED_EMAIL_DOMAINS:-}
|
|
DISABLE_WORKSPACE_CREATION: ${DISABLE_WORKSPACE_CREATION:-}
|
|
GITHUB_APP_SLUG: ${GITHUB_APP_SLUG:-}
|
|
GITHUB_WEBHOOK_SECRET: ${GITHUB_WEBHOOK_SECRET:-}
|
|
# Server-internal LLM layer (MUL-4238). Backs chat auto-titling and chat
|
|
# follow-up suggestions. Setting either the key or the base URL enables
|
|
# it; leaving both empty disables those features silently. Without these
|
|
# three lines the vars in .env never reach the container, so the features
|
|
# cannot be turned on at all no matter what the operator configures.
|
|
MULTICA_LLM_API_KEY: ${MULTICA_LLM_API_KEY:-}
|
|
MULTICA_LLM_BASE_URL: ${MULTICA_LLM_BASE_URL:-}
|
|
MULTICA_LLM_DEFAULT_MODEL: ${MULTICA_LLM_DEFAULT_MODEL:-}
|
|
# Public URL the API is reachable at from the open internet, no
|
|
# trailing slash. Used to mint absolute webhook URLs for autopilot
|
|
# webhook triggers. Leave unset behind a same-origin reverse proxy
|
|
# (e.g. plain localhost dev); the frontend will compose the URL
|
|
# from window.origin + webhook_path in that case. Headers are
|
|
# intentionally NOT used to derive this value, to avoid Host /
|
|
# X-Forwarded-Host spoofing on misconfigured proxies.
|
|
MULTICA_PUBLIC_URL: ${MULTICA_PUBLIC_URL:-}
|
|
# Comma-separated CIDRs whose source IP is allowed to set
|
|
# X-Forwarded-For / X-Real-IP for the webhook per-IP rate limiter.
|
|
# Empty default = headers ignored, RemoteAddr used. Set e.g.
|
|
# "127.0.0.1/32" when running behind a same-host reverse proxy.
|
|
MULTICA_TRUSTED_PROXIES: ${MULTICA_TRUSTED_PROXIES:-}
|
|
# Lark / Feishu bot integration. MULTICA_LARK_SECRET_KEY is the
|
|
# opt-in: unset = integration disabled. Mainland 飞书 and international
|
|
# Lark are auto-detected per installation and served side by side, so
|
|
# the two base-URL knobs should normally stay EMPTY. They are optional
|
|
# deployment-wide overrides that force every installation onto one host
|
|
# (proxy / mock / single-cloud staging). Upgrading from a setup that
|
|
# used https://open.larksuite.com here? The server relabels existing
|
|
# installs to region=lark on first boot, then you can clear them.
|
|
# See docs/lark-bot-integration.
|
|
MULTICA_LARK_SECRET_KEY: ${MULTICA_LARK_SECRET_KEY:-}
|
|
MULTICA_LARK_HTTP_BASE_URL: ${MULTICA_LARK_HTTP_BASE_URL:-}
|
|
MULTICA_LARK_CALLBACK_BASE_URL: ${MULTICA_LARK_CALLBACK_BASE_URL:-}
|
|
# Slack bot integration. MULTICA_SLACK_SECRET_KEY is the opt-in: unset =
|
|
# integration disabled. It decrypts the per-installation bot/app tokens,
|
|
# which are brought by each workspace via OAuth/BYO and stored encrypted
|
|
# in the database, so this single deployment-wide key is all the operator
|
|
# needs to set here.
|
|
MULTICA_SLACK_SECRET_KEY: ${MULTICA_SLACK_SECRET_KEY:-}
|
|
# Self-hosted Git provider integration (Forgejo / Gitea / GitLab). This
|
|
# is a self-host-only feature, so the compose file turns it on by default;
|
|
# the managed cloud leaves it unset (off). It still needs a valid
|
|
# MULTICA_VCS_SECRET_KEY below to actually work.
|
|
MULTICA_VCS_INTEGRATION_ENABLED: ${MULTICA_VCS_INTEGRATION_ENABLED:-true}
|
|
# VCS integration at-rest encryption key for token-based providers
|
|
MULTICA_VCS_SECRET_KEY: ${MULTICA_VCS_SECRET_KEY:-}
|
|
restart: unless-stopped
|
|
|
|
frontend:
|
|
image: ${MULTICA_WEB_IMAGE:-ghcr.io/multica-ai/multica-web}:${MULTICA_IMAGE_TAG:-latest}
|
|
depends_on:
|
|
- backend
|
|
ports:
|
|
- "127.0.0.1:${FRONTEND_PORT:-3000}:3000"
|
|
environment:
|
|
HOSTNAME: "0.0.0.0"
|
|
REMOTE_API_URL: ${REMOTE_API_URL:-http://backend:8080}
|
|
DOCS_URL: ${DOCS_URL:-}
|
|
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-}
|
|
NEXT_PUBLIC_WS_URL: ${NEXT_PUBLIC_WS_URL:-}
|
|
restart: unless-stopped
|
|
|
|
volumes:
|
|
pgdata:
|
|
backend_uploads:
|