mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-17 11:48:42 +02:00
* Restrict /health/realtime metrics exposure (MUL-1342) The realtime metrics endpoint was registered on the public router with no authentication, exposing per-event/per-scope counters, redis.last_error, and redis.node_id to anonymous callers. This enables information disclosure and traffic profiling. Move the handler behind a token + loopback policy: - If REALTIME_METRICS_TOKEN is set, require Authorization: Bearer <token> using a constant-time compare. Reject other callers with 401 plus a WWW-Authenticate hint. - If the env var is unset, only serve loopback callers and return 404 to remote clients so the endpoint is not enumerable. This keeps local dev workflows working without configuration. The handler is extracted into health_realtime.go with focused unit tests covering the token, loopback, and rejection paths. .env.example documents the new variable. Refs: https://github.com/multica-ai/multica/issues/1606 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fail closed for proxied /health/realtime requests (MUL-1342) Addresses review on PR #1608: when the server runs behind a reverse proxy (Caddy / Nginx -> localhost:8080), public callers reach the Go handler with RemoteAddr=127.0.0.1, so the previous loopback shortcut exposed the metrics surface in self-hosted deployments. The no-token path now treats any forwarding header (X-Forwarded-For / -Host / -Proto, X-Real-Ip, Forwarded) as a 'this request was proxied, can't attribute, fail closed' signal and returns 404. Direct loopback callers without those headers still work for local dev. Token-gated path is unchanged. Tests cover all listed proxy headers (incl. multi-hop XFF chain and RFC 7239 Forwarded) over both 127.0.0.1 and ::1, plus a regression case ensuring an empty/whitespace forwarding header does not break direct loopback access. .env.example updated to call out that proxied deployments must configure REALTIME_METRICS_TOKEN. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: CC-Girl <cc-girl@multica.ai> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
131 lines
5.4 KiB
Plaintext
131 lines
5.4 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 dev-only auth shortcuts (primarily the 888888 master code).
|
|
# - Docker self-host: docker-compose.selfhost.yml already pins APP_ENV to
|
|
# "production" by default, so 888888 is DISABLED — a public instance can't
|
|
# be logged into with any email + 888888.
|
|
# - Local dev (make dev): leave APP_ENV unset so 888888 works out of the box.
|
|
# - Docker self-host on a private network you fully control, or evaluation
|
|
# without Resend: set APP_ENV=development to re-enable 888888. Do NOT
|
|
# enable on a publicly reachable instance.
|
|
# See SELF_HOSTING.md for the full login setup.
|
|
APP_ENV=
|
|
PORT=8080
|
|
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 — codes print to stdout, and
|
|
# master code 888888 works (only when APP_ENV != "production"; see above).
|
|
# 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=
|
|
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=
|