Skip to content

Docker Installation

The recommended way to run OmniLux. This guide covers every service, volume, environment variable, and optional sidecar.

Who this is for

Use this guide if you want the default self-hosted path with the least friction. If you only need a server running quickly, start with Self-Hosted Quick Start and come back here when you want to tune the deployment.

What this guide covers

  • The main OmniLux container
  • Storage and permission mapping
  • GPU passthrough for transcoding
  • Networking and update-safe storage patterns

Prerequisites

  • Docker 24+ with Docker Compose v2
  • 2 GB RAM minimum (4 GB+ recommended for transcoding)
  • Storage for your media library and application data

Core service

The main OmniLux container runs the backend API, web frontend, and all background workers.

yaml
services:
  omnilux:
    build:
      context: .
      dockerfile: Dockerfile.server
    image: omnilux:latest
    container_name: omnilux
    restart: unless-stopped
    ports:
      - "4000:4000"          # Web UI + API
      - "1900:1900/udp"      # DLNA/SSDP discovery
    environment:
      NODE_ENV: production
      PORT: 4000
      OMNILUX_LIBRARY_ROOT: /data
      OMNILUX_DB_PATH: /app/data/omnilux.db
      OMNILUX_DOWNLOAD_PATH: /app/data/downloads
      TMDB_API_KEY: ${TMDB_API_KEY:-}
    volumes:
      - /path/to/omnilux/data:/app/data
      - /path/to/media:/data
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:4000/api/health"]
      interval: 30s
      timeout: 5s
      start_period: 10s
      retries: 3

Ports

PortProtocolPurpose
4000TCPWeb UI and REST API
1900UDPDLNA/SSDP device discovery

Volumes

Container pathPurpose
/app/dataSQLite database, downloads, logs, config
/dataMedia library root (movies, TV, music, etc.)

Minimum viable setup

If you want the smallest possible starting point, focus on these three edits before first boot:

  1. Change /path/to/omnilux/data to a persistent host directory.
  2. Change /path/to/media to the root of your mounted media library.
  3. Keep the first boot simple and add GPU settings later only if you need transcoding help.

Permissions

The container runs as UID 1000 by default. Make sure your host directories are readable and writable by UID 1000, or set user: "your-uid:your-gid" in the compose file.

GPU passthrough for hardware transcoding

NVIDIA

Install the NVIDIA Container Toolkit, then add to your compose service:

yaml
omnilux:
  runtime: nvidia
  environment:
    NVIDIA_VISIBLE_DEVICES: all
    NVIDIA_DRIVER_CAPABILITIES: compute,video,utility
  deploy:
    resources:
      reservations:
        devices:
          - driver: nvidia
            count: all
            capabilities: [gpu, video, compute]

OmniLux will automatically detect NVENC and use hardware-accelerated transcoding for live TV and on-the-fly streaming. An RTX 3060 supports up to 8 simultaneous NVENC encode sessions.

Intel Quick Sync (VA-API)

yaml
omnilux:
  devices:
    - /dev/dri:/dev/dri

AMD (VA-API)

yaml
omnilux:
  devices:
    - /dev/dri:/dev/dri
  environment:
    LIBVA_DRIVER_NAME: radeonsi

Networking

Bridge mode (default)

Uses Docker's default bridge network. Ports are mapped with -p and the server stays isolated from the host except for the ports you publish.

Host mode

For DLNA discovery and HDHomeRun emulation, host networking works better:

yaml
omnilux:
  network_mode: host

With host networking, remove the ports section — all ports bind directly to the host.

For most operators, the cleanest production setup is:

  1. Run OmniLux in bridge mode.
  2. Mount persistent bind paths for /app/data and /data.
  3. Put HTTPS and your public hostname in front of it with Reverse Proxy.
  4. Add GPU passthrough only after the base install is stable.

Storage

Bind mounts vs named volumes

Bind mounts (recommended) — map host directories directly. Easier to back up and inspect:

yaml
volumes:
  - /srv/omnilux/data:/app/data
  - /srv/media:/data

Named volumes — managed by Docker. Data lives in /var/lib/docker/volumes/:

yaml
volumes:
  - omnilux-data:/app/data
  - media:/data

volumes:
  omnilux-data:
  media:
    driver: local
    driver_opts:
      type: none
      device: /srv/media
      o: bind

Multiple media directories

Mount additional media paths under /data:

yaml
volumes:
  - /mnt/movies:/data/movies
  - /mnt/tv:/data/tv
  - /mnt/music:/data/music
  - /mnt/games:/data/games

Then add each as a separate library root in the OmniLux UI.

Logging

yaml
logging:
  driver: json-file
  options:
    max-size: "50m"
    max-file: "5"

Application logs are also written inside the data volume at /app/data/logs/.

Full example

See the complete docker-compose.example.yml mirrored on the docs site.