Up and running in five minutes
Vora is one image bundling the API and the web client. It needs PostgreSQL with thevector extension, a volume for its data, and your media mounted read-only. Schema migrations apply themselves on startup.
docker compose
The fastest path. Save this as docker-compose.yml, change the two passwords and the JWT secret, adjust the media paths, then run docker compose up -d.
services:
postgres:
image: pgvector/pgvector:pg16
container_name: vora-postgres
restart: unless-stopped
environment:
POSTGRES_DB: vora
POSTGRES_USER: vora
POSTGRES_PASSWORD: change-me-to-a-strong-password
volumes:
- /srv/vora/postgres-data:/var/lib/postgresql/data
vora:
image: ghcr.io/axufuris/vora-media-server:latest
container_name: vora
restart: unless-stopped
depends_on:
- postgres
ports:
- "8080:8080"
environment:
PUID: 99
PGID: 100
ASPNETCORE_HTTP_PORTS: 8080
ConnectionStrings__DefaultConnection: "Host=postgres;Port=5432;Database=vora;Username=vora;Password=change-me-to-a-strong-password"
Jwt__SecretKey: "REPLACE_WITH_A_LONG_RANDOM_STRING"
StoragePaths__CustomArtwork: /app/data/custom_artwork
StoragePaths__OriginalArtworkCache: /app/data/original_artwork_cache
StoragePaths__EpgCache: /app/data/iptv/epg_cache
StoragePaths__IptvDvr: /app/data/iptv/dvr
StoragePaths__UserImages: /app/data/users
StoragePaths__Plugins: /app/data/plugins
StoragePaths__Subtitles: /app/data/subtitles
volumes:
- /srv/vora/data:/app/data
- /srv/vora/transcode:/transcode
- /mnt/media/movies:/media/movies:ro
- /mnt/media/shows:/media/shows:ro
- /mnt/media/music:/media/music:roGenerate a JWT secret
Any long random string works. Keep it somewhere safe — changing it later invalidates every session.
openssl rand -base64 64
Bring the stack up
Vora waits for Postgres, applies its migrations, and starts serving.
docker compose up -d docker compose logs -f vora
Create the first profile
Open http://your-host:8080. The first profile you create through the setup flow becomes the server admin. Add your libraries from the admin area and let the first scan run.
Which tag to pull
Images are published to GitHub Container Registry for linux/amd64.
| Tag | What it is |
|---|---|
latest | The newest stable release. Recommended. |
1.4, 1.4.2 | Pin a specific release or minor line. |
qa | Pre-release builds from the main branch. Expect breakage. |
The environment variables that matter
| Variable | Purpose |
|---|---|
ConnectionStrings__DefaultConnection | Npgsql connection string. Use the Postgres container name as the host when both sit on one Docker network. |
Jwt__SecretKey | Long random string signing account and profile tokens. Generate once and keep it stable — rotating it signs everyone out. |
PUID / PGID | User and group the container runs as. Data and transcode mounts are chowned to match on startup, so no host-side chown is needed. Defaults are 99 / 100. |
StoragePaths__* | Where artwork, the EPG cache, DVR recordings, user images, plugins, and subtitles live inside the container. Keep them under one mounted volume. |
ASPNETCORE_HTTP_PORTS | Listening port inside the container. 8080 unless you have a reason. |
Seed plugin API keys from compose
Plugin settings can be supplied as environment variables. They are written only when the database row is still empty, so anything you later change in the admin UI wins.
The pattern is Vora__PluginSettings__<pluginId>__<settingKey>. Unknown plugins and unknown keys are skipped with a warning, and values are redacted from the logs.
Vora__PluginSettings__tmdb_metadata__api_key: "YOUR_TMDB_KEY" Vora__PluginSettings__tvdb_metadata__api_key: "YOUR_TVDB_KEY" Vora__PluginSettings__fanart_artwork__api_key: "YOUR_FANART_KEY" Vora__PluginSettings__lastfm_listening__api_key: "YOUR_LASTFM_KEY" Vora__PluginSettings__opensubtitles_search__api_key: "YOUR_OPENSUBS_KEY" Vora__PluginSettings__openai_recommendations__is_enabled: "true"
NVIDIA GPU transcoding
Install the NVIDIA Container Toolkit on the host and reserve a GPU. The image already carries the driver capabilities it needs, so CUDA decode, NVENC encode, and HDR-to-SDR tone mapping work without further configuration.
Do not narrow NVIDIA_DRIVER_CAPABILITIES — dropping libcuda.so.1 is the usual cause of a transcode failing to start.
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu, video]Community Applications
Add both containers from a manual template with the Network Type set to the same custom bridge, so Vora can resolve Postgres by container name.
- Leave Postgres unmapped — keeping the database off the LAN is safer, and Vora reaches it over the internal network.
- PUID 99 / PGID 100 — Unraid's
nobody:users, which already own everything under/mnt/user. - Media read-only — set each library path to Access Mode Read Only.
- For GPU transcoding — install the Nvidia-Driver plugin and set Extra Parameters to
--runtime=nvidia. Nothing else is required.
Upgrading
Pull the new image and restart. Vora detects pending migrations and applies them before it serves traffic; your data volume and the Postgres directory persist. If a migration fails the container exits rather than serving a half-migrated schema.
docker compose pull vora docker compose up -d vora
Something not working?
The README covers every storage path, plugin setting, and deployment quirk in detail. Bugs and questions are welcome on the issue tracker.