Getting Started
Deploy Sofa with Docker in under a minute.
Prerequisites
- Docker and Docker Compose installed
- A free TMDB API Read Access Token — get one here
Quick Start
Create a docker-compose.yml:
services:
sofa:
image: ghcr.io/jakejarvis/sofa:edge
container_name: sofa
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- sofa-data:/data
environment:
- TMDB_API_READ_ACCESS_TOKEN=${TMDB_API_READ_ACCESS_TOKEN}
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
- BETTER_AUTH_URL=${BETTER_AUTH_URL:-http://localhost:3000}
volumes:
sofa-data:Create a .env file next to it with your configuration:
# Get a token at https://www.themoviedb.org/settings/api
TMDB_API_READ_ACCESS_TOKEN=your_token_here
# Random secret for session encryption (min 32 chars)
BETTER_AUTH_SECRET=your_secret_here
# Public URL of your instance
BETTER_AUTH_URL=http://localhost:3000Generate a secure secret:
openssl rand -base64 32Start the container:
docker compose up -dOpen http://localhost:3000 and create your account.
First Account
The first account you create automatically becomes the admin. After that, registration closes by default. You can reopen it in Settings → Admin → Registration.
Reverse Proxy
If you're running Sofa behind a reverse proxy (Caddy, nginx, Traefik, etc.), make sure to:
- Set
BETTER_AUTH_URLto your public URL (e.g.https://sofa.example.com) - Set
CORS_ORIGINto the same URL if your proxy uses a different origin - Forward the
Hostheader and WebSocket connections
Example with Caddy:
sofa.example.com {
reverse_proxy localhost:3000
}Example with nginx:
server {
listen 443 ssl;
server_name sofa.example.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Updating
Pull the latest image and recreate the container:
docker compose pull && docker compose up -dDatabase migrations run automatically on startup — no manual steps needed.
Health Check
Sofa exposes a health endpoint at GET /api/health:
{
"status": "healthy",
"instanceId": "..."
}The Docker image includes a built-in health check that polls this endpoint every 30 seconds.
Data Directory
All persistent data lives in the /data volume:
/data/
├── sqlite.db # SQLite database
├── backups/ # Manual and scheduled backups
├── images/ # Cached TMDB images (if enabled)
└── avatars/ # User profile picturesTo back up your instance, you can either:
- Use Sofa's built-in backup system (Settings → Admin → Backups)
- Copy the Docker volume directly:
docker cp sofa:/data ./sofa-backup