Skip to content

Commit 6d9540a

Browse files
committed
docs(docker): document single-origin proxy deployment
1 parent 2c6cf8d commit 6d9540a

5 files changed

Lines changed: 106 additions & 34 deletions

File tree

surfsense_web/content/docs/docker-installation/dev-compose.mdx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ cd SurfSense/docker
1010
docker compose -f docker-compose.dev.yml up --build
1111
```
1212

13-
This file builds the backend and frontend from your local source code (instead of pulling prebuilt images) and includes pgAdmin for database inspection at [http://localhost:5050](http://localhost:5050). Use the production `docker-compose.yml` for all other cases.
13+
This file builds the backend and frontend from your local source code (instead
14+
of pulling prebuilt images) and includes pgAdmin for database inspection at
15+
[http://localhost:5050](http://localhost:5050). It intentionally keeps raw
16+
frontend, backend, and zero-cache ports published for debugging. Use the
17+
production `docker-compose.yml` for the default Caddy single-origin setup.
1418

1519
## Dev-Only Environment Variables
1620

@@ -28,3 +32,6 @@ The following `.env` variables are **only used by the dev compose file** (they h
2832
| `NEXT_PUBLIC_DEPLOYMENT_MODE` | Frontend build arg for deployment mode | `self-hosted` |
2933

3034
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.
35+
Production Docker exposes only the bundled Caddy proxy by default; dev compose
36+
keeps direct service ports so contributors can inspect and restart individual
37+
services without going through the proxy.

surfsense_web/content/docs/docker-installation/docker-compose.mdx

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ docker compose up -d
1515

1616
After starting, access SurfSense at:
1717

18-
- **Frontend**: [http://localhost:3929](http://localhost:3929)
19-
- **Backend API**: [http://localhost:8929](http://localhost:8929)
20-
- **API Docs**: [http://localhost:8929/docs](http://localhost:8929/docs)
18+
- **SurfSense**: [http://localhost:3929](http://localhost:3929)
19+
- **Backend API**: [http://localhost:3929/api/v1](http://localhost:3929/api/v1)
20+
- **Zero sync**: `ws://localhost:3929/zero`
2121
---
2222

2323
## Configuration
@@ -99,24 +99,59 @@ docker run -d --name watchtower \
9999

100100
SurfSense containers are labeled for Watchtower, so `--label-enable` limits updates to the SurfSense services.
101101

102-
### Ports
102+
### Public URL and Ports
103103

104104
| Variable | Description | Default |
105105
|----------|-------------|---------|
106-
| `FRONTEND_PORT` | Frontend service port | `3929` |
107-
| `BACKEND_PORT` | Backend API service port | `8929` |
108-
| `ZERO_CACHE_PORT` | Zero-cache real-time sync port | `5929` |
106+
| `SURFSENSE_PUBLIC_URL` | Public origin used by the frontend, backend OAuth callbacks, and Zero browser URL | `http://localhost:3929` |
107+
| `SURFSENSE_SITE_ADDRESS` | Caddy site address. `:80` means local plain HTTP; a hostname enables automatic HTTPS | `:80` |
108+
| `LISTEN_HTTP_PORT` | Host port mapped to Caddy's HTTP listener | `3929` |
109+
| `LISTEN_HTTPS_PORT` | Host port mapped to Caddy's HTTPS listener for domain mode | `443` |
109110

110-
### Custom Domain / Reverse Proxy
111+
SurfSense includes Caddy by default. The `frontend`, `backend`, and
112+
`zero-cache` containers are internal-only in the production compose file; the
113+
browser reaches them through Caddy path routing.
111114

112-
Only set these if serving SurfSense on a real domain via a reverse proxy (Caddy, Nginx, Cloudflare Tunnel, etc.). Leave commented out for standard localhost deployments.
115+
### Custom Domain / Automatic HTTPS
116+
117+
For a real domain, point DNS at the Docker host and set:
118+
119+
```dotenv
120+
SURFSENSE_SITE_ADDRESS=surf.example.com
121+
LISTEN_HTTP_PORT=80
122+
LISTEN_HTTPS_PORT=443
123+
CERT_EMAIL=you@example.com
124+
SURFSENSE_PUBLIC_URL=https://surf.example.com
125+
```
126+
127+
Caddy will issue and renew Let's Encrypt certificates automatically. Ports 80
128+
and 443 must be reachable from the internet for the default HTTP-01 challenge.
113129

114130
| Variable | Description |
115131
|----------|-------------|
116-
| `NEXT_FRONTEND_URL` | Public frontend URL (e.g. `https://app.yourdomain.com`) |
117-
| `BACKEND_URL` | Public backend URL for OAuth callbacks (e.g. `https://api.yourdomain.com`) |
118-
| `NEXT_PUBLIC_FASTAPI_BACKEND_URL` | Backend URL used by the frontend (e.g. `https://api.yourdomain.com`) |
119-
| `NEXT_PUBLIC_ZERO_CACHE_URL` | Zero-cache URL used by the frontend (e.g. `https://zero.yourdomain.com`) |
132+
| `CERT_EMAIL` | Optional ACME contact email |
133+
| `CERT_ACME_CA` | ACME directory URL; use Let's Encrypt staging when testing cert issuance |
134+
| `CERT_ACME_DNS` | DNS-01 challenge config; requires the custom Caddy build |
135+
| `TRUSTED_PROXIES` | CIDR ranges trusted for forwarded client IP headers |
136+
| `SURFSENSE_MAX_BODY_SIZE` | Upload limit enforced at the proxy |
137+
138+
### Bring Your Own Proxy
139+
140+
If you already run nginx, Traefik, Cloudflare Tunnel, or another ingress, you
141+
can comment out the `proxy` service and route traffic to the internal services
142+
with the same path contract:
143+
144+
| Public path | Upstream |
145+
|-------------|----------|
146+
| `/auth/*` | `backend:8000` |
147+
| `/api/v1/*` | `backend:8000` |
148+
| `/zero/*` | `zero-cache:4848` |
149+
| `/*` | `frontend:3000` |
150+
151+
Alternative proxies must preserve WebSocket upgrades for `/zero`, avoid
152+
buffering streaming responses, allow long-running requests, and support large
153+
uploads. For DNS-01 or wildcard certificates with Caddy, build
154+
`docker/proxy/Dockerfile` and set `CERT_ACME_DNS` for your DNS provider.
120155

121156
### Zero-cache (Real-Time Sync)
122157

@@ -165,7 +200,10 @@ Create credentials at the [Google Cloud Console](https://console.cloud.google.co
165200

166201
### Connector OAuth Keys
167202

168-
Uncomment the connectors you want to use. Redirect URIs follow the pattern `http://localhost:8000/api/v1/auth/<connector>/connector/callback`.
203+
Uncomment the connectors you want to use. Redirect URIs follow the single-origin
204+
pattern `${SURFSENSE_PUBLIC_URL}/api/v1/auth/<connector>/connector/callback`.
205+
For local Docker defaults, that means
206+
`http://localhost:3929/api/v1/auth/<connector>/connector/callback`.
169207

170208
| Connector | Variables |
171209
|-----------|-----------|
@@ -218,6 +256,7 @@ for full setup.
218256

219257
| Service | Description |
220258
|---------|-------------|
259+
| `proxy` | Caddy reverse proxy; the only public ingress in production Docker |
221260
| `db` | PostgreSQL with pgvector extension |
222261
| `migrations` | Short-lived: runs `alembic upgrade head` and verifies `zero_publication`, then exits |
223262
| `redis` | Message broker for Celery |
@@ -226,7 +265,7 @@ for full setup.
226265
| `celery_worker` | Background task processing (document indexing, etc.) |
227266
| `celery_beat` | Periodic task scheduler (connector sync) |
228267
| `zero-cache` | Rocicorp Zero real-time sync (replicates Postgres to clients) |
229-
| `frontend` | Next.js web application |
268+
| `frontend` | Next.js web application, internal behind Caddy |
230269

231270
All services start automatically with `docker compose up -d`.
232271

@@ -292,9 +331,9 @@ docker compose down -v
292331

293332
## Troubleshooting
294333

295-
- **Ports already in use**: Change the relevant `*_PORT` variable in `.env` and restart.
334+
- **Port already in use**: Change `LISTEN_HTTP_PORT` in `.env` and restart. In domain mode, use ports `80` and `443` so Caddy can complete certificate issuance.
296335
- **Permission errors on Linux**: You may need to prefix `docker` commands with `sudo`.
297-
- **Real-time updates not working**: Open DevTools → Console and check for WebSocket errors. Verify `NEXT_PUBLIC_ZERO_CACHE_URL` matches the running zero-cache address.
336+
- **Real-time updates not working**: Open DevTools → Console and check for WebSocket errors. In production Docker the expected URL is `${SURFSENSE_PUBLIC_URL}/zero`.
298337
- **Line ending issues on Windows**: Run `git config --global core.autocrlf true` before cloning.
299338

300339
### Migration service exited non-zero

surfsense_web/content/docs/docker-installation/install-script.mdx

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,27 @@ If Watchtower is enabled, it preserves the running image variant tag automatical
7474

7575
After starting, access SurfSense at:
7676

77-
- **Frontend**: [http://localhost:3929](http://localhost:3929)
78-
- **Backend API**: [http://localhost:8929](http://localhost:8929)
79-
- **API Docs**: [http://localhost:8929/docs](http://localhost:8929/docs)
80-
- **Zero-cache**: [http://localhost:5929](http://localhost:5929)
77+
- **SurfSense**: [http://localhost:3929](http://localhost:3929)
78+
- **Backend API**: [http://localhost:3929/api/v1](http://localhost:3929/api/v1)
79+
- **Zero sync**: `ws://localhost:3929/zero`
80+
81+
The installer uses the bundled Caddy reverse proxy by default. The backend and
82+
zero-cache containers are not published on separate host ports in the production
83+
stack.
84+
85+
For a custom domain, edit `surfsense/.env` after installation:
86+
87+
```dotenv
88+
SURFSENSE_SITE_ADDRESS=surf.example.com
89+
LISTEN_HTTP_PORT=80
90+
LISTEN_HTTPS_PORT=443
91+
CERT_EMAIL=you@example.com
92+
SURFSENSE_PUBLIC_URL=https://surf.example.com
93+
```
94+
95+
Then run:
96+
97+
```bash
98+
cd surfsense
99+
docker compose up -d --wait
100+
```

surfsense_web/content/docs/how-to/zero-sync.mdx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ zero-cache is included in the Docker Compose setup. The key environment variable
3232

3333
| Variable | Description | Default |
3434
|----------|-------------|---------|
35-
| `ZERO_CACHE_PORT` | Port for the zero-cache service | `5929` (prod) / `4848` (dev) |
35+
| `SURFSENSE_PUBLIC_URL` | Public SurfSense origin used by the browser | `http://localhost:3929` |
3636
| `ZERO_ADMIN_PASSWORD` | Password for the zero-cache admin UI and `/statz` endpoint | `surfsense-zero-admin` |
3737
| `ZERO_UPSTREAM_DB` | PostgreSQL connection URL for replication | Built from `DB_*` vars |
38-
| `NEXT_PUBLIC_ZERO_CACHE_URL` | URL the frontend uses to connect to zero-cache | `http://localhost:<ZERO_CACHE_PORT>` |
38+
| `NEXT_PUBLIC_ZERO_CACHE_URL` | URL the frontend uses to connect to zero-cache | `${SURFSENSE_PUBLIC_URL}/zero` |
3939
| `ZERO_APP_PUBLICATIONS` | PostgreSQL publication restricting which tables are replicated | `zero_publication` |
4040
| `ZERO_NUM_SYNC_WORKERS` | Number of view-sync worker processes. Must be ≤ `ZERO_UPSTREAM_MAX_CONNS` and ≤ `ZERO_CVR_MAX_CONNS` | `4` |
4141
| `ZERO_UPSTREAM_MAX_CONNS` | Max connections to upstream PostgreSQL for mutations | `20` |
@@ -71,7 +71,11 @@ For the full manual setup walkthrough, see the [Manual Installation guide](/docs
7171

7272
### Custom Domain / Reverse Proxy
7373

74-
When deploying behind a reverse proxy, set `NEXT_PUBLIC_ZERO_CACHE_URL` to your public zero-cache URL (e.g., `https://zero.yourdomain.com`). The zero-cache service must be accessible via WebSocket from the browser.
74+
The production Docker stack includes Caddy by default. Zero is exposed under the
75+
same public origin as the app at `${SURFSENSE_PUBLIC_URL}/zero`, for example
76+
`https://surf.example.com/zero`. Zero accepts this single path-component base
77+
URL, so Caddy forwards `/zero/*` to the internal `zero-cache:4848` service
78+
without stripping the prefix.
7579

7680
### Database Requirements
7781

@@ -110,7 +114,7 @@ Zero syncs the following tables for real-time features:
110114

111115
- **zero-cache not starting**: Check `docker compose logs zero-cache`. Ensure PostgreSQL has `wal_level=logical` (configured in `postgresql.conf`).
112116
- **"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`.
113-
- **Frontend not syncing**: Open DevTools → Console and check for WebSocket connection errors. Verify `NEXT_PUBLIC_ZERO_CACHE_URL` matches the running zero-cache address.
117+
- **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`.
114118
- **Stale data after restart**: zero-cache rebuilds its SQLite replica from PostgreSQL on startup. This may take a moment for large databases.
115119

116120
## Learn More

surfsense_web/content/docs/messaging-channels/docker.mdx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,19 @@ wired by Compose.
1515
## Public URLs
1616

1717
For localhost-only testing, the defaults are enough for the SurfSense UI, but
18-
public webhooks from Telegram, WhatsApp, and Slack require a public HTTPS backend
19-
URL. Use your deployed backend URL or a tunnel such as Cloudflare Tunnel or
20-
ngrok.
18+
public webhooks from Telegram, WhatsApp, and Slack require a public HTTPS
19+
SurfSense URL. Use your deployed domain or a tunnel such as Cloudflare Tunnel
20+
or ngrok.
2121

22-
When using a custom domain or tunnel, set:
22+
When using a custom domain or tunnel with the bundled Caddy proxy, set:
2323

2424
```bash
25-
BACKEND_URL=https://api.example.com
26-
GATEWAY_BASE_URL=https://api.example.com
27-
NEXT_FRONTEND_URL=https://app.example.com
28-
NEXT_PUBLIC_FASTAPI_BACKEND_URL=https://api.example.com
25+
SURFSENSE_PUBLIC_URL=https://surf.example.com
26+
SURFSENSE_SITE_ADDRESS=surf.example.com
27+
LISTEN_HTTP_PORT=80
28+
LISTEN_HTTPS_PORT=443
29+
CERT_EMAIL=you@example.com
30+
GATEWAY_BASE_URL=https://surf.example.com
2931
```
3032

3133
## Environment Variables

0 commit comments

Comments
 (0)