mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-17 03:38:32 +02:00
* fix(storage): build region-qualified S3 public URLs (#2051) The uploadedURL fallback (no CloudFront, no custom endpoint) wrote "https://<bucket>/<key>" — missing the ".s3.<region>.amazonaws.com" suffix — so any deployment that pointed S3_BUCKET at a real AWS bucket without a CDN got broken image URLs back to the client. Avatar URLs were persisted in this broken form on the user/agent rows, so profile pictures uploaded via the SDK never rendered. - Track S3_REGION on S3Storage and emit https://<bucket>.s3.<region>.amazonaws.com/<key> by default; fall back to path-style https://s3.<region>.amazonaws.com/<bucket>/<key> when the bucket name contains dots, since the AWS wildcard cert can't validate dotted virtual-hosted hosts. - Teach KeyFromURL to recognise the new region-qualified hosts (both styles) and keep recognising the legacy bucket-only host so historical records can still be deleted/migrated. - Document that S3_BUCKET is the bucket name only, not a hostname, in env-vars docs (en+zh), self-hosting guides, and .env.example. Co-authored-by: multica-agent <github@multica.ai> * feat(storage): warn at startup when S3_BUCKET looks like a hostname Catches the most common misconfiguration shape (S3_BUCKET set to "<bucket>.s3.<region>.amazonaws.com") with a startup log line so operators don't silently end up with a config that signs uploads against an invalid bucket name. A real bucket name can never legitimately contain "amazonaws.com", so the check is a single substring match — no false positives worth carving out. Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: multica-agent <github@multica.ai>
137 lines
5.8 KiB
Plaintext
137 lines
5.8 KiB
Plaintext
# Database
|
|
POSTGRES_DB=multica
|
|
POSTGRES_USER=multica
|
|
POSTGRES_PASSWORD=multica
|
|
POSTGRES_PORT=5432
|
|
DATABASE_URL=postgres://multica:multica@localhost:5432/multica?sslmode=disable
|
|
# Optional pgxpool tuning. Defaults are 25 / 5 per pod and are usually fine.
|
|
# You can also set pool_max_conns / pool_min_conns as query params on
|
|
# DATABASE_URL; env vars below take precedence over URL params.
|
|
# DATABASE_MAX_CONNS=25
|
|
# DATABASE_MIN_CONNS=5
|
|
|
|
# Server
|
|
# APP_ENV gates production safety checks. Docker self-host pins APP_ENV to
|
|
# "production" by default. Local dev can leave it unset.
|
|
# See SELF_HOSTING.md for the full login setup.
|
|
APP_ENV=
|
|
# Optional local/testing shortcut. Empty by default, so there is no fixed
|
|
# verification code. Without RESEND_API_KEY, generated codes print to stdout.
|
|
# If you need deterministic local automation, set a 6-digit value such as
|
|
# 888888 and keep APP_ENV non-production. This is ignored when APP_ENV=production.
|
|
MULTICA_DEV_VERIFICATION_CODE=
|
|
PORT=8080
|
|
# Prometheus metrics are disabled by default. When enabled, bind to loopback
|
|
# unless you protect the listener with private networking, allowlists, or
|
|
# proxy auth. Do not expose this endpoint through the public app/API ingress.
|
|
# HTTP request metrics start accumulating only when this listener is enabled.
|
|
# METRICS_ADDR=127.0.0.1:9090
|
|
JWT_SECRET=change-me-in-production
|
|
MULTICA_SERVER_URL=ws://localhost:8080/ws
|
|
MULTICA_APP_URL=http://localhost:3000
|
|
MULTICA_DAEMON_CONFIG=
|
|
MULTICA_WORKSPACE_ID=
|
|
MULTICA_DAEMON_ID=
|
|
MULTICA_DAEMON_DEVICE_NAME=
|
|
MULTICA_DAEMON_POLL_INTERVAL=3s
|
|
MULTICA_DAEMON_HEARTBEAT_INTERVAL=15s
|
|
MULTICA_CODEX_PATH=codex
|
|
MULTICA_CODEX_MODEL=
|
|
MULTICA_CODEX_WORKDIR=
|
|
MULTICA_CODEX_TIMEOUT=20m
|
|
|
|
# Self-host image channel
|
|
# Default stable release channel. Pin to an exact release like v0.2.4 if you
|
|
# want to stay on a specific version. If the selected tag has not been
|
|
# published to GHCR yet, use make selfhost-build / the build override instead.
|
|
MULTICA_IMAGE_TAG=latest
|
|
MULTICA_BACKEND_IMAGE=ghcr.io/multica-ai/multica-backend
|
|
MULTICA_WEB_IMAGE=ghcr.io/multica-ai/multica-web
|
|
|
|
# Email (Resend)
|
|
# For local/dev use, leave RESEND_API_KEY empty — generated codes print to stdout.
|
|
# For production, set your Resend API key and change RESEND_FROM_EMAIL to a domain verified in your Resend account.
|
|
RESEND_API_KEY=
|
|
RESEND_FROM_EMAIL=noreply@multica.ai
|
|
|
|
# Google OAuth
|
|
# The web login page reads GOOGLE_CLIENT_ID from /api/config at runtime, so
|
|
# changing it only requires restarting the backend / compose stack. No web
|
|
# rebuild is needed.
|
|
GOOGLE_CLIENT_ID=
|
|
GOOGLE_CLIENT_SECRET=
|
|
GOOGLE_REDIRECT_URI=http://localhost:3000/auth/callback
|
|
|
|
# S3 / CloudFront
|
|
# S3_BUCKET — bucket NAME only (e.g. "my-bucket"). Do NOT include the
|
|
# ".s3.<region>.amazonaws.com" suffix; the server builds the public URL
|
|
# from S3_BUCKET + S3_REGION. S3_REGION must match the bucket's real region.
|
|
S3_BUCKET=
|
|
S3_REGION=us-west-2
|
|
CLOUDFRONT_KEY_PAIR_ID=
|
|
CLOUDFRONT_PRIVATE_KEY_SECRET=multica/cloudfront-signing-key
|
|
CLOUDFRONT_PRIVATE_KEY=
|
|
CLOUDFRONT_DOMAIN=
|
|
# COOKIE_DOMAIN — optional Domain attribute on session + CloudFront cookies.
|
|
# Leave empty for single-host deployments (localhost, LAN IP, or a single
|
|
# hostname) — session cookies become host-only, which is what the browser
|
|
# wants. Only set it when the frontend and backend sit on different
|
|
# subdomains of one registered domain (e.g. ".example.com"). Do NOT set it
|
|
# to an IP address: RFC 6265 forbids IP literals in the cookie Domain
|
|
# attribute and browsers silently drop such cookies.
|
|
COOKIE_DOMAIN=
|
|
|
|
# Local file storage (fallback when S3_BUCKET is not set)
|
|
LOCAL_UPLOAD_DIR=./data/uploads
|
|
LOCAL_UPLOAD_BASE_URL=http://localhost:8080
|
|
|
|
# Security
|
|
# Comma-separated list of allowed origins for CORS and WebSocket connections.
|
|
# Defaults to localhost dev origins when unset.
|
|
# Example: ALLOWED_ORIGINS=https://app.multica.ai,https://staging.multica.ai
|
|
ALLOWED_ORIGINS=
|
|
|
|
# Realtime metrics endpoint (/health/realtime) access control. See MUL-1342.
|
|
# When unset, the endpoint only serves direct loopback (127.0.0.1 / ::1)
|
|
# callers with no forwarding headers and returns 404 to everything else —
|
|
# safe for local dev. Any deployment behind a reverse proxy (Caddy / Nginx
|
|
# terminating TLS in front of localhost:8080) MUST set this token, since
|
|
# proxied requests look like loopback at the Go layer; with no token, those
|
|
# requests are refused with 404. Pass the token as
|
|
# `Authorization: Bearer <token>`.
|
|
# REALTIME_METRICS_TOKEN=
|
|
|
|
# Frontend
|
|
FRONTEND_PORT=3000
|
|
FRONTEND_ORIGIN=http://localhost:3000
|
|
# Leave empty — auto-derived from page origin in browser, set by Makefile for local dev.
|
|
# Only set explicitly if frontend and backend are on different domains.
|
|
NEXT_PUBLIC_API_URL=
|
|
NEXT_PUBLIC_WS_URL=
|
|
|
|
# Remote API (optional) — set to proxy local frontend to a remote backend
|
|
# Leave empty to use local backend (localhost:8080)
|
|
# REMOTE_API_URL=https://multica-api.copilothub.ai
|
|
|
|
# ==================== Self-hosting: Control Signups (fixes #930) ====================
|
|
# Set to "false" to completely disable new user signups (recommended for private instances)
|
|
ALLOW_SIGNUP=true
|
|
# The web UI reads ALLOW_SIGNUP from /api/config at runtime, so toggling this
|
|
# only requires restarting the backend / compose stack — not rebuilding web.
|
|
# It is not hot-reloaded.
|
|
|
|
# Optional: Only allow emails from these domains (comma-separated)
|
|
ALLOWED_EMAIL_DOMAINS=
|
|
|
|
# Optional: Only allow these exact email addresses (comma-separated)
|
|
ALLOWED_EMAILS=
|
|
|
|
# ==================== Analytics (PostHog) ====================
|
|
# Product analytics events feed the acquisition → activation → expansion funnel.
|
|
# Leave POSTHOG_API_KEY empty for local dev / self-hosted instances; the server
|
|
# will run a no-op analytics client and ship nothing. See docs/analytics.md.
|
|
POSTHOG_API_KEY=
|
|
POSTHOG_HOST=https://us.i.posthog.com
|
|
# Force the no-op client even when POSTHOG_API_KEY is set (CI / opt-out).
|
|
ANALYTICS_DISABLED=
|