From 237301494372091110ff9af582d68b319e4e6298 Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Mon, 15 Jun 2026 11:03:33 +0530 Subject: [PATCH] feat(docker): route production stack through bundled proxy --- docker/.env.example | 97 +++++++++++++++++++++++++-------------- docker/docker-compose.yml | 53 +++++++++++++++++---- 2 files changed, 106 insertions(+), 44 deletions(-) diff --git a/docker/.env.example b/docker/.env.example index c19c50545..8257a80d6 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -43,12 +43,15 @@ ETL_SERVICE=DOCLING EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2 # ------------------------------------------------------------------------------ -# Ports (change to avoid conflicts with other services on your machine) +# Public proxy ports (change to avoid conflicts with other services on your machine) # ------------------------------------------------------------------------------ -# BACKEND_PORT=8929 -# FRONTEND_PORT=3929 -# ZERO_CACHE_PORT=5929 +# LISTEN_HTTP_PORT maps the bundled Caddy proxy's container port 80 to the host. +# The default preserves the familiar http://localhost:3929 URL. +# LISTEN_HTTP_PORT=3929 +# +# LISTEN_HTTPS_PORT is used when SURFSENSE_SITE_ADDRESS is a domain. +# LISTEN_HTTPS_PORT=443 # SEARXNG_PORT=8888 # ============================================================================== @@ -66,6 +69,11 @@ EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2 # -- WhatsApp bridge exposed port (dev/hybrid only; prod keeps it Docker-internal) -- # WHATSAPP_BRIDGE_PORT=9929 +# +# -- Raw app ports (dev/deps-only compose only; prod exposes Caddy instead) -- +# BACKEND_PORT=8000 +# FRONTEND_PORT=3000 +# ZERO_CACHE_PORT=4848 # -- Frontend Build Args -- # In dev, the frontend is built from source and these are passed as build args. @@ -75,17 +83,36 @@ EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2 # NEXT_PUBLIC_DEPLOYMENT_MODE=self-hosted # ------------------------------------------------------------------------------ -# Custom Domain / Reverse Proxy +# Public URL / Reverse Proxy # ------------------------------------------------------------------------------ -# ONLY set these if you are serving SurfSense on a real domain via a reverse -# proxy (e.g. Caddy, Nginx, Cloudflare Tunnel). -# For standard localhost deployments, leave all of these commented out. -# they are automatically derived from the port settings above. +# SurfSense includes Caddy as the default single public entry point. +# Localhost defaults require no changes: +# SURFSENSE_SITE_ADDRESS=:80 +# LISTEN_HTTP_PORT=3929 +# SURFSENSE_PUBLIC_URL=http://localhost:3929 # -# NEXT_FRONTEND_URL=https://app.yourdomain.com -# BACKEND_URL=https://api.yourdomain.com -# NEXT_PUBLIC_FASTAPI_BACKEND_URL=https://api.yourdomain.com -# NEXT_PUBLIC_ZERO_CACHE_URL=https://zero.yourdomain.com +# For a real domain, point DNS at this host and set: +# SURFSENSE_SITE_ADDRESS=surf.example.com +# LISTEN_HTTP_PORT=80 +# LISTEN_HTTPS_PORT=443 +# CERT_EMAIL=you@example.com +# SURFSENSE_PUBLIC_URL=https://surf.example.com +# +# SURFSENSE_SITE_ADDRESS=:80 +# SURFSENSE_PUBLIC_URL=http://localhost:3929 +# CERT_EMAIL= +# CERT_ACME_CA=https://acme-v02.api.letsencrypt.org/directory +# CERT_ACME_DNS= +# TRUSTED_PROXIES=0.0.0.0/0 +# SURFSENSE_MAX_BODY_SIZE=5GB +# +# The compose file derives the browser-facing URLs from SURFSENSE_PUBLIC_URL: +# NEXT_FRONTEND_URL=${SURFSENSE_PUBLIC_URL} +# BACKEND_URL=${SURFSENSE_PUBLIC_URL} +# NEXT_PUBLIC_FASTAPI_BACKEND_URL=${SURFSENSE_PUBLIC_URL} +# NEXT_PUBLIC_ZERO_CACHE_URL=${SURFSENSE_PUBLIC_URL}/zero +# +# Internal service-to-service URLs stay on Docker DNS: # FASTAPI_BACKEND_INTERNAL_URL=http://backend:8000 # ------------------------------------------------------------------------------ @@ -131,9 +158,9 @@ EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2 # Override when running the frontend outside Docker: # ZERO_QUERY_URL=http://host.docker.internal:3000/api/zero/query # ZERO_MUTATE_URL=http://host.docker.internal:3000/api/zero/mutate -# Override for custom domain: -# ZERO_QUERY_URL=https://app.yourdomain.com/api/zero/query -# ZERO_MUTATE_URL=https://app.yourdomain.com/api/zero/mutate +# Override for custom domain only when zero-cache is not in the bundled Docker network: +# ZERO_QUERY_URL=https://surf.example.com/api/zero/query +# ZERO_MUTATE_URL=https://surf.example.com/api/zero/mutate # ZERO_QUERY_URL=http://frontend:3000/api/zero/query # ZERO_MUTATE_URL=http://frontend:3000/api/zero/mutate @@ -221,62 +248,62 @@ STT_SERVICE=local/base # ------------------------------------------------------------------------------ # -- Google Connectors -- -# GOOGLE_CALENDAR_REDIRECT_URI=http://localhost:8000/api/v1/auth/google/calendar/connector/callback -# GOOGLE_GMAIL_REDIRECT_URI=http://localhost:8000/api/v1/auth/google/gmail/connector/callback -# GOOGLE_DRIVE_REDIRECT_URI=http://localhost:8000/api/v1/auth/google/drive/connector/callback +# GOOGLE_CALENDAR_REDIRECT_URI=http://localhost:3929/api/v1/auth/google/calendar/connector/callback +# GOOGLE_GMAIL_REDIRECT_URI=http://localhost:3929/api/v1/auth/google/gmail/connector/callback +# GOOGLE_DRIVE_REDIRECT_URI=http://localhost:3929/api/v1/auth/google/drive/connector/callback # -- Notion -- # NOTION_CLIENT_ID= # NOTION_CLIENT_SECRET= -# NOTION_REDIRECT_URI=http://localhost:8000/api/v1/auth/notion/connector/callback +# NOTION_REDIRECT_URI=http://localhost:3929/api/v1/auth/notion/connector/callback # -- Slack -- # SLACK_CLIENT_ID= # SLACK_CLIENT_SECRET= -# SLACK_REDIRECT_URI=http://localhost:8000/api/v1/auth/slack/connector/callback +# SLACK_REDIRECT_URI=http://localhost:3929/api/v1/auth/slack/connector/callback # -- Discord -- # DISCORD_CLIENT_ID= # DISCORD_CLIENT_SECRET= -# DISCORD_REDIRECT_URI=http://localhost:8000/api/v1/auth/discord/connector/callback +# DISCORD_REDIRECT_URI=http://localhost:3929/api/v1/auth/discord/connector/callback # DISCORD_BOT_TOKEN= # -- Atlassian (Jira & Confluence) -- # ATLASSIAN_CLIENT_ID= # ATLASSIAN_CLIENT_SECRET= -# JIRA_REDIRECT_URI=http://localhost:8000/api/v1/auth/jira/connector/callback -# CONFLUENCE_REDIRECT_URI=http://localhost:8000/api/v1/auth/confluence/connector/callback +# JIRA_REDIRECT_URI=http://localhost:3929/api/v1/auth/jira/connector/callback +# CONFLUENCE_REDIRECT_URI=http://localhost:3929/api/v1/auth/confluence/connector/callback # -- Linear -- # LINEAR_CLIENT_ID= # LINEAR_CLIENT_SECRET= -# LINEAR_REDIRECT_URI=http://localhost:8000/api/v1/auth/linear/connector/callback +# LINEAR_REDIRECT_URI=http://localhost:3929/api/v1/auth/linear/connector/callback # -- ClickUp -- # CLICKUP_CLIENT_ID= # CLICKUP_CLIENT_SECRET= -# CLICKUP_REDIRECT_URI=http://localhost:8000/api/v1/auth/clickup/connector/callback +# CLICKUP_REDIRECT_URI=http://localhost:3929/api/v1/auth/clickup/connector/callback # -- Airtable -- # AIRTABLE_CLIENT_ID= # AIRTABLE_CLIENT_SECRET= -# AIRTABLE_REDIRECT_URI=http://localhost:8000/api/v1/auth/airtable/connector/callback +# AIRTABLE_REDIRECT_URI=http://localhost:3929/api/v1/auth/airtable/connector/callback # -- Microsoft OAuth (Teams & OneDrive) -- # MICROSOFT_CLIENT_ID= # MICROSOFT_CLIENT_SECRET= -# TEAMS_REDIRECT_URI=http://localhost:8000/api/v1/auth/teams/connector/callback -# ONEDRIVE_REDIRECT_URI=http://localhost:8000/api/v1/auth/onedrive/connector/callback +# TEAMS_REDIRECT_URI=http://localhost:3929/api/v1/auth/teams/connector/callback +# ONEDRIVE_REDIRECT_URI=http://localhost:3929/api/v1/auth/onedrive/connector/callback # -- Dropbox -- # DROPBOX_APP_KEY= # DROPBOX_APP_SECRET= -# DROPBOX_REDIRECT_URI=http://localhost:8000/api/v1/auth/dropbox/connector/callback +# DROPBOX_REDIRECT_URI=http://localhost:3929/api/v1/auth/dropbox/connector/callback # -- Composio -- # COMPOSIO_API_KEY= # COMPOSIO_ENABLED=TRUE -# COMPOSIO_REDIRECT_URI=http://localhost:8000/api/v1/auth/composio/connector/callback +# COMPOSIO_REDIRECT_URI=http://localhost:3929/api/v1/auth/composio/connector/callback # ------------------------------------------------------------------------------ # Messaging Channels (optional) @@ -287,7 +314,7 @@ STT_SERVICE=local/base # TELEGRAM_SHARED_BOT_TOKEN= # TELEGRAM_SHARED_BOT_USERNAME= # TELEGRAM_WEBHOOK_SECRET= -# GATEWAY_BASE_URL=http://localhost:8929 +# GATEWAY_BASE_URL=http://localhost:3929 # GATEWAY_TELEGRAM_INTAKE_MODE=webhook # -- WhatsApp -- @@ -306,20 +333,20 @@ STT_SERVICE=local/base # # GATEWAY_SLACK_ENABLED=FALSE # GATEWAY_SLACK_SIGNING_SECRET= -# GATEWAY_SLACK_REDIRECT_URI=http://localhost:8929/api/v1/gateway/slack/callback +# GATEWAY_SLACK_REDIRECT_URI=http://localhost:3929/api/v1/gateway/slack/callback # -- Discord -- # Uses DISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET, and DISCORD_BOT_TOKEN from the # Discord connector section. # # GATEWAY_DISCORD_ENABLED=FALSE -# GATEWAY_DISCORD_REDIRECT_URI=http://localhost:8929/api/v1/gateway/discord/callback +# GATEWAY_DISCORD_REDIRECT_URI=http://localhost:3929/api/v1/gateway/discord/callback # ------------------------------------------------------------------------------ # SearXNG (bundled web search, works out of the box with no config needed) # ------------------------------------------------------------------------------ # SearXNG provides web search to all search spaces automatically. -# To access the SearXNG UI directly: http://localhost:8888 +# To access the SearXNG UI directly in dev/deps-only compose: http://localhost:8888 # To disable the service entirely: docker compose up --scale searxng=0 # To point at your own SearXNG instance instead of the bundled one: # SEARXNG_DEFAULT_HOST=http://your-searxng:8080 diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 9bbf28ffd..342753ed3 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -94,10 +94,39 @@ services: timeout: 5s retries: 5 + # Single public entry point for the Docker stack. Comment this service out + # only if you front SurfSense with your own reverse proxy. + proxy: + image: caddy:2-alpine + # For DNS-01/wildcard certificates, replace image with: + # build: ./proxy + restart: unless-stopped + ports: + - "${LISTEN_HTTP_PORT:-3929}:80" + - "${LISTEN_HTTPS_PORT:-443}:443" + volumes: + - ./proxy/Caddyfile:/etc/caddy/Caddyfile:ro + - caddy_data:/data + - caddy_config:/config + environment: + SURFSENSE_SITE_ADDRESS: ${SURFSENSE_SITE_ADDRESS:-:80} + CERT_EMAIL: ${CERT_EMAIL:-} + CERT_ACME_CA: ${CERT_ACME_CA:-https://acme-v02.api.letsencrypt.org/directory} + CERT_ACME_DNS: ${CERT_ACME_DNS:-} + TRUSTED_PROXIES: ${TRUSTED_PROXIES:-0.0.0.0/0} + SURFSENSE_MAX_BODY_SIZE: ${SURFSENSE_MAX_BODY_SIZE:-5GB} + depends_on: + frontend: + condition: service_started + backend: + condition: service_healthy + zero-cache: + condition: service_healthy + backend: image: ghcr.io/modsetter/surfsense-backend:${SURFSENSE_VERSION:-latest}${SURFSENSE_VARIANT:+-${SURFSENSE_VARIANT}} - ports: - - "${BACKEND_PORT:-8929}:8000" + expose: + - "8000" volumes: - shared_temp:/shared_tmp env_file: @@ -113,7 +142,8 @@ services: PYTHONPATH: /app UVICORN_LOOP: asyncio UNSTRUCTURED_HAS_PATCHED_LOOP: "1" - NEXT_FRONTEND_URL: ${NEXT_FRONTEND_URL:-http://localhost:${FRONTEND_PORT:-3929}} + NEXT_FRONTEND_URL: ${NEXT_FRONTEND_URL:-${SURFSENSE_PUBLIC_URL:-http://localhost:${LISTEN_HTTP_PORT:-3929}}} + BACKEND_URL: ${BACKEND_URL:-${SURFSENSE_PUBLIC_URL:-http://localhost:${LISTEN_HTTP_PORT:-3929}}} SEARXNG_DEFAULT_HOST: ${SEARXNG_DEFAULT_HOST:-http://searxng:8080} WHATSAPP_BRIDGE_URL: ${WHATSAPP_BRIDGE_URL:-http://whatsapp-bridge:9929} # Daytona Sandbox – uncomment and set credentials to enable cloud code execution @@ -217,8 +247,8 @@ services: zero-cache: image: rocicorp/zero:1.4.0 - ports: - - "${ZERO_CACHE_PORT:-5929}:4848" + expose: + - "4848" extra_hosts: - "host.docker.internal:host-gateway" environment: @@ -252,11 +282,12 @@ services: frontend: image: ghcr.io/modsetter/surfsense-web:${SURFSENSE_VERSION:-latest} - ports: - - "${FRONTEND_PORT:-3929}:3000" + expose: + - "3000" environment: - NEXT_PUBLIC_FASTAPI_BACKEND_URL: ${NEXT_PUBLIC_FASTAPI_BACKEND_URL:-http://localhost:${BACKEND_PORT:-8929}} - NEXT_PUBLIC_ZERO_CACHE_URL: ${NEXT_PUBLIC_ZERO_CACHE_URL:-http://localhost:${ZERO_CACHE_PORT:-5929}} + NEXT_PUBLIC_FASTAPI_BACKEND_URL: ${NEXT_PUBLIC_FASTAPI_BACKEND_URL:-${SURFSENSE_PUBLIC_URL:-http://localhost:${LISTEN_HTTP_PORT:-3929}}} + NEXT_PUBLIC_ZERO_CACHE_URL: ${NEXT_PUBLIC_ZERO_CACHE_URL:-${SURFSENSE_PUBLIC_URL:-http://localhost:${LISTEN_HTTP_PORT:-3929}}/zero} + BACKEND_URL: ${BACKEND_URL:-${SURFSENSE_PUBLIC_URL:-http://localhost:${LISTEN_HTTP_PORT:-3929}}} NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE: ${AUTH_TYPE:-LOCAL} NEXT_PUBLIC_ETL_SERVICE: ${ETL_SERVICE:-DOCLING} NEXT_PUBLIC_DEPLOYMENT_MODE: ${DEPLOYMENT_MODE:-self-hosted} @@ -280,5 +311,9 @@ volumes: name: surfsense-shared-temp zero_cache_data: name: surfsense-zero-cache + caddy_data: + name: surfsense-caddy-data + caddy_config: + name: surfsense-caddy-config whatsapp_sessions: name: surfsense-whatsapp-sessions