Quick Start
Obscura runs as one Docker image. PostgreSQL 16, ffmpeg, audiowaveform, the SvelteKit web server, and the background worker are all bundled. You provide two volumes — /data for application state and /media for your library — and one port (8008).
Requirements
- Docker 24 or newer (Docker Desktop, Colima, or a Linux Docker engine)
- 2 GB of RAM for the container itself; transcoding spikes can push higher
- Disk for cache and database under
/data— plan for ~5–10% of your library size - A private network. Obscura ships with no authentication; do not expose port 8008 to the public internet.
One-line Docker run
docker run -d \
--name obscura \
-p 8008:8008 \
-v obscura-data:/data \
-v /path/to/your/media:/media \
ghcr.io/pauljoda/obscura:latest
Open http://localhost:8008 and the dashboard loads. (On a fresh install you'll be sent through First Boot instead.)
Docker Compose
The compose form is what most users run long-term — it's easier to update, restart, and pin.
services:
obscura:
image: ghcr.io/pauljoda/obscura:latest
container_name: obscura
ports:
- "8008:8008"
volumes:
- obscura-data:/data
- /path/to/your/media:/media
restart: unless-stopped
volumes:
obscura-data:
docker compose up -d
docker compose logs -f obscura # follow startup
To upgrade later:
docker compose pull && docker compose up -d
Volumes
| Mount | Purpose | Notes |
|---|---|---|
/data | PostgreSQL data, generated cache (HLS, thumbnails, sprites, waveforms), breaking-gate consent markers. | Use a named volume or a host bind mount on a fast disk. |
/media | Your media library. | Read-only is supported; if you want Obscura to upload files to a folder, mount it read-write. |
You can mount multiple library roots. The simplest pattern is to mount each top-level library directly:
volumes:
- obscura-data:/data
- /srv/movies:/media/movies
- /srv/series:/media/series
- /srv/galleries:/media/galleries
Then add /media/movies, /media/series, and /media/galleries as separate library roots in Settings → Watched Libraries. Each root has its own scan-type flags (videos / images / audio) and its own NSFW default.
Read Library Organization before pointing Obscura at a real library. Folder depth determines how files become movies, flat series, or seasoned series — getting the layout right up front saves a lot of cleanup later.
Ports & networking
Only port 8008 is exposed. Obscura serves the web UI and same-origin /api/* routes from a single SvelteKit process; there is no separate API server, no nginx, no Redis.
If you want the app on a different host port:
ports:
- "9000:8008" # host:container
Behind a reverse proxy (Caddy, Traefik, nginx) just point at http://obscura:8008. WebSocket support is not required.
Image tags
| Tag | What it pins | Use it when |
|---|---|---|
latest | The most recent stable release. | Normal installs. |
X.Y.Z (e.g. 0.20.1) | One exact release. | You want to pin a known-good version. |
X.Y (e.g. 0.20) | The latest patch on a minor line. | You want bug fixes but not minor-version churn. |
X (e.g. 0) | The latest minor on a major line. | Long-running deployment with the broadest tracking band. |
dev | The newest commit on main. | You're testing an unreleased change and accept breakage. |
sha-abc1234 | One exact dev build. | Rollback or pinned dev testing. |
The dev tag is rebuilt on every push to main; latest only moves when a release is cut. See Upgrading for the full release/version policy.
What boots inside the container
| Process | Role |
|---|---|
| PostgreSQL 16 | Application data and the pg-boss job queue. Data lives at /data/postgres. |
| SvelteKit server | Web UI plus same-origin /api/*. Port 8008. |
| Worker | Background scan, probe, fingerprint, preview, HLS, and import jobs. |
| ffmpeg / ffprobe | Media probing, HLS transcoding, sprite generation. |
| audiowaveform | Audio waveform peak files. |
| obscura-phash | Stash-compatible video perceptual hashes (Go binary). |
You don't manage these individually — the container runs them under one supervisor and exits as a unit.
Next steps
- Walk through First Boot — the breaking gate (if any), library roots, and your first scan.
- Skim Library Organization so your folders match what Obscura expects.
- Bookmark the Operations page — that's where you watch jobs and re-run scans.