h04-media-entertainment

00-chapter-intro.md

kstack: book: Centerpoint Home Lab chapter: Media & Entertainment page: Chapter Introduction tags: [media, plex, jellyfin, immich, audiobookshelf, stash]

Overview

This chapter covers all media consumption and photo management services on Centerpoint. Media files themselves are not stored locally — they live on the UnRAID NAS (192.168.1.119) and are bind-mounted into containers from the NFS shares at /mnt/Multimedia and /mnt/Photos.

Shared Storage

NFS Mount Contents Consumers
/mnt/Multimedia Movies, TV, adult content, audiobooks, podcasts Plex, Jellyfin, Emby, Audiobookshelf, Stash
/mnt/Photos Photo library, Google Photos imports Immich

Services in This Chapter

Service Container(s) Status Purpose
Plex plex Active Primary media server
Jellyfin jellyfin Active Open-source media server (secondary)
Emby emby Offline Legacy media server — not running
Tautulli tautulli Active Plex analytics and monitoring
Immich immich_server, immich_machine_learning, immich_postgres, immich_redis Active Photo & video library
Audiobookshelf audiobookshelf Active Audiobooks and podcasts
Seerr seerr Active Media request management
Stash stash, stash-vr Active Adult media library + VR frontend
Threadfin threadfin Active IPTV M3U proxy for Plex/Jellyfin

Last Updated: 2026-06-16

01-plex.md

kstack: book: Centerpoint Home Lab chapter: Media & Entertainment page: Plex tags: [plex, media, streaming]

Overview

Plex Media Server is the primary media server for the homelab, serving movies, TV shows, and other content to Plex clients on the local network and remotely. It uses Plex's own account-based authentication — no Authentik ForwardAuth is applied. GeoBlock is active on the external route.

A second Plex instance running on another device (192.168.1.186) is routed via Traefik's file provider as plex2.jeeves5454.ddns.net.

Access

Type URL Notes
External https://plex.jeeves5454.ddns.net GeoBlock (CA/US/IN), no Authentik — Plex account auth
Direct http://192.168.1.85:32400 LAN direct access

No *.home.local internal Traefik route — Plex is accessed externally or by direct IP on the LAN.

Configuration

Image: lscr.io/linuxserver/plex:latest Compose project: Standalone (managed via Portainer)

Ports

Port Protocol Purpose
32400 TCP Plex Media Server API and web UI

Traefik Labels

traefik.enable: "true"
traefik.http.routers.plex.rule: Host(`plex.jeeves5454.ddns.net`)
traefik.http.routers.plex.entrypoints: websecure
traefik.http.routers.plex.tls.certresolver: letsencrypt
traefik.http.routers.plex.middlewares: plex-geoblock@file,plex-headers
traefik.http.middlewares.plex-headers.headers.customrequestheaders.X-Forwarded-Proto: https
traefik.http.services.plex.loadbalancer.server.port: 32400

The plex-headers middleware injects X-Forwarded-Proto: https — required for Plex to generate correct redirect and callback URLs when behind a reverse proxy.

Environment Variables

Variable Value Purpose
PUID 1000 Run as user ID 1000
PGID 1000 Run as group ID 1000
TZ America/Toronto Timezone
VERSION docker Use the latest Plex from Docker Hub
ADVERTISE_IP https://plex.jeeves5454.ddns.net:443 External URL Plex advertises to clients

ADVERTISE_IP must match the externally reachable URL for remote streaming to work correctly when behind Traefik.

Volumes / Bind Mounts

Host Path Container Path Purpose
/home/jeeves/docker/plex/config /config Plex database, metadata, settings
/mnt/Multimedia /Multimedia All media files (NFS from UnRAID)
/home/jeeves/docker /docker Utility bind (admin access)

Networks

Network Purpose
traefik-net Exposes Plex via Traefik external route

Dependencies

Notes / Gotchas


Last Updated: 2026-06-16

02-jellyfin.md

kstack: book: Centerpoint Home Lab chapter: Media & Entertainment page: Jellyfin tags: [jellyfin, media, streaming, open-source]

Overview

Jellyfin is a free and open-source media server used as a secondary streaming solution alongside Plex. It serves TV shows and movies from the same UnRAID NFS share and is accessible on the LAN only.

Access

Type URL Notes
Internal https://jellyfin.home.local LAN access via Step-CA TLS
Direct http://192.168.1.85:8096 LAN direct access

No external (internet-facing) route.

Configuration

Image: jellyfin/jellyfin:latest Compose project: Standalone (managed via Portainer)

Ports

Port Protocol Purpose
8096 TCP Jellyfin web UI and API (host-bound)

Traefik Labels

traefik.enable: "true"
traefik.http.routers.jellyfin.rule: Host(`jellyfin.home.local`)
traefik.http.routers.jellyfin.entrypoints: websecure
traefik.http.routers.jellyfin.tls: "true"
traefik.http.routers.jellyfin.tls.certresolver: step-ca
traefik.http.services.jellyfin.loadbalancer.server.port: 8096

Environment Variables

Variable Value Purpose
PUID 1000 User ID
PGID 1000 Group ID
TZ America/Toronto Timezone

Volumes / Bind Mounts

Host Path Container Path Purpose
/home/jeeves/docker/jellyfin/config /config Jellyfin database and settings
/home/jeeves/docker/jellyfin/cache /cache Thumbnail and transcode cache
/mnt/Multimedia/TV /media/tv:ro TV series (NFS from UnRAID, read-only)
/mnt/Multimedia/Movies /media/movies:ro Movies (NFS from UnRAID, read-only)

Networks

Network Purpose
traefik-net Exposes Jellyfin via Traefik

Dependencies

Notes / Gotchas


Last Updated: 2026-06-16

03-emby.md

kstack: book: Centerpoint Home Lab chapter: Media & Entertainment page: Emby (Offline) tags: [emby, media, offline]

Overview

Status: OFFLINE — The Emby container is present on Centerpoint but is not currently running. It has been superseded by Jellyfin for open-source media serving needs. The container and its configuration are retained.

Emby was previously used as an alternative media server. Its configuration and data remain intact and the container can be restarted if needed, subject to the port 8096 conflict with Jellyfin (see Notes).

Access

Type URL Notes
Internal https://emby.home.local Traefik labels present — not routed while offline

Configuration

Image: emby/embyserver:latest Status: exited (container stopped)

Traefik Labels (inactive while container is stopped)

traefik.enable: "true"
traefik.http.routers.emby.rule: Host(`emby.home.local`)
traefik.http.routers.emby.entrypoints: websecure
traefik.http.routers.emby.tls.certresolver: step-ca
traefik.http.services.emby.loadbalancer.server.port: 8096

Volumes / Bind Mounts

Host Path Container Path Purpose
/home/jeeves/docker/emby/config /config Emby database and library config
/mnt/Multimedia/ST /data Media files (same NFS as Stash)

Notes / Gotchas


Last Updated: 2026-06-16

04-tautulli.md

kstack: book: Centerpoint Home Lab chapter: Media & Entertainment page: Tautulli tags: [tautulli, plex, monitoring, analytics]

Overview

Tautulli is the monitoring and analytics companion for Plex Media Server. It tracks play history, user activity, and library statistics, and can send notifications (email, Telegram, etc.) on media events such as new content additions, playback starts, or user logins.

Access

Type URL Notes
Internal https://tautulli.home.local LAN access via Step-CA TLS

No external route — LAN and Tailscale access only.

Configuration

Image: lscr.io/linuxserver/tautulli:latest Compose project: Standalone (managed via Portainer)

Traefik Labels

traefik.enable: "true"
traefik.http.routers.tautulli.rule: Host(`tautulli.home.local`)
traefik.http.routers.tautulli.entrypoints: websecure
traefik.http.routers.tautulli.tls.certresolver: step-ca
traefik.http.services.tautulli.loadbalancer.server.port: 8181

Environment Variables

Variable Value Purpose
PUID 1000 User ID
PGID 1000 Group ID
TZ America/Toronto Timezone

Volumes / Bind Mounts

Host Path Container Path Purpose
/home/jeeves/docker/Tautulli/local_tautulli /config Tautulli database and configuration

Networks

Network Purpose
traefik-net Exposes Tautulli UI; also reaches Plex container

Dependencies

Notes / Gotchas


Last Updated: 2026-06-16

05-immich.md

kstack: book: Centerpoint Home Lab chapter: Media & Entertainment page: Immich tags: [immich, photos, media, cuda, gpu, self-hosted]

Overview

Immich is the self-hosted photo and video library for the homelab — a local alternative to Google Photos. It provides automatic mobile backup, face recognition, smart search, and album management. The machine learning container runs on the RTX 5080 via CUDA for accelerated facial recognition and CLIP-based smart search.

Photo storage lives on the UnRAID NAS NFS mount at /mnt/Photos.

Access

Type URL Notes
Internal https://photos.home.local LAN access via Step-CA TLS
External https://photos.jeevesconsults.ca GeoBlock (CA/US/IN) + CrowdSec — no Authentik ForwardAuth

Immich uses its own user authentication — Authentik ForwardAuth is not applied because it would break the mobile app OAuth flow.

Containers in This Stack

Container Image GPU Role
immich_server ghcr.io/immich-app/immich-server:release No Main API and web server
immich_machine_learning ghcr.io/immich-app/immich-machine-learning:release-cuda Yes Face recognition + CLIP search
immich_postgres ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0 No PostgreSQL with pgvecto.rs
immich_redis valkey/valkey:8-bookworm No Job queue and cache

Configuration

Compose file: /home/jeeves/docker/immich/docker-compose.yml Compose project: immich

Ports

Port Protocol Purpose
2283 TCP Immich web UI and API (host-bound)

Traefik Labels

# External route
traefik.http.routers.immich.rule: Host(`photos.jeevesconsults.ca`)
traefik.http.routers.immich.entrypoints: websecure
traefik.http.routers.immich.tls.certresolver: letsencrypt
traefik.http.routers.immich.middlewares: plex-geoblock@file,crowdsec-bouncer@file,immich-headers
traefik.http.middlewares.immich-headers.headers.customrequestheaders.X-Forwarded-Proto: https

# Internal route
traefik.http.routers.immich-internal.rule: Host(`photos.home.local`)
traefik.http.routers.immich-internal.entrypoints: websecure
traefik.http.routers.immich-internal.tls.certresolver: step-ca

traefik.http.services.immich.loadbalancer.server.port: 2283

Key Environment Variables (.env file)

Variable Value / Notes
UPLOAD_LOCATION /mnt/Photos/immich-library
DB_HOSTNAME immich_postgres
DB_USERNAME postgres
DB_PASSWORD REDACTED
DB_DATABASE_NAME immich
REDIS_HOSTNAME immich_redis
TZ America/Toronto
IMMICH_VERSION release (pinned to latest stable)

Volumes / Bind Mounts

Host Path / Volume Container Path Purpose
/mnt/Photos/immich-library /data Primary upload library (NFS)
/mnt/Photos/Plex /mnt/Photos/Plex:rw Plex photo library (external library)
/mnt/Photos/Google_Photos /mnt/Photos/Google_Photos:rw Google Photos import folder
/etc/localtime /etc/localtime:ro Host timezone sync
model-cache (named volume) /cache ML model weight cache (machine learning container)
${DB_DATA_LOCATION} (from .env) /var/lib/postgresql/data PostgreSQL data

Sub-section: Machine Learning (CUDA)

immich_machine_learning runs with runtime: nvidia, giving it access to the RTX 5080 for:

Environment Variable Value Purpose
NVIDIA_VISIBLE_DEVICES all GPU access
NVIDIA_DRIVER_CAPABILITIES compute,utility CUDA compute caps
MACHINE_LEARNING_DEVICE_ID 0 Use GPU device 0

ML model files are cached in the model-cache named Docker volume. Models are downloaded from HuggingFace on first use and cached for subsequent runs.

Sub-section: PostgreSQL (pgvecto.rs)

Immich uses a custom PostgreSQL 14 image with the pgvecto.rs and pgvectors extensions pre-installed. These extensions power the vector similarity search that underlies CLIP smart search and face clustering.

ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0

The shm_size: 128mb allocation is required for PostgreSQL's shared memory.

Sub-section: Redis / Valkey

immich_redis uses Valkey (the Redis fork) as the job queue and cache backend. It handles background job scheduling for ML processing, thumbnail generation, and library scans.

Dependencies

Notes / Gotchas


Last Updated: 2026-06-16

06-audiobookshelf.md

kstack: book: Centerpoint Home Lab chapter: Media & Entertainment page: Audiobookshelf tags: [audiobookshelf, audiobooks, podcasts, media]

Overview

Audiobookshelf is a self-hosted audiobook and podcast server. It manages and streams audiobook and podcast content from the UnRAID NFS share, tracks listening progress across devices, and supports mobile apps for on-the-go listening.

A notable configuration detail: the Step-CA root certificate is injected into the container's trust store so that Audiobookshelf can make HTTPS calls to internal *.home.local services (e.g. for metadata lookups or integrations).

Access

Type URL Notes
External https://audio.jeeves5454.ddns.net GeoBlock (CA/US/IN) + CrowdSec — no Authentik

No *.home.local internal Traefik route — accessible externally or via direct LAN IP. Audiobookshelf uses its own account-based authentication.

Configuration

Image: ghcr.io/advplyr/audiobookshelf:latest Compose project: Standalone (managed via Portainer)

Traefik Labels

traefik.enable: "true"
traefik.http.routers.audio.rule: Host(`audio.jeeves5454.ddns.net`)
traefik.http.routers.audio.entrypoints: websecure
traefik.http.routers.audio.tls.certresolver: letsencrypt
traefik.http.routers.audio.middlewares: plex-geoblock@file,crowdsec-bouncer@file,audio-headers
traefik.http.middlewares.audio-headers.headers.customrequestheaders.X-Forwarded-Proto: https
traefik.http.services.audio.loadbalancer.server.port: 80

Volumes / Bind Mounts

Host Path Container Path Purpose
/home/jeeves/docker/audiobookshelf/config /config App database and settings
/home/jeeves/docker/audiobookshelf/metadata /metadata Cover art and cached metadata
/mnt/Multimedia/Audio/Audio_Books /audiobooks Audiobook files (NFS from UnRAID)
/mnt/Multimedia/Audio/podcasts /podcasts Podcast episode files (NFS from UnRAID)
/home/jeeves/docker/step-ca/config/certs/root_ca.crt /usr/local/share/ca-certificates/step-ca.crt:ro Step-CA root cert trust injection

The Step-CA root certificate is bind-mounted into the container's CA trust directory, allowing Audiobookshelf to trust *.home.local TLS certificates when making outbound HTTPS requests to internal services.

Networks

Network Purpose
traefik-net Exposes the Audiobookshelf UI

Dependencies

Notes / Gotchas


Last Updated: 2026-06-16

07-seerr.md

kstack: book: Centerpoint Home Lab chapter: Media & Entertainment page: Seerr tags: [seerr, overseerr, media-requests, plex, jellyfin]

Overview

Seerr is a media request management application — a maintained fork of Overseerr. It provides a user-friendly interface for requesting movies and TV shows, which are then forwarded to the *arr stack (Radarr, Sonarr) for automated download and delivery to Plex and Jellyfin. It also surfaces Plex availability status so users can see what is already in the library before requesting.

Access

Type URL Notes
Internal https://seerr.home.local LAN access via Step-CA TLS
External https://seerr.jeeves5454.ddns.net Authentik SSO + GeoBlock + CrowdSec

Configuration

Image: ghcr.io/seerr-team/seerr:latest Compose project: arr stack (managed via Portainer alongside the *arr services)

Traefik Labels

# External route
traefik.http.routers.seerr-external.rule: Host(`seerr.jeeves5454.ddns.net`)
traefik.http.routers.seerr-external.entrypoints: websecure
traefik.http.routers.seerr-external.tls.certresolver: letsencrypt
traefik.http.routers.seerr-external.middlewares: authentik-auth@docker,plex-geoblock@file,crowdsec-bouncer@file
traefik.http.routers.seerr-external.service: seerr-svc

# Internal route
traefik.http.routers.seerr-internal.rule: Host(`seerr.home.local`)
traefik.http.routers.seerr-internal.entrypoints: websecure
traefik.http.routers.seerr-internal.tls.certresolver: step-ca
traefik.http.routers.seerr-internal.service: seerr-svc

traefik.http.services.seerr-svc.loadbalancer.server.port: 5055

Environment Variables

Variable Value Purpose
PORT 5055 Application port
LOG_LEVEL debug Logging verbosity
TZ America/Toronto Timezone
NODE_ENV production Runtime environment

Volumes / Bind Mounts

Host Path Container Path Purpose
/home/jeeves/docker/arr/Seer/config /app/config Seerr database and configuration

Networks

Network Purpose
traefik-net Exposes Seerr UI
media-network Internal network shared with *arr stack services (Sonarr, Radarr, etc.)

The media-network attachment allows Seerr to communicate directly with Sonarr, Radarr, and Plex by container hostname without going through Traefik.

Dependencies

Notes / Gotchas


Last Updated: 2026-06-16

09-threadfin.md

kstack: book: Centerpoint Home Lab chapter: Media & Entertainment page: Threadfin tags: [threadfin, iptv, m3u, xmltv, plex, jellyfin]

Overview

Threadfin is an M3U proxy and IPTV middleware that translates IPTV streams into a format consumable by Plex DVR and Jellyfin Live TV. It manages M3U playlists, XMLTV guide data, and presents a virtual tuner device to media servers via HDHR (HDHomeRun) emulation.

Access

Type URL / Endpoint Notes
Web UI http://192.168.1.85:34400 Direct LAN access — no Traefik route
HDHR http://192.168.1.85:34400 HDHomeRun device emulation endpoint

No Traefik route is configured for Threadfin — Plex and Jellyfin connect to it via direct IP and port on the LAN.

Configuration

Image: fyb3roptik/threadfin:latest Compose project: Standalone (managed via Portainer)

Ports

Port Protocol Purpose
34400 TCP Threadfin web UI and HDHR endpoint (host-bound)

Environment Variables

Variable Value Purpose
TZ America/Toronto Timezone
THREADFIN_PORT 34400 Listen port
THREADFIN_BRANCH main Update channel
THREADFIN_BIND_IP_ADDRESS 0.0.0.0 Bind to all interfaces
THREADFIN_DEBUG 0 Debug logging off

Volumes / Bind Mounts

Host Path Container Path Purpose
/home/jeeves/docker/threadfin/config /home/threadfin/conf M3U playlists, XMLTV data, settings

Networks

Network Purpose
traefik-net Present (container is on traefik-net but no labels)

Threadfin is on traefik-net for network reachability but has no Traefik labels — it is accessed by direct IP.

Plex / Jellyfin Integration

Plex:

  1. In Plex Settings → Live TV & DVR → Set Up Plex Tuner
  2. Enter the Threadfin HDHR URL: http://192.168.1.85:34400/device.xml
  3. Plex discovers the virtual tuner and available channels

Jellyfin:

  1. Admin Dashboard → Live TV → Add Tuner Device
  2. Select HDHomeRun and enter http://192.168.1.85:34400

Dependencies

Notes / Gotchas


Last Updated: 2026-06-16