Files
homelab/docs/plex.md
2026-09-13 17:00:56 +02:00

5.4 KiB

Plex

Purpose: Self-hosted media server for streaming TV and movies from the local library.

Property Value
Image lscr.io/linuxserver/plex:latest
Web UI https://plex.home.jens.pub
Compose file ../services/plex/docker-compose.yml

Current upstream version: 1.43.4.10903 (1.43.4.10903-e5521bd8c-ls324). The latest tag is used deliberately — LinuxServer recommends it for Plex, and VERSION=docker lets the image track the current public build. Plex also self-updates inside the container.


Environment Variables

Variable Description
PUID Host user ID for volume ownership
PGID Host group ID for volume ownership
TZ Timezone (e.g. Europe/Berlin)
TV_PATH Host path to TV library
MOVIES_PATH Host path to movies library
PLEX_CLAIM Claim token for first-time setup

VERSION=docker is set in the compose file (not Portainer) and means "let the image decide the Plex version".


First-time setup (claiming)

Plex refuses the setup wizard when the request arrives through a reverse proxy with an unknown Host header (it treats it as non-local), so the web UI shows "Not authorized — You do not have access to this server" until the server is claimed. Claim it with a claim token:

  1. Open https://plex.tv/claim while logged in and copy the token (it expires after ~4 minutes).
  2. Put it in the PLEX_CLAIM value of the plex stack in Portainer.
  3. Restart the stack: knecht restart plex (or knecht update plex).
  4. Open https://plex.home.jens.pub/web — the server is now claimed to your account.

PLEX_CLAIM can be emptied again afterwards; it is only read while the server is unclaimed.

After claiming

Plex clients (Apple TV, mobile, TV apps) do not use the Traefik domain. They read the server's connection list from plex.tv and connect directly, so two things are needed:

  1. Publish the client ports — see Ports below. Otherwise the only advertised address is the container IP (172.18.0.11), which no client can reach.

  2. Custom server access URLs = http://192.168.178.193:32400 (host LAN IP) and optionally https://plex.home.jens.pub. Set via Settings → Network or the API:

    curl -X PUT "http://192.168.178.193:32400/:/prefs\
    ?customConnections=http://192.168.178.193:32400,https://plex.home.jens.pub\
    &allowedNetworks=192.168.178.0/24,172.18.0.0/16\
    &X-Plex-Token=<PlexOnlineToken>"
    

    The token lives in /config/Library/Application Support/Plex Media Server/Preferences.xml (PlexOnlineToken).

allowedNetworks (LAN Networks) makes the LAN and the Docker subnet count as local, avoiding the remote bandwidth cap. After this, plex.tv advertises e.g. https://192-168-178-193.<hash>.plex.direct:32400 (local=1) and clients connect directly.


Ports

Bridge networking means Plex clients can only reach the server if its ports are published on the host. GDM multicast discovery does not traverse the Docker bridge — clients rely on the plex.tv connection list instead.

Port Purpose
32400/tcp Web UI + client streaming
8324/tcp Plex Companion
32469/tcp DLNA
32410-32414/udp GDM local discovery

1900/udp (SSDP) and 5353/udp (mDNS) are deliberately not published — they clash with the host's own Avahi/SSDP services and aren't needed for connectivity.

If clients still misbehave (e.g. rely on GDM discovery), network_mode: host is LinuxServer's recommended mode and makes discovery work — at the cost of the Traefik route for the web UI.


Volumes

Volume Mount Purpose
plex_config /config Database, metadata, settings
${TV_PATH} /media/tv:ro TV library (read-only)
${MOVIES_PATH} /media/movies:ro Movies library (read-only)
tmpfs /transcode (4 GB) RAM transcoding scratch

Media is mounted read-only — Plex only reads, Sonarr/Radarr manage the files.

The transcode directory is a tmpfs rather than a named volume: LinuxServer removed /transcode volume support, and transcoding to RAM is faster and avoids SSD wear. The 4 GB is a cap, not a reservation.


Networks

  • proxy (external) — Traefik routes plex.home.jens.pub → port 32400
  • Host ports 32400, 8324, 32469, 32410-32414/udp published directly (see Ports)

Plex is intentionally not routed through the VPN. Like Jellyfin it serves local clients and doesn't need outbound anonymity.

Remote access

Because 32400 is published on the host, Plex's remote-access check passes and it is reachable from outside the LAN (router port-forward / UPnP required). The public address is reported by Plex as the WAN IP.