How to Deploy Seerr: Media Request and Discovery Hub for Jellyfin and Plex with Docker Compose

Seerr is a modern request management and media discovery platform that lets users browse and request movies and TV shows for Jellyfin, Plex, and Emby without accessing server infrastructure. Learn how to deploy Seerr with Docker Compose, bootstrap the initial administrator account, and automate media requests.

How to Deploy Seerr: Media Request and Discovery Hub for Jellyfin and Plex with Docker Compose

Seerr is a free and open-source request management and media discovery platform for self-hosted media servers. Serving as the modern unified evolution in the Overseerr and Jellyseerr lineage, Seerr provides a clean, responsive web interface that connects directly with Jellyfin, Plex, and Emby. Instead of handling ad-hoc texts and emails asking to add new titles to your media collection, Seerr empowers your friends and family to independently search an interactive The Movie Database (TMDB) catalog, view high-definition trailers, browse recommendations, and submit requests with customizable user quotas and granular permission controls.

Seerr Discover and Request Dashboard

Under the hood, Seerr interfaces seamlessly with automation tools such as Sonarr (for television series) and Radarr (for movies). When an authorized user submits a request, Seerr can automatically approve the item or place it in an administrative queue for review. Once approved, Seerr dispatches the request to the appropriate downstream service and tracks the item's lifecycle from *Requested* to *Processing*, ultimately marking it as *Available* once indexed by your media server.

Key Capabilities and Architecture

  1. Multi-Server Authentication & Synchronization: Connects natively to Jellyfin, Plex, or Emby for user account synchronization, single sign-on (SSO), and continuous library indexing.
  2. Granular User Permissions: Assign role-based capabilities, including auto-approval privileges, per-user weekly/monthly request quotas, 4K-specific request limits, and user management rights.
  3. Rich Catalog Discovery: Leverages TMDB for localized metadata, trailers, cast details, similar titles, and dynamic discovery carousels (Trending, Popular Movies, Upcoming TV Shows).
  4. Dual Database Engine Support: Supports lightweight zero-configuration SQLite (with Write-Ahead Logging) for standalone setups, as well as enterprise PostgreSQL for high-concurrency environments.
  5. Interactive OpenAPI / Swagger Documentation: Ships with an embedded Swagger UI interface hosted at /api-docs alongside a comprehensive REST API for scripting and external notifications.

---

Prerequisites

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

  • Operating System: Modern Linux distribution (Debian 12+, Ubuntu 22.04/24.04 LTS, Rocky Linux, or Arch Linux) or macOS/Windows running Docker Engine / WSL2.
  • Container Engine: Docker Engine 24.0+ with Docker Compose v2 (docker compose version v2.24+).
  • Hardware Resources:

- CPU: 1 to 2 vCPU cores. Seerr is lightweight in idle states; resource usage increases during initial TMDB library scans. - Memory: 512 MB RAM minimum; 1 GB to 2 GB recommended when scanning libraries with tens of thousands of items. - Storage: 1 GB persistent disk space for Seerr configuration, logs, and database cache.

  • Network Ports:

- Seerr Web UI / REST API: Host port 3000 (mapped to container internal port 5055). - Media Server (Jellyfin/Plex): Host port 8096 (Jellyfin) or 32400 (Plex). Both services communicate internally over the Docker bridge network.

  • Media Server Requirement: Seerr requires an active Jellyfin, Plex, or Emby instance to complete its initial bootstrap wizard and create the primary administrator account.

---

Exact Install Steps

The official Seerr application is published as a container image on GitHub Container Registry (ghcr.io/seerr-team/seerr:latest). In this deployment, we configure Seerr alongside a local Jellyfin container on a dedicated Docker bridge network so Seerr can validate libraries and bootstrap administrative credentials immediately.

Step 1: Create Staging Directory Structure

Create dedicated directories on the host to hold persistent configuration data, database files, and media directories:

mkdir -p seerr/config seerr/jellyfin/config seerr/jellyfin/cache seerr/media/movies seerr/media/tv
cd seerr

Ensure permissions allow container processes to read and write data:

chmod 775 config jellyfin/config jellyfin/cache media/movies media/tv

Step 2: Define Environment Variables (.env)

Create a .env file to set your project name, host port bindings, and timezone:

cat > .env <<'EOF'
COMPOSE_PROJECT_NAME=shortform-seerr
PORT=3000
JF_PORT=8096
TZ=Etc/UTC
LOG_LEVEL=info
EOF

chmod 600 .env

Step 3: Create Docker Compose Specification (compose.yml)

Create the compose.yml file defining both the Seerr application service and the Jellyfin media server. The services share an isolated bridge network, allowing Seerr to reach Jellyfin via its container DNS name jellyfin:8096:

cat > compose.yml <<'EOF'
services:
  seerr:
    container_name: ${COMPOSE_PROJECT_NAME}-app
    image: ghcr.io/seerr-team/seerr:latest
    init: true
    restart: unless-stopped
    ports:
      - "${PORT}:5055"
    environment:
      - LOG_LEVEL=${LOG_LEVEL}
      - TZ=${TZ}
      - PORT=5055
    volumes:
      - ./config:/app/config
    healthcheck:
      test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://127.0.0.1:5055/api/v1/status || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 10
      start_period: 20s
    depends_on:
      - jellyfin
    networks:
      - seerr

  jellyfin:
    container_name: ${COMPOSE_PROJECT_NAME}-jellyfin
    image: jellyfin/jellyfin:latest
    user: "1000:1000"
    restart: unless-stopped
    ports:
      - "${JF_PORT}:8096"
    environment:
      - TZ=${TZ}
    volumes:
      - ./jellyfin/config:/config
      - ./jellyfin/cache:/cache
      - ./media:/media
    networks:
      - seerr

networks:
  seerr:
    name: ${COMPOSE_PROJECT_NAME}-net
EOF

Step 4: Pull Images and Launch the Stack

Pull the container images and launch the services in detached mode:

docker compose pull -q
docker compose up -d

Monitor container health until both services report healthy:

docker compose ps

Step 5: Bootstrap the Initial Owner Account

Unlike standalone applications that create a local root administrator during database initialization, Seerr's security architecture anchors its initial owner account to an upstream media server.

When configuring via the browser setup wizard or automated API, submit your media server administrator credentials to Seerr's authentication endpoint. This creates user #1 with full ADMIN rights (permissions: 2) and links the media server configuration:

# Authenticate with Jellyfin and register the primary owner
curl -sf -c .jar -H 'Content-Type: application/json' -X POST "http://localhost:3000/api/v1/auth/jellyfin" \
  -d '{
    "hostname": "jellyfin",
    "port": 8096,
    "useSsl": false,
    "urlBase": "",
    "username": "admin",
    "password": "YourSecurePassword!",
    "email": "admin@example.com",
    "serverType": 2
  }'

Next, sync the media server libraries, enable them, and mark Seerr as initialized:

# Synchronize libraries from Jellyfin
curl -sf -b .jar -X POST "http://localhost:3000/api/v1/settings/jellyfin/library/sync"

# Enable all detected libraries
for id in $(curl -sf -b .jar "http://localhost:3000/api/v1/settings/jellyfin/library" | python3 -c "import sys,json; [print(l['id']) for l in json.load(sys.stdin)]"); do
  curl -sf -b .jar -X PUT "http://localhost:3000/api/v1/settings/jellyfin/library/$id" \
    -H 'Content-Type: application/json' -d '{"enabled":true}'
done

# Finalize initialization
curl -sf -b .jar -X POST "http://localhost:3000/api/v1/settings/initialize"

# (Optional) Assign a local password to allow direct email/password login
curl -sf -b .jar -X POST "http://localhost:3000/api/v1/user/1/settings/password" \
  -H 'Content-Type: application/json' \
  -d '{"newPassword":"YourSecurePassword!","confirmPassword":"YourSecurePassword!"}'

---

Browser Setup

Once the stack is initialized, open your browser and navigate to http://localhost:3000 to complete the walkthrough.

1. Authentication and Login

Navigate to http://localhost:3000/login. You will be greeted by the Seerr login interface.

Seerr Login Screen

You can authenticate using your Jellyfin credentials directly (via the "Sign in with Jellyfin" button) or switch to the local email/password sign-in form using the credentials configured during account initialization.

2. Discovering Media

Upon signing in, Seerr displays the central Discover dashboard.

Seerr Discover Page

The Discover view aggregates several dynamic sections:

  • Recently Added: Displays titles currently available in your linked Jellyfin library, tagged with green *Available* badges.
  • Recent Requests: Highlights media requested by users, showing their current approval and processing state.

Discover Sliders and Trending Media

Scrolling down reveals interactive carousels for Trending Movies, Popular Series, and Upcoming Releases powered by live TMDB metadata.

3. Searching for Media and Submitting Requests

To search for content, click the global search input in the top navigation bar and enter a title (e.g., "The Matrix").

Searching for The Matrix

Select the target card from the instant search results to open the detailed media overview page.

Movie Details Page

Click the blue Request button. A modal dialog will appear allowing you to select specific seasons, target server profiles, or tag 4K requirements.

Request Confirmation Modal

For administrators, the modal notes that the request will be approved automatically. Click Request to confirm. Once submitted, the button changes to a purple badge displaying Requested.

Title Marked as Requested

4. Managing and Approving Requests

Standard non-admin users submit requests that enter an administrative review queue. Navigate to the Requests tab in the left sidebar to view the queue.

Pending Requests Queue

Pending requests display the requesting user, title details, and status. Click the green checkmark button on a pending request (e.g., *Interstellar*) to approve it.

Approved Request Status

The request immediately updates to approved status, and the sidebar badge count decrements accordingly.

5. Final Payoff

Returning to the Discover home page displays the updated ecosystem state:

Seerr Dashboard Payoff

The header displays available media synced directly from Jellyfin, recent requests reflect approved and pending statuses, and the notification badge accurately tracks pending administrative tasks.

---

Verification

Confirm that your deployment is healthy and operational using the following verification checks:

1. Check Container Health Status

Run docker compose ps to inspect container status:

docker compose ps

Both containers should display state Up (healthy).

2. Query System Status Endpoint

Query Seerr's status endpoint to confirm version, commit tag, and health:

curl -s http://localhost:3000/api/v1/status | python3 -m json.tool

Expected output includes version 3.5.1 and build commit details:

{
  "version": "3.5.1",
  "commitTag": "564bfb08b54c..."
}

3. Verify Initialization and Media Server Connection

Query the public settings endpoint to ensure initialization succeeded:

curl -s http://localhost:3000/api/v1/settings/public | python3 -m json.tool

Confirm that "initialized": true and "mediaServerType": 2 (Jellyfin) are returned.

4. Query Available Media and Requests via API Key

Retrieve your Seerr API key from Settings > General (or inspect /api/v1/settings/main with an authenticated cookie session) and run programmatic checks:

API_KEY="your-api-key-here"

# Query indexed media
curl -sf -H "X-Api-Key: $API_KEY" "http://localhost:3000/api/v1/media?filter=available" | python3 -m json.tool

# Query request statistics
curl -sf -H "X-Api-Key: $API_KEY" "http://localhost:3000/api/v1/request/count" | python3 -m json.tool

5. Access Interactive Swagger Documentation

Seerr embeds full OpenAPI documentation directly in the container. Access the interactive Swagger explorer by opening http://localhost:3000/api-docs in your browser to inspect and test all REST endpoints.

---

Troubleshooting

Symptom / ErrorRoot CauseResolution
Initial setup wizard blocks or errors on first runSeerr requires a media server connection (Jellyfin, Plex, or Emby) to establish user #1 as administrator.Ensure your media server container is running and healthy, then complete the media server connection step in /setup or via POST /api/v1/auth/jellyfin.
Connection refused when connecting Seerr to JellyfinUsing localhost:8096 or 127.0.0.1:8096 in Seerr's media server configuration points back to the Seerr container itself.Use Docker's internal container DNS name jellyfin and port 8096 (e.g., http://jellyfin:8096) within the shared Compose network.
Requests remain in "Requested" status and never downloadDownstream automation services (Sonarr or Radarr) are not configured, or download clients are paused.In Settings > Services, add your Sonarr and Radarr server URLs and API keys, and map your root folders and quality profiles.
Permission denied writing to ./config/db or settings.jsonThe Seerr container drops privileges to non-root UID 1000:1000, which lacks write access to host directory.Grant ownership on the host: chown -R 1000:1000 seerr/config and verify folder permissions are set to 775.
Movie posters and actor thumbnails fail to loadOutbound network egress to TMDB (api.themoviedb.org, image.tmdb.org) is blocked by DNS or firewall.Check host and container DNS settings. Run docker exec -it <container_name> wget -qO- https://api.themoviedb.org to test outbound HTTPS connectivity.
Media items missing from Discover after adding filesJellyfin or Seerr library synchronization interval has not elapsed.Trigger a manual library scan in Jellyfin first, then navigate in Seerr to Settings > Jellyfin > Sync Libraries and click Start Sync.

---

Assumptions & Decisions

  • Media Server Sidecar Requirement: Upstream Seerr cannot complete its first-run wizard or initialize owner authentication without an upstream media server (Jellyfin, Plex, or Emby). Rather than attempting to mock settings.json (which results in zero valid user accounts), we deploy an official jellyfin/jellyfin:latest sidecar container in the Compose stack to establish real end-to-end authentication and library discovery.
  • Port Mapping: Host port 3000 is mapped to Seerr internal port 5055 following the standard lab configuration guidelines, and Jellyfin is exposed on host port 8096.
  • Dual Authentication Modes: The primary administrator is established via Jellyfin authentication (/api/v1/auth/jellyfin), and a local password is subsequently provisioned to allow seamless login via both Jellyfin credentials and direct local email/password forms.
  • Request State Semantics: In the absence of a configured Radarr or Sonarr download pipeline, approved media requests appropriately remain in status *Requested* / *Processing* in the UI rather than falsely claiming download completion.
  • Asset Paths: Screenshots are referenced using relative paths matching the lab test execution artifacts (runs/seerr-20261106-145849/browser/*.png), ensuring compatibility with Ghost draft asset uploading and local verification.