diff --git a/docker/docker-compose.proxy.yml b/docker/docker-compose.proxy.yml new file mode 100644 index 000000000..1990f6db8 --- /dev/null +++ b/docker/docker-compose.proxy.yml @@ -0,0 +1,54 @@ +# ============================================================================= +# SurfSense — Optional Caddy reverse-proxy overlay +# ============================================================================= +# Usage (from docker/): +# PROXY_HTTP_PORT=8080 SURFSENSE_PUBLIC_URL=http://localhost:8080 \ +# docker compose -f docker-compose.yml -f docker-compose.proxy.yml up -d +# +# This overlay is for validation and custom deployments. The production +# docker-compose.yml includes Caddy by default. +# ============================================================================= + +services: + backend: + ports: + - "${BACKEND_PORT:-8929}:8000" + + zero-cache: + ports: + - "${ZERO_CACHE_PORT:-5929}:4848" + + frontend: + ports: + - "${FRONTEND_PORT:-3929}:3000" + + proxy: + image: caddy:2-alpine + restart: unless-stopped + ports: + - "${PROXY_HTTP_PORT:-8080}:80" + - "${PROXY_HTTPS_PORT:-8443}: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 + +volumes: + caddy_data: + name: surfsense-caddy-data + caddy_config: + name: surfsense-caddy-config diff --git a/docker/proxy/Caddyfile b/docker/proxy/Caddyfile new file mode 100644 index 000000000..2553b8474 --- /dev/null +++ b/docker/proxy/Caddyfile @@ -0,0 +1,36 @@ +{ + # Optional ACME/global settings. These are harmless in the default :80 + # localhost mode and become active when SURFSENSE_SITE_ADDRESS is a domain. + {$CERT_EMAIL} + acme_ca {$CERT_ACME_CA:https://acme-v02.api.letsencrypt.org/directory} + {$CERT_ACME_DNS} + servers { + client_ip_headers X-Forwarded-For X-Real-IP + trusted_proxies static {$TRUSTED_PROXIES:0.0.0.0/0} + } +} + +(surfsense_proxy) { + request_body { + max_size {$SURFSENSE_MAX_BODY_SIZE:5GB} + } + + # Backend auth routes (FastAPI Users + OAuth helpers). + reverse_proxy /auth/* backend:8000 + + # Backend REST, streaming, connector OAuth, and messaging gateway endpoints. + # FastAPI already serves /api/v1, so the path is forwarded unchanged. + reverse_proxy /api/v1/* backend:8000 + + # Zero accepts a single path-component base URL (Zero >= 0.6). + # Preserve /zero so browser cacheURL can be ${SURFSENSE_PUBLIC_URL}/zero. + reverse_proxy /zero/* zero-cache:4848 + + # Next.js app and frontend-owned API routes: + # /api/zero/*, /api/search, /api/contact, etc. + reverse_proxy /* frontend:3000 +} + +{$SURFSENSE_SITE_ADDRESS::80} { + import surfsense_proxy +} diff --git a/docker/proxy/Dockerfile b/docker/proxy/Dockerfile new file mode 100644 index 000000000..8395a817c --- /dev/null +++ b/docker/proxy/Dockerfile @@ -0,0 +1,10 @@ +FROM caddy:2-builder-alpine AS builder + +RUN xcaddy build \ + --with github.com/caddy-dns/cloudflare \ + --with github.com/caddy-dns/digitalocean + +FROM caddy:2-alpine + +COPY --from=builder /usr/bin/caddy /usr/bin/caddy +COPY Caddyfile /etc/caddy/Caddyfile