logo

Docker Installation

Setting up AINexLayer using Docker

This guide explains how to run SurfSense using Docker, with options ranging from a single-command install to a fully manual setup.

Quick Start

Downloads the compose files, generates a SECRET_KEY, starts all services, and sets up Watchtower for automatic daily updates.

Windows users: install WSL first and run the command below in the Ubuntu terminal.

curl -fsSL https://raw.githubusercontent.com/MODSetter/SurfSense/main/docker/scripts/install.sh | bash

This creates a ./surfsense/ directory with docker-compose.yml and .env, then runs docker compose up -d.

To skip Watchtower (e.g. in production where you manage updates yourself):

curl -fsSL https://raw.githubusercontent.com/MODSetter/SurfSense/main/docker/scripts/install.sh | bash -s -- --no-watchtower

To customise the check interval (default 24h), use --watchtower-interval=SECONDS.

Option 2 — Manual Docker Compose

git clone https://github.com/MODSetter/SurfSense.git
cd SurfSense/docker
cp .env.example .env
# Edit .env — at minimum set SECRET_KEY
docker compose up -d

After starting, access SurfSense at:


Updating

Option 1 — Watchtower daemon (recommended, auto-updates every 24 h):

If you used the install script (Option 1 above), Watchtower is already running. No extra setup needed.

For manual Docker Compose installs (Option 2), start Watchtower separately:

docker run -d --name watchtower \
  --restart unless-stopped \
  -v /var/run/docker.sock:/var/run/docker.sock \
  nickfedor/watchtower \
  --label-enable \
  --interval 86400

Option 2 — Watchtower one-time update:

docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
  nickfedor/watchtower --run-once \
  --label-filter "com.docker.compose.project=surfsense"

Use nickfedor/watchtower. The original containrrr/watchtower is no longer maintained and may fail with newer Docker versions.

Option 3 — Manual:

cd surfsense   # or SurfSense/docker if you cloned manually
docker compose pull && docker compose up -d

Database migrations are applied automatically on every startup.


Configuration

All configuration lives in a single docker/.env file (or surfsense/.env if you used the install script). Copy .env.example to .env and edit the values you need.

Required

VariableDescription
SECRET_KEYJWT secret key. Generate with: openssl rand -base64 32. Auto-generated by the install script.

Core Settings

VariableDescriptionDefault
SURFSENSE_VERSIONImage tag to deploy. Use latest, a clean version (e.g. 0.0.14), or a specific build (e.g. 0.0.14.1)latest
AUTH_TYPEAuthentication method: LOCAL (email/password) or GOOGLE (OAuth)LOCAL
ETL_SERVICEDocument parsing: DOCLING (local), UNSTRUCTURED, or LLAMACLOUDDOCLING
EMBEDDING_MODELEmbedding model for vector searchsentence-transformers/all-MiniLM-L6-v2
TTS_SERVICEText-to-speech provider for podcastslocal/kokoro
STT_SERVICESpeech-to-text provider for audio fileslocal/base
REGISTRATION_ENABLEDAllow new user registrationsTRUE

Ports

VariableDescriptionDefault
FRONTEND_PORTFrontend service port3000
BACKEND_PORTBackend API service port8000
ELECTRIC_PORTElectric SQL service port5133

Custom Domain / Reverse Proxy

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.

VariableDescription
NEXT_FRONTEND_URLPublic frontend URL (e.g. https://app.yourdomain.com)
BACKEND_URLPublic backend URL for OAuth callbacks (e.g. https://api.yourdomain.com)
NEXT_PUBLIC_FASTAPI_BACKEND_URLBackend URL used by the frontend (e.g. https://api.yourdomain.com)
NEXT_PUBLIC_ELECTRIC_URLElectric SQL URL used by the frontend (e.g. https://electric.yourdomain.com)

Database

Defaults work out of the box. Change for security in production.

VariableDescriptionDefault
DB_USERPostgreSQL usernamesurfsense
DB_PASSWORDPostgreSQL passwordsurfsense
DB_NAMEPostgreSQL database namesurfsense
DB_HOSTPostgreSQL hostdb
DB_PORTPostgreSQL port5432
DB_SSLMODESSL mode: disable, require, verify-ca, verify-fulldisable
DATABASE_URLFull connection URL override. Use for managed databases (RDS, Supabase, etc.)(built from above)

Electric SQL

VariableDescriptionDefault
ELECTRIC_DB_USERReplication user for Electric SQLelectric
ELECTRIC_DB_PASSWORDReplication password for Electric SQLelectric_password
ELECTRIC_DATABASE_URLFull connection URL override for Electric. Set to host.docker.internal when pointing at a local Postgres instance(built from above)

Authentication

VariableDescription
GOOGLE_OAUTH_CLIENT_IDGoogle OAuth client ID (required if AUTH_TYPE=GOOGLE)
GOOGLE_OAUTH_CLIENT_SECRETGoogle OAuth client secret (required if AUTH_TYPE=GOOGLE)

Create credentials at the Google Cloud Console.

External API Keys

VariableDescription
FIRECRAWL_API_KEYFirecrawl API key for web crawling
UNSTRUCTURED_API_KEYUnstructured.io API key (required if ETL_SERVICE=UNSTRUCTURED)
LLAMA_CLOUD_API_KEYLlamaCloud API key (required if ETL_SERVICE=LLAMACLOUD)

Connector OAuth Keys

Uncomment the connectors you want to use. Redirect URIs follow the pattern http://localhost:8000/api/v1/auth/<connector>/connector/callback.

ConnectorVariables
Google Drive / Gmail / CalendarGOOGLE_DRIVE_REDIRECT_URI, GOOGLE_GMAIL_REDIRECT_URI, GOOGLE_CALENDAR_REDIRECT_URI
NotionNOTION_CLIENT_ID, NOTION_CLIENT_SECRET, NOTION_REDIRECT_URI
SlackSLACK_CLIENT_ID, SLACK_CLIENT_SECRET, SLACK_REDIRECT_URI
DiscordDISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET, DISCORD_BOT_TOKEN, DISCORD_REDIRECT_URI
Jira & ConfluenceATLASSIAN_CLIENT_ID, ATLASSIAN_CLIENT_SECRET, JIRA_REDIRECT_URI, CONFLUENCE_REDIRECT_URI
LinearLINEAR_CLIENT_ID, LINEAR_CLIENT_SECRET, LINEAR_REDIRECT_URI
ClickUpCLICKUP_CLIENT_ID, CLICKUP_CLIENT_SECRET, CLICKUP_REDIRECT_URI
AirtableAIRTABLE_CLIENT_ID, AIRTABLE_CLIENT_SECRET, AIRTABLE_REDIRECT_URI
Microsoft TeamsTEAMS_CLIENT_ID, TEAMS_CLIENT_SECRET, TEAMS_REDIRECT_URI

For Airtable, create an OAuth integration at the Airtable Developer Hub.

Observability (optional)

VariableDescription
LANGSMITH_TRACINGEnable LangSmith tracing (true / false)
LANGSMITH_ENDPOINTLangSmith API endpoint
LANGSMITH_API_KEYLangSmith API key
LANGSMITH_PROJECTLangSmith project name

Advanced (optional)

VariableDescriptionDefault
SCHEDULE_CHECKER_INTERVALHow often to check for scheduled connector tasks (e.g. 5m, 1h)5m
RERANKERS_ENABLEDEnable document reranking for improved searchFALSE
RERANKERS_MODEL_NAMEReranker model name (e.g. ms-marco-MiniLM-L-12-v2)
RERANKERS_MODEL_TYPEReranker model type (e.g. flashrank)
PAGES_LIMITMax pages per user for ETL servicesunlimited

Docker Services

ServiceDescription
dbPostgreSQL with pgvector extension
redisMessage broker for Celery
backendFastAPI application server
celery_workerBackground task processing (document indexing, etc.)
celery_beatPeriodic task scheduler (connector sync)
electricElectric SQL — real-time sync for the frontend
frontendNext.js web application

All services start automatically with docker compose up -d.

The backend includes a health check — dependent services (workers, frontend) wait until the API is fully ready before starting. You can monitor startup progress with docker compose ps (look for (health: starting)(healthy)).


Development Compose File

If you're contributing to SurfSense and want to build from source, use docker-compose.dev.yml instead:

cd SurfSense/docker
docker compose -f docker-compose.dev.yml up --build

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. Use the production docker-compose.yml for all other cases.

The following .env variables are only used by the dev compose file (they have no effect on the production docker-compose.yml):

VariableDescriptionDefault
PGADMIN_PORTpgAdmin web UI port5050
PGADMIN_DEFAULT_EMAILpgAdmin login emailadmin@surfsense.com
PGADMIN_DEFAULT_PASSWORDpgAdmin login passwordsurfsense
REDIS_PORTExposed Redis port (internal-only in prod)6379
NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPEFrontend build arg for auth typeLOCAL
NEXT_PUBLIC_ETL_SERVICEFrontend build arg for ETL serviceDOCLING
NEXT_PUBLIC_DEPLOYMENT_MODEFrontend build arg for deployment modeself-hosted
NEXT_PUBLIC_ELECTRIC_AUTH_MODEFrontend build arg for Electric authinsecure

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.


Migrating from the All-in-One Container

If you were previously using docker-compose.quickstart.yml (the legacy all-in-one surfsense container), your data lives in a surfsense-data volume and requires a one-time migration before switching to the current setup. PostgreSQL has been upgraded from version 14 to 17, so a simple volume swap will not work.

See the full step-by-step guide: Migrate from the All-in-One Container.


Useful Commands

# View logs (all services)
docker compose logs -f

# View logs for a specific service
docker compose logs -f backend
docker compose logs -f electric

# Stop all services
docker compose down

# Restart a specific service
docker compose restart backend

# Stop and remove all containers + volumes (destructive!)
docker compose down -v

Troubleshooting

  • Ports already in use — Change the relevant *_PORT variable in .env and restart.
  • Permission errors on Linux — You may need to prefix docker commands with sudo.
  • Electric SQL not connecting — Check docker compose logs electric. If it shows domain does not exist: db, ensure ELECTRIC_DATABASE_URL is not set to a stale value in .env.
  • Real-time updates not working in browser — Open DevTools → Console and look for [Electric] errors. Check that NEXT_PUBLIC_ELECTRIC_URL matches the running Electric SQL address.
  • Line ending issues on Windows — Run git config --global core.autocrlf true before cloning.

On this page