From 34a49df8a306af674cd41fbbb05785c05401c341 Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Tue, 16 Jun 2026 02:12:11 +0530 Subject: [PATCH] docs: document runtime env vars and same-origin proxy access --- docker/.env.example | 42 +++++++++---------- surfsense_web/.env.example | 15 ++++--- .../docs/docker-installation/dev-compose.mdx | 12 +++--- .../content/docs/how-to/zero-sync.mdx | 6 +-- .../content/docs/manual-installation.mdx | 20 +++++---- 5 files changed, 48 insertions(+), 47 deletions(-) diff --git a/docker/.env.example b/docker/.env.example index d3598f16a..71c743837 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -30,6 +30,9 @@ SECRET_KEY=replace_me_with_a_random_string # Auth type: LOCAL (email/password) or GOOGLE (OAuth) AUTH_TYPE=LOCAL +# Deployment mode: self-hosted enables local filesystem connectors; cloud hides them. +DEPLOYMENT_MODE=self-hosted + # Allow new user registrations (TRUE or FALSE) # REGISTRATION_ENABLED=TRUE @@ -45,9 +48,8 @@ EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2 # ------------------------------------------------------------------------------ # How You Access SurfSense # ------------------------------------------------------------------------------ -# Default local URL: http://localhost:3929 -# Most local installs can leave this unchanged. -# SURFSENSE_PUBLIC_URL=http://localhost:3929 +# One public URL. Browser traffic stays same-origin and Caddy routes internally. +SURFSENSE_PUBLIC_URL=http://localhost:3929 # ------------------------------------------------------------------------------ # Public Ports @@ -57,8 +59,8 @@ EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2 # # Local default: LISTEN_HTTP_PORT=3929 # Domain default: LISTEN_HTTP_PORT=80 and LISTEN_HTTPS_PORT=443 -# LISTEN_HTTP_PORT=3929 -# LISTEN_HTTPS_PORT=443 +LISTEN_HTTP_PORT=3929 +LISTEN_HTTPS_PORT=443 # ------------------------------------------------------------------------------ # Custom Domain / HTTPS @@ -67,8 +69,8 @@ EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2 # Set it to your domain to enable automatic HTTPS: # SURFSENSE_SITE_ADDRESS=surf.example.com # CERT_EMAIL=you@example.com -# SURFSENSE_SITE_ADDRESS=:80 -# CERT_EMAIL= +SURFSENSE_SITE_ADDRESS=:80 +CERT_EMAIL= # ------------------------------------------------------------------------------ # Advanced Reverse Proxy Settings @@ -78,18 +80,13 @@ EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2 # # CERT_ACME_CA=https://acme-v02.api.letsencrypt.org/directory # CERT_ACME_DNS= +# If a CDN/load balancer sits in front of Caddy, narrow this to that proxy's CIDRs. # TRUSTED_PROXIES=0.0.0.0/0 # SURFSENSE_MAX_BODY_SIZE=5GB # -# These browser-facing URLs are derived from SURFSENSE_PUBLIC_URL in -# docker-compose.yml: -# 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 URL. Usually do not change. -# FASTAPI_BACKEND_INTERNAL_URL=http://backend:8000 +# Browser API and Zero URLs are same-origin relative behind bundled Caddy. +# Next.js server-side calls use Docker DNS through SURFSENSE_BACKEND_INTERNAL_URL +# set internally by docker-compose.yml. Usually do not override it. # ------------------------------------------------------------------------------ # Zero-cache (real-time sync) @@ -485,10 +482,9 @@ NOLOGIN_MODE_ENABLED=FALSE # FRONTEND_PORT=3000 # ZERO_CACHE_PORT=4848 -# -- Frontend build args (dev compose only) -- -# In dev, the frontend is built from source and these are passed as build args. -# In prod, runtime values are derived from AUTH_TYPE, ETL_SERVICE, and -# SURFSENSE_PUBLIC_URL. -# NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE=LOCAL -# NEXT_PUBLIC_ETL_SERVICE=DOCLING -# NEXT_PUBLIC_DEPLOYMENT_MODE=self-hosted +# -- Frontend runtime flags (prod and dev compose) -- +# The frontend reads these at request time in Docker; no NEXT_PUBLIC_* rebuild +# or startup substitution is required. +# AUTH_TYPE=LOCAL +# ETL_SERVICE=DOCLING +# DEPLOYMENT_MODE=self-hosted diff --git a/surfsense_web/.env.example b/surfsense_web/.env.example index 5fb9d07d1..746957257 100644 --- a/surfsense_web/.env.example +++ b/surfsense_web/.env.example @@ -1,18 +1,17 @@ -NEXT_PUBLIC_FASTAPI_BACKEND_URL=http://localhost:8000 +# Optional packaged-client override. Leave unset in Docker so browser requests +# use same-origin relative URLs behind Caddy. +# NEXT_PUBLIC_FASTAPI_BACKEND_URL=http://localhost:8000 # Server-only. Internal backend URL used by Next.js server code. -FASTAPI_BACKEND_INTERNAL_URL=https://your-internal-backend.example.com +SURFSENSE_BACKEND_INTERNAL_URL=http://backend:8000 -NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE=LOCAL or GOOGLE -NEXT_PUBLIC_ETL_SERVICE=UNSTRUCTURED or LLAMACLOUD or DOCLING -NEXT_PUBLIC_ZERO_CACHE_URL=http://localhost:4848 +AUTH_TYPE=LOCAL +ETL_SERVICE=DOCLING +DEPLOYMENT_MODE=self-hosted # Contact Form Vars (optional) DATABASE_URL=postgresql://postgres:[YOUR-PASSWORD]@db.sdsf.supabase.co:5432/postgres -# Deployment mode (optional) -NEXT_PUBLIC_DEPLOYMENT_MODE="self-hosted" or "cloud" - # PostHog analytics (optional, leave empty to disable) NEXT_PUBLIC_POSTHOG_KEY= diff --git a/surfsense_web/content/docs/docker-installation/dev-compose.mdx b/surfsense_web/content/docs/docker-installation/dev-compose.mdx index 0bfe75aa2..e16c6a685 100644 --- a/surfsense_web/content/docs/docker-installation/dev-compose.mdx +++ b/surfsense_web/content/docs/docker-installation/dev-compose.mdx @@ -26,12 +26,14 @@ The following `.env` variables are **only used by the dev compose file** (they h | `PGADMIN_DEFAULT_EMAIL` | pgAdmin login email | `admin@surfsense.com` | | `PGADMIN_DEFAULT_PASSWORD` | pgAdmin login password | `surfsense` | | `REDIS_PORT` | Exposed Redis port (internal-only in prod) | `6379` | -| `NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE` | Frontend build arg for auth type | `LOCAL` | -| `NEXT_PUBLIC_ETL_SERVICE` | Frontend build arg for ETL service | `DOCLING` | -| `NEXT_PUBLIC_ZERO_CACHE_URL` | Frontend build arg for Zero-cache URL | `http://localhost:4848` | -| `NEXT_PUBLIC_DEPLOYMENT_MODE` | Frontend build arg for deployment mode | `self-hosted` | +| `AUTH_TYPE` | Runtime auth mode | `LOCAL` | +| `ETL_SERVICE` | Runtime document parsing service | `DOCLING` | +| `DEPLOYMENT_MODE` | Runtime deployment mode | `self-hosted` | +| `ZERO_CACHE_PORT` | Exposed zero-cache port for debugging | `4848` | -In the production compose file, the `NEXT_PUBLIC_*` frontend variables are automatically derived from `AUTH_TYPE`, `ETL_SERVICE`, and the port settings. In the dev compose file, they are passed as build args since the frontend is built from source. +In the production compose file, the frontend reads `AUTH_TYPE`, `ETL_SERVICE`, +and `DEPLOYMENT_MODE` at request time. Browser API and Zero traffic are +same-origin relative through bundled Caddy. Production Docker exposes only the bundled Caddy proxy by default; dev compose keeps direct service ports so contributors can inspect and restart individual services without going through the proxy. diff --git a/surfsense_web/content/docs/how-to/zero-sync.mdx b/surfsense_web/content/docs/how-to/zero-sync.mdx index 22ba851b4..728da9b86 100644 --- a/surfsense_web/content/docs/how-to/zero-sync.mdx +++ b/surfsense_web/content/docs/how-to/zero-sync.mdx @@ -35,7 +35,7 @@ zero-cache is included in the Docker Compose setup. The key environment variable | `SURFSENSE_PUBLIC_URL` | Public SurfSense origin used by the browser | `http://localhost:3929` | | `ZERO_ADMIN_PASSWORD` | Password for the zero-cache admin UI and `/statz` endpoint | `surfsense-zero-admin` | | `ZERO_UPSTREAM_DB` | PostgreSQL connection URL for replication | Built from `DB_*` vars | -| `NEXT_PUBLIC_ZERO_CACHE_URL` | URL the frontend uses to connect to zero-cache | `${SURFSENSE_PUBLIC_URL}/zero` | +| `/zero` | Same-origin browser path Caddy routes to zero-cache | `${SURFSENSE_PUBLIC_URL}/zero` | | `ZERO_APP_PUBLICATIONS` | PostgreSQL publication restricting which tables are replicated | `zero_publication` | | `ZERO_NUM_SYNC_WORKERS` | Number of view-sync worker processes. Must be ≤ `ZERO_UPSTREAM_MAX_CONNS` and ≤ `ZERO_CVR_MAX_CONNS` | `4` | | `ZERO_UPSTREAM_MAX_CONNS` | Max connections to upstream PostgreSQL for mutations | `20` | @@ -64,7 +64,7 @@ If running the frontend outside Docker (e.g. `pnpm dev`), you need: ``` Run `uv run alembic upgrade head` from `surfsense_backend/` **before** starting this container so the `zero_publication` exists. -2. **`NEXT_PUBLIC_ZERO_CACHE_URL`** set in `surfsense_web/.env` (default: `http://localhost:4848`). +2. If the frontend is not behind bundled Caddy, set `NEXT_PUBLIC_ZERO_CACHE_URL=http://localhost:4848` before building/running the frontend so the browser connects directly to zero-cache. 3. **`wal_level = logical`** in your PostgreSQL config (see [Manual Installation → Configure PostgreSQL for Zero Sync](/docs/manual-installation#3-configure-postgresql-for-zero-sync)). For the full manual setup walkthrough, see the [Manual Installation guide](/docs/manual-installation). @@ -114,7 +114,7 @@ Zero syncs the following tables for real-time features: - **zero-cache not starting**: Check `docker compose logs zero-cache`. Ensure PostgreSQL has `wal_level=logical` (configured in `postgresql.conf`). - **"Insufficient upstream connections" error**: zero-cache defaults `ZERO_NUM_SYNC_WORKERS` to the number of CPU cores, which can exceed connection pool limits on high-core machines. Lower `ZERO_NUM_SYNC_WORKERS` or raise `ZERO_UPSTREAM_MAX_CONNS` / `ZERO_CVR_MAX_CONNS` in your `.env`. -- **Frontend not syncing**: Open DevTools → Console and check for WebSocket connection errors. In production Docker, verify `NEXT_PUBLIC_ZERO_CACHE_URL` resolves to `${SURFSENSE_PUBLIC_URL}/zero`. +- **Frontend not syncing**: Open DevTools → Console and check for WebSocket connection errors. In production Docker, verify Caddy serves `${SURFSENSE_PUBLIC_URL}/zero`. In manual local development, verify `NEXT_PUBLIC_ZERO_CACHE_URL` points at the running zero-cache port. - **Stale data after restart**: zero-cache rebuilds its SQLite replica from PostgreSQL on startup. This may take a moment for large databases. ## Learn More diff --git a/surfsense_web/content/docs/manual-installation.mdx b/surfsense_web/content/docs/manual-installation.mdx index 22a8ff5a1..ab09b4155 100644 --- a/surfsense_web/content/docs/manual-installation.mdx +++ b/surfsense_web/content/docs/manual-installation.mdx @@ -546,7 +546,10 @@ cd ../docker docker compose -f docker-compose.deps-only.yml up -d ``` -The deps-only stack exposes zero-cache on port `4848` by default. Keep `NEXT_PUBLIC_ZERO_CACHE_URL=http://localhost:4848` in your `surfsense_web/.env`. +The deps-only stack exposes zero-cache on port `4848` by default. If your +frontend is not behind a reverse proxy that serves `/zero`, set +`NEXT_PUBLIC_ZERO_CACHE_URL=http://localhost:4848` before building/running the +frontend. ## Frontend Setup @@ -577,12 +580,13 @@ Copy-Item -Path .env.example -Destination .env Edit the `.env` file and set: -| ENV VARIABLE | DESCRIPTION | -| ------------------------------- | ------------------------------------------- | -| NEXT_PUBLIC_FASTAPI_BACKEND_URL | Backend URL (e.g., `http://localhost:8000`) | -| NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE | Same value as set in backend AUTH_TYPE i.e `GOOGLE` for OAuth with Google, `LOCAL` for email/password authentication | -| NEXT_PUBLIC_ETL_SERVICE | Document parsing service (should match backend ETL_SERVICE): `UNSTRUCTURED`, `LLAMACLOUD`, or `DOCLING` - affects supported file formats in upload interface | -| NEXT_PUBLIC_ZERO_CACHE_URL | URL for Zero-cache real-time sync service (e.g., `http://localhost:4848`) | +| ENV VARIABLE | DESCRIPTION | +| --- | --- | +| `SURFSENSE_BACKEND_INTERNAL_URL` | Backend URL used by Next.js server routes, e.g. `http://localhost:8000` or `http://backend:8000` in Docker | +| `AUTH_TYPE` | Same value as backend auth type: `GOOGLE` for OAuth with Google, `LOCAL` for email/password authentication | +| `ETL_SERVICE` | Document parsing service (should match backend ETL_SERVICE): `UNSTRUCTURED`, `LLAMACLOUD`, or `DOCLING`; affects supported file formats in the upload interface | +| `DEPLOYMENT_MODE` | `self-hosted` or `cloud`; controls self-hosted-only connector visibility | +| `NEXT_PUBLIC_ZERO_CACHE_URL` | Only needed when the browser cannot reach Zero through same-origin `/zero`, e.g. manual local dev at `http://localhost:4848` | ### 2. Install Dependencies @@ -693,7 +697,7 @@ To verify your installation: - **Authentication Problems**: Check your Google OAuth configuration and ensure redirect URIs are set correctly - **LLM Errors**: Confirm your LLM API keys are valid and the selected models are accessible - **File Upload Failures**: Validate your ETL service API key (Unstructured.io or LlamaCloud) or ensure Docling is properly configured -- **Real-time updates not working / stale UI**: Verify zero-cache is running (`curl http://localhost:4848/keepalive` returns 200). Open browser DevTools → Console and look for WebSocket errors. Confirm `NEXT_PUBLIC_ZERO_CACHE_URL` in `surfsense_web/.env` matches the running zero-cache address. +- **Real-time updates not working / stale UI**: Verify zero-cache is running (`curl http://localhost:4848/keepalive` returns 200). Open browser DevTools → Console and look for WebSocket errors. In default Docker, confirm `/zero` is routed by Caddy. In manual local development, confirm `NEXT_PUBLIC_ZERO_CACHE_URL` in `surfsense_web/.env` matches the running zero-cache address. - **Zero-cache stuck on `Unknown or invalid publications. Specified: [zero_publication]`**: You skipped (or never ran) `uv run alembic upgrade head` from `surfsense_backend/`. Run it, then restart the zero-cache container with `docker restart surfsense-zero-cache`. - **Zero-cache crashes with `_zero.tableMetadata` errors**: A previous run left a half-built SQLite replica behind. Stop the container, remove the volume, and start fresh: `docker rm -f surfsense-zero-cache && docker volume rm surfsense-zero-cache && docker run -d ...` (re-run the command from [Zero-Cache Setup](#zero-cache-setup)). - **`wal_level` is not set to `logical`**: zero-cache requires logical replication. Set `wal_level = logical` in `postgresql.conf`, restart PostgreSQL, and verify with `SHOW wal_level;` in psql.