docs(docker): document single-origin proxy deployment

This commit is contained in:
Anish Sarkar 2026-06-15 11:04:31 +05:30
parent 2c6cf8d795
commit 6d9540a1e8
5 changed files with 106 additions and 34 deletions

View file

@ -15,9 +15,9 @@ docker compose up -d
After starting, access SurfSense at:
- **Frontend**: [http://localhost:3929](http://localhost:3929)
- **Backend API**: [http://localhost:8929](http://localhost:8929)
- **API Docs**: [http://localhost:8929/docs](http://localhost:8929/docs)
- **SurfSense**: [http://localhost:3929](http://localhost:3929)
- **Backend API**: [http://localhost:3929/api/v1](http://localhost:3929/api/v1)
- **Zero sync**: `ws://localhost:3929/zero`
---
## Configuration
@ -99,24 +99,59 @@ docker run -d --name watchtower \
SurfSense containers are labeled for Watchtower, so `--label-enable` limits updates to the SurfSense services.
### Ports
### Public URL and Ports
| Variable | Description | Default |
|----------|-------------|---------|
| `FRONTEND_PORT` | Frontend service port | `3929` |
| `BACKEND_PORT` | Backend API service port | `8929` |
| `ZERO_CACHE_PORT` | Zero-cache real-time sync port | `5929` |
| `SURFSENSE_PUBLIC_URL` | Public origin used by the frontend, backend OAuth callbacks, and Zero browser URL | `http://localhost:3929` |
| `SURFSENSE_SITE_ADDRESS` | Caddy site address. `:80` means local plain HTTP; a hostname enables automatic HTTPS | `:80` |
| `LISTEN_HTTP_PORT` | Host port mapped to Caddy's HTTP listener | `3929` |
| `LISTEN_HTTPS_PORT` | Host port mapped to Caddy's HTTPS listener for domain mode | `443` |
### Custom Domain / Reverse Proxy
SurfSense includes Caddy by default. The `frontend`, `backend`, and
`zero-cache` containers are internal-only in the production compose file; the
browser reaches them through Caddy path routing.
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.
### Custom Domain / Automatic HTTPS
For a real domain, point DNS at the Docker host and set:
```dotenv
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
```
Caddy will issue and renew Let's Encrypt certificates automatically. Ports 80
and 443 must be reachable from the internet for the default HTTP-01 challenge.
| Variable | Description |
|----------|-------------|
| `NEXT_FRONTEND_URL` | Public frontend URL (e.g. `https://app.yourdomain.com`) |
| `BACKEND_URL` | Public backend URL for OAuth callbacks (e.g. `https://api.yourdomain.com`) |
| `NEXT_PUBLIC_FASTAPI_BACKEND_URL` | Backend URL used by the frontend (e.g. `https://api.yourdomain.com`) |
| `NEXT_PUBLIC_ZERO_CACHE_URL` | Zero-cache URL used by the frontend (e.g. `https://zero.yourdomain.com`) |
| `CERT_EMAIL` | Optional ACME contact email |
| `CERT_ACME_CA` | ACME directory URL; use Let's Encrypt staging when testing cert issuance |
| `CERT_ACME_DNS` | DNS-01 challenge config; requires the custom Caddy build |
| `TRUSTED_PROXIES` | CIDR ranges trusted for forwarded client IP headers |
| `SURFSENSE_MAX_BODY_SIZE` | Upload limit enforced at the proxy |
### Bring Your Own Proxy
If you already run nginx, Traefik, Cloudflare Tunnel, or another ingress, you
can comment out the `proxy` service and route traffic to the internal services
with the same path contract:
| Public path | Upstream |
|-------------|----------|
| `/auth/*` | `backend:8000` |
| `/api/v1/*` | `backend:8000` |
| `/zero/*` | `zero-cache:4848` |
| `/*` | `frontend:3000` |
Alternative proxies must preserve WebSocket upgrades for `/zero`, avoid
buffering streaming responses, allow long-running requests, and support large
uploads. For DNS-01 or wildcard certificates with Caddy, build
`docker/proxy/Dockerfile` and set `CERT_ACME_DNS` for your DNS provider.
### Zero-cache (Real-Time Sync)
@ -165,7 +200,10 @@ Create credentials at the [Google Cloud Console](https://console.cloud.google.co
### Connector OAuth Keys
Uncomment the connectors you want to use. Redirect URIs follow the pattern `http://localhost:8000/api/v1/auth/<connector>/connector/callback`.
Uncomment the connectors you want to use. Redirect URIs follow the single-origin
pattern `${SURFSENSE_PUBLIC_URL}/api/v1/auth/<connector>/connector/callback`.
For local Docker defaults, that means
`http://localhost:3929/api/v1/auth/<connector>/connector/callback`.
| Connector | Variables |
|-----------|-----------|
@ -218,6 +256,7 @@ for full setup.
| Service | Description |
|---------|-------------|
| `proxy` | Caddy reverse proxy; the only public ingress in production Docker |
| `db` | PostgreSQL with pgvector extension |
| `migrations` | Short-lived: runs `alembic upgrade head` and verifies `zero_publication`, then exits |
| `redis` | Message broker for Celery |
@ -226,7 +265,7 @@ for full setup.
| `celery_worker` | Background task processing (document indexing, etc.) |
| `celery_beat` | Periodic task scheduler (connector sync) |
| `zero-cache` | Rocicorp Zero real-time sync (replicates Postgres to clients) |
| `frontend` | Next.js web application |
| `frontend` | Next.js web application, internal behind Caddy |
All services start automatically with `docker compose up -d`.
@ -292,9 +331,9 @@ docker compose down -v
## Troubleshooting
- **Ports already in use**: Change the relevant `*_PORT` variable in `.env` and restart.
- **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.
- **Permission errors on Linux**: You may need to prefix `docker` commands with `sudo`.
- **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.
- **Real-time updates not working**: Open DevTools → Console and check for WebSocket errors. In production Docker the expected URL is `${SURFSENSE_PUBLIC_URL}/zero`.
- **Line ending issues on Windows**: Run `git config --global core.autocrlf true` before cloning.
### Migration service exited non-zero