How to Deploy Dispatcharr with Docker Compose: IPTV and Live TV Stream Management

Dispatcharr is an open-source stream management hub and proxy relay that unifies multiple IPTV playlists, XMLTV guides, and stream profiles with HDHomeRun emulation. Here is how to deploy Dispatcharr v0.33 using Docker Compose, complete the first-run superuser setup, and configure stream relays.

How to Deploy Dispatcharr with Docker Compose: IPTV and Live TV Stream Management

Dispatcharr is an open-source (AGPL-3.0) stream management hub, proxy relay, and DVR companion designed as the "*arr" ecosystem's counterpart for live television and IPTV. While tools like Radarr, Sonarr, and Lidarr organize on-demand movie, TV, and music downloads, live streaming has historically suffered from brittle M3U playlists, mismatched Electronic Program Guides (EPG), and strict provider connection limits. Dispatcharr bridges this gap by centralizing multiple IPTV sources, standardizing guide data, and exposing unified endpoints and virtual HDHomeRun tuners to media servers like Plex, Jellyfin, and Emby.

Instead of exposing fragile provider URLs directly to consumer playback clients—which frequently leads to exceeded simultaneous connection caps and account bans—Dispatcharr acts as an intelligent intermediary. It manages channel lineups, synchronizes XMLTV and Schedules Direct metadata, handles stream routing through configurable profiles, and offers automated DVR series recording rules.

Dispatcharr's core architecture delivers several key streaming capabilities:

  • Unified Tuner Emulation (HDHomeRun): Emulates SiliconDust HDHomeRun (HDHR) network tuners alongside standardized M3U playlist and XMLTV guide URLs, enabling seamless live TV integration with Plex Live TV & DVR, Jellyfin, and Emby.
  • Flexible Stream Relay Profiles: Routes incoming streams through five distinct engine profiles: direct Proxy (passthrough with chunk buffering), HTTP Redirect (direct client-to-source handover for zero server bandwidth), FFmpeg (live transcoding, container repackaging, and audio normalization), Streamlink (handling complex web feeds), or VLC (alternative transcode and demux engine).
  • Provider Connection Guardrails: Enforces per-provider maximum stream limits (Max Streams) to guarantee that simultaneous client streams never exceed your IPTV subscription allowance.
  • Automated M3U & EPG Synchronization: Regularly refreshes remote M3U and Xtream Codes accounts on a configurable schedule, scans for Video-on-Demand (VOD) assets, and aligns guide data with channel lineups.
  • Modern React 19 Web Interface: Provides an interactive Single Page Application (SPA) built with React 19 and Mantine v8, featuring a two-pane channel and stream editor, an interactive timeline TV guide, real-time connection stats, and downloaded log auditing.
  • All-in-One Container Architecture: Packages Nginx, uWSGI (Django backend), Daphne (ASGI WebSockets), Celery task workers, Celery Beat scheduler, Redis cache/broker, PostgreSQL 16, FFmpeg, and Comskip into a single zero-dependency Docker image (ghcr.io/dispatcharr/dispatcharr:latest).

This guide walks through deploying Dispatcharr v0.33 using Docker Compose with persistent data volumes, creating the initial administrator account, navigating the web interface, and configuring stream relays.

Dispatcharr Channels Dashboard showing live channels and stream relays overview

Prerequisites

Before deploying Dispatcharr, verify that your host system satisfies the following requirements:

  • Docker Engine & Docker Compose: Docker Engine 20.10+ and Docker Compose v2.24+ installed on your host system (docker compose version).
  • Operating System & Architecture: Linux x86_64 or arm64 with network egress to pull container images from GitHub Container Registry (ghcr.io).
  • Host Port Availability: Dispatcharr's internal Nginx web server listens on port 9191. In this guide, host port 3000 (or 9191) is forwarded to container port 9191. Ensure the selected host port is free:

``sh ss -ltn | grep -E ':(3000|9191)\b' ``

  • User Permissions (PUID/PGID): Identify your non-root host user and group IDs (typically 1000:1000 via id -u and id -g) so container operations and PostgreSQL write with proper permissions.
  • Persistent Storage: Sufficient storage for Dispatcharr's runtime state (/data), which houses the PostgreSQL database (/data/db), application logs (/data/logs), JWT secrets (/data/jwt), recordings, and cache.
  • Web Browser: Any modern web browser (Chrome, Firefox, Safari, or Edge) to access the web UI.

Exact Install Steps

Follow these steps to deploy Dispatcharr using Docker Compose with persistent volume storage.

1. Create Deployment Directory Structure

Create a dedicated directory for your compose configuration and persistent data:

mkdir -p dispatcharr/data
cd dispatcharr
  • dispatcharr/: Contains deployment configuration manifests (.env, docker-compose.yml).
  • dispatcharr/data/: Persistent mount directory for PostgreSQL database files, logs, and authentication keys.

2. Configure Environment Variables (.env)

Create a .env file in the deployment directory to define project parameters:

cat > .env <<'EOF'
COMPOSE_PROJECT_NAME=dispatcharr
IMAGE=ghcr.io/dispatcharr/dispatcharr:latest
DISPATCHARR_PORT=3000
PUID=1000
PGID=1000
TZ=Etc/UTC
EOF
  • COMPOSE_PROJECT_NAME: Defines the Docker Compose project namespace and container name prefix.
  • IMAGE: Specifies the official All-in-One image from GitHub Container Registry (ghcr.io/dispatcharr/dispatcharr:latest).
  • DISPATCHARR_PORT: Specifies the host port mapping to Dispatcharr's web interface (maps to internal port 9191).
  • PUID and PGID: Match container process execution to your host user account to prevent file permission mismatches.
  • TZ: Configures the container timezone.

3. Create Docker Compose File (docker-compose.yml)

Create the docker-compose.yml manifest:

services:
  dispatcharr:
    image: ${IMAGE}
    container_name: ${COMPOSE_PROJECT_NAME}-dispatcharr
    restart: unless-stopped
    ports:
      - "127.0.0.1:${DISPATCHARR_PORT}:9191"
    volumes:
      - "./data:/data"
    environment:
      - DISPATCHARR_ENV=aio
      - REDIS_HOST=localhost
      - CELERY_BROKER_URL=redis://localhost:6379/0
      - DISPATCHARR_LOG_LEVEL=info
      - DISPATCHARR_PORT=9191
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    healthcheck:
      test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:9191/api/core/version/ || exit 1"]
      interval: 5s
      timeout: 3s
      retries: 20
      start_period: 15s

Key configuration parameters:

  • DISPATCHARR_ENV=aio: Boots the container in All-in-One mode, automatically launching PostgreSQL, Redis, Celery, Daphne, uWSGI, and Nginx in a unified environment.
  • ports: Binds host port 3000 (127.0.0.1:3000) to internal container port 9191.
  • volumes: Maps local ./data to /data in the container.
  • healthcheck: Queries the unauthenticated internal /api/core/version/ endpoint to confirm service readiness.

4. Pull and Start the Container

Pull the container image and start the service in detached mode:

docker compose pull --quiet
docker compose up -d

5. Wait for Application Readiness

The container entrypoint initializes the internal PostgreSQL database, runs Django database migrations, generates internal JWT signing keys, and launches background workers. Poll the version endpoint until the service responds:

echo "Waiting for Dispatcharr to become ready..."
until curl -fsS http://localhost:3000/api/core/version/ >/dev/null 2>&1; do
  sleep 3
done
echo "Dispatcharr is ready!"

Once the loop prints Dispatcharr is ready!, the web UI and REST API are fully initialized.

Browser Setup

Once the container is healthy, launch your web browser and navigate to:

http://localhost:3000/

*(If you set DISPATCHARR_PORT=9191, visit http://localhost:9191/).*

Step 1: Create the Initial Superuser Account

Dispatcharr implements strict first-run onboarding security: there are no default passwords or unauthenticated administrator backdoors. When visiting a clean installation, Dispatcharr checks /api/accounts/initialize-superuser/. Detecting that no superuser exists (superuser_exists: false), it presents the Super User Account creation card.

Dispatcharr initial setup screen prompting for superuser account creation

Populate the administrator credentials:

  1. Username: Enter an administrative username (e.g., admin).
  2. Password: Enter a strong password (e.g., Dispatcharr2026!).
  3. Email (optional): Enter an administrative email address (e.g., admin@dispatcharr.local).

Superuser setup form filled with administrator credentials

Click the blue Create Account button. Dispatcharr provisions the administrator record in the PostgreSQL database and immediately transitions to the standard login card.

Dispatcharr login screen following superuser creation

Step 2: Authenticate as Administrator

On the login screen, enter your newly created credentials:

  1. Username: admin
  2. Password: Dispatcharr2026!

Dispatcharr login form populated with admin credentials

Click Login. The frontend authenticates via POST /api/accounts/auth/login/, stores JWT access and refresh tokens, and redirects to the default Channels view.

Step 3: Explore Channels and Client Endpoints

The primary Channels view (/channels) features a responsive two-pane layout:

  • Left Pane: Channels table displaying configured channel numbers, logos, channel names, and linked stream counts.
  • Right Pane: Streams table displaying the individual stream sources associated with the selected channel.
  • Top Bar Client Links: Includes quick-copy endpoint chips for HDHR, M3U, and EPG. These links provide the tuner emulation and playlist feeds that you supply to downstream media players (Plex, Jellyfin, Emby, or Kodi).

Dispatcharr Channels dashboard showing channel and stream split-pane layout

Step 4: Add an IPTV Provider (M3U & EPG Manager)

To add your IPTV playlists or Xtream Codes accounts:

  1. Click M3U & EPG Manager (/sources) in the left sidebar.
  2. The page displays two sections: M3U Playlists and XMLTV / EPG Guides.

M3U and EPG Manager displaying empty playlists and guide sources tables

  1. Click the green + Add M3U button.
  2. The M3U Account modal opens with a three-column layout:

- Column 1 (Account Information): Specify the Account Name, Server URL, Account Type (defaults to *Xtream Codes*, or select *M3U Playlist*), Username, and Password. - Column 2 (Stream Limits & Routing): Set Max Streams (crucial: configure this to match your IPTV provider's simultaneous stream cap to avoid IP bans), assign a Server Group, set a custom User-Agent, and enter an optional Hash Key. - Column 3 (Sync & Automation): Configure the Refresh Interval (defaults to 24 hours), enable or disable VOD Scanning, set VOD Priority, and toggle automatic Create EPG.

Add M3U Account modal showing three-column configuration layout

  1. Click Save to begin importing channels and streams, or press Esc to return to the manager.

Step 5: Review the TV Guide & DVR Rules

Click TV Guide (/guide) in the left sidebar to open the Electronic Program Guide:

  • The interactive timeline grid organizes channels by channel number, displaying current programming, upcoming airings, and a red indicator line representing current playback time.
  • Click the Series Rules button in the upper right to define recurring recording rules for the built-in DVR scheduler.

TV Guide timeline grid showing channel numbers and interactive schedule

Step 6: Monitor Live Connections & Stats

Click Stats (/stats) in the left navigation menu:

  • The dashboard displays an active summary banner: *"Active Connections — 0 streams • 0 VOD connections • 0 catch-up sessions"*.
  • Real-time connection metrics refresh automatically every 5 seconds.
  • The collapsible System Events panel logs internal dispatch and worker events.

Stats dashboard showing active stream connections and system events panel

Step 7: Configure Stream Profiles

Navigate to Settings (/settings) in the sidebar, then select Stream Profiles: Dispatcharr provides five pre-configured stream processing profiles:

  1. Proxy: Relays raw provider stream chunks directly through Dispatcharr to the client without transcoding. Low CPU usage.
  2. Redirect: Returns an HTTP 302 redirect sending the playback client directly to the provider stream URL. Uses zero server bandwidth.
  3. FFmpeg: Passes streams through the bundled FFmpeg binary for on-the-fly video transcoding, audio normalization, and container repackaging (e.g., MPEG-TS to fMP4).
  4. Streamlink: Uses Streamlink to extract and relay live streams from dynamic or protected streaming endpoints.
  5. VLC: Uses libVLC as an alternate demuxing and transcoding engine.

Settings Stream Profiles view listing FFmpeg, Proxy, Redirect, Streamlink, and VLC profiles

Step 8: Inspect System Logs

Navigate to System › Logs (/logs):

  • Dispatcharr provides a centralized log view listing runtime log files (such as dispatcharr.log).
  • Click the Download link beside any log file to retrieve full diagnostic traces from the uWSGI, Daphne, Celery, and Nginx processes.

System Logs page displaying dispatcharr.log file and download link

Verification

Run these verification checks against your running Dispatcharr instance to confirm that all services are operational:

1. Application Version Endpoint

Query Dispatcharr's unauthenticated core version API:

curl -fsS http://localhost:3000/api/core/version/

Expected output:

{"version":"0.33.0","timestamp":null}

2. Superuser Status Gate

Check the superuser status endpoint to confirm that initial administrative onboarding succeeded:

curl -fsS http://localhost:3000/api/accounts/initialize-superuser/

Expected output:

{"superuser_exists": true, "client_ip": "172.21.0.1", "setup_allowed": true}

3. Application Web Shell

Verify that the React SPA HTML shell loads with the expected title:

curl -fsS http://localhost:3000/ | grep -o '<title>[^<]*</title>'

Expected output:

<title>Dispatcharr</title>

4. Container Health Status

Check the health status reported by Docker Engine:

docker compose ps

The container status should display Up (healthy).

5. API Authentication Token Verification

Test administrator authentication by requesting a JWT token pair:

curl -fsS -X POST http://localhost:3000/api/accounts/token/ \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"Dispatcharr2026!"}'

Expected output:

{"refresh":"<jwt-refresh-token>","access":"<jwt-access-token>"}

Troubleshooting

Symptom / ErrorRoot CauseResolution
Initial setup blocked: setup_allowed: false or HTTP 403 ForbiddenDispatcharr restricts initial superuser creation to private local IP ranges (RFC1918) and localhost (127.0.0.1). If accessing through an external reverse proxy, client IP detection fails.Access the setup page directly via http://localhost:3000/ or ensure your reverse proxy (Nginx, Traefik, Caddy) forwards the client IP header using proxy_set_header X-Forwarded-For $remote_addr;.
Container fails to start or exits with port allocation errorHost port 3000 (or 9191) is already in use by another service on your system.Run ss -ltn to identify the conflicting process. Change DISPATCHARR_PORT in .env to an unused port (such as 3002 or 19191) and run docker compose up -d.
Container health check remains starting or times out after 90 secondsOn slower disks or initial container creation, PostgreSQL database initialization and Django migrations require extra time before Nginx and uWSGI open the HTTP port.Monitor progress with docker compose logs -f dispatcharr. Wait for the entrypoint to log database initialization completion. In automated scripts, increase the readiness check timeout to 240 seconds.
Permission denied errors writing to /data (/data/db or /data/logs)The PUID or PGID values in .env do not match the ownership of the host ./data directory.Run id -u and id -g on your host. Update PUID and PGID in .env to match, run chown -R $(id -u):$(id -g) ./data, and restart the container with docker compose up -d.
IPTV streams terminate abruptly or provider account is temporarily bannedThe number of simultaneous streams requested by media clients exceeds your provider subscription allowance.Open M3U & EPG Manager (/sources), edit your M3U account, and set Max Streams to your subscription limit (e.g., 1 or 2). Dispatcharr will queue or reject excess stream requests rather than exceeding provider caps.
Downstream client (Plex / Jellyfin) reports playback error or bufferingProvider stream codec or container format is incompatible with the client, or direct proxy bandwidth is unstable.In Dispatcharr, edit the channel or provider and change the assigned Stream Profile from Proxy to FFmpeg. FFmpeg remuxes the stream into standard MPEG-TS and normalizes audio tracks for consistent playback.
Host public IP address visible in sidebar widgetDispatcharr's sidebar includes a Public IP detection widget that displays the first two octets of the host IP.When recording screencasts or taking screenshots for public sharing, blur or crop the bottom-left sidebar area (approximately x: 26–213, y: 558–594 at 1280×720 resolution).

Teardown / Cleanup

If you need to stop and remove the Dispatcharr deployment, execute the following commands from your deployment directory:

# 1. Stop and remove containers, networks, and internal Docker volumes
docker compose down --remove-orphans -v

# 2. Remove persistent data directories (handling container-owned files)
cd ..
docker run --rm -v "$(pwd)/dispatcharr:/d" alpine rm -rf /d/data
rm -rf dispatcharr

# 3. Verify no containers remain
docker ps -a --filter "name=dispatcharr"

Assumptions & Decisions

  • Official All-in-One Image Selection: Dispatcharr explicitly designates Docker Compose with the All-in-One (aio) image (ghcr.io/dispatcharr/dispatcharr:latest) as its official deployment method. Bare-metal deployments are unsupported upstream. The AIO image packages PostgreSQL 16, Redis, Celery, Daphne, uWSGI, Nginx, FFmpeg, and Comskip into a single zero-dependency container, avoiding host runtime installation.
  • Port Mapping (3000 to 9191): Dispatcharr's internal Nginx listens on port 9191. We mapped host port 3000 to internal container port 9191 (127.0.0.1:3000:9191) to maintain consistency across homelab deployment guides while documenting 9191 as the upstream default.
  • Documentation Discrepancy Corrections: Based on the live validated deployment and Playwright browser inspection (validated-process.md):

- *Superuser Endpoint:* The authoritative endpoint is /api/accounts/initialize-superuser/ rather than the informal name /api/accounts/superuser-exists/. - *M3U Dialog Layout:* The Add M3U modal is a single 3-column form (Account Info, Stream Limits, Sync Automation), not a multi-tab dialog. - *Stats Telemetry:* On a fresh instance, the Stats page displays active connection counts and events; bandwidth graphs appear only after active client streaming commences. - *Stream Profiles:* The Settings interface provides 5 distinct stream routing profiles (FFmpeg, Proxy, Redirect, Streamlink, VLC). - *Logs View:* The Logs page provides downloadable log files (dispatcharr.log) rather than a real-time terminal stream.

  • First-Run Superuser Creation: We documented the exact credentials (admin / Dispatcharr2026! / admin@dispatcharr.local) verified during automated browser testing.
  • Storage Isolation: Persistent application state is isolated in ./data (/data), ensuring database tables, JWT keys, and logs survive container restarts and can be completely removed upon teardown.
  • Table Formatting: In accordance with Ghost publishing constraints, the troubleshooting section is formatted as a GitHub-flavored Markdown pipe table, which ghost-draft parses and wraps into a Ghost HTML card (<!--kg-card-begin: html-->).
  • Screenshot References: All referenced screenshots point to verified local image assets in runs/dispatcharr-20261030-135938/browser/ captured during automated Playwright execution.