113 lines
4.5 KiB
YAML
113 lines
4.5 KiB
YAML
x-info:
|
|
github: https://github.com/linuxserver/docker-plex
|
|
docs: https://docs.linuxserver.io/images/docker-plex/
|
|
changelog: https://github.com/plexinc/pms-docker/releases
|
|
homelab_status: active
|
|
last_updated: 2026-03-13
|
|
|
|
# Managed by Ansible — manual edits will be overwritten on next deploy.
|
|
# Source: ansible/templates/stacks/plex.stack.yml
|
|
# Deploy: ansible-playbook -i inventory/hosts.ini playbooks/docker/deploy_plex.yml
|
|
#
|
|
# SECRETS REQUIRED:
|
|
# vault_plex_claim must be defined in group_vars/vault/all.yml.
|
|
# Encrypt with:
|
|
# ansible-vault encrypt_string 'claim-XXXX' --name 'vault_plex_claim'
|
|
# PLEX_CLAIM is a bootstrap token used only on first server claim; it is
|
|
# ignored by Plex on subsequent starts.
|
|
#
|
|
# DEVICE PASSTHROUGH NOTE:
|
|
# Docker Swarm has limited support for 'devices:' in service specs (requires
|
|
# Docker Engine 20.10+ and a single-node placement constraint). Hardware
|
|
# transcoding (/dev/dri, /dev/dvb) is pinned to swarm-manager-1. If your
|
|
# Swarm Engine does not support device passthrough, remove the 'devices:'
|
|
# block and rely on CPU transcoding only.
|
|
|
|
version: "3.9"
|
|
|
|
services:
|
|
plex:
|
|
image: lscr.io/linuxserver/plex:1.42.2.10156-f737b826c-ls283
|
|
environment:
|
|
- PUID=1000
|
|
- PGID=1000
|
|
- TZ=America/New_York
|
|
- VERSION=docker
|
|
- PLEX_CLAIM={{ vault_plex_claim }}
|
|
# ADVERTISE_IP: comma-separated list; Plex clients select the best path.
|
|
# External clients → Traefik HTTPS on port 443 (websecure entrypoint).
|
|
# LAN clients → direct Swarm routing mesh on port 32400 (fast path,
|
|
# no Traefik hop; required for SSDP/GDM discovery).
|
|
- ADVERTISE_IP=https://plex.castaldifamily.com:443/,http://{{ edge_routing.swarm.bind_ip }}:32400/
|
|
# ACCESS POLICY (Option B — split-access):
|
|
# LAN (10.0.0.0/24, 10.0.200.0/24): direct on port 32400 via Swarm routing mesh.
|
|
# External: Traefik HTTPS only (see deploy.labels block below).
|
|
# FIREWALL REQUIREMENT: block port 32400 from VLAN 30 (Guest) and VLAN 50 (IoT).
|
|
ports:
|
|
- "32400:32400"
|
|
volumes:
|
|
- /mnt/homelab/apps/plex/data:/config
|
|
- /mnt/media/tvshows:/tv
|
|
- /mnt/media/movies:/movies
|
|
# WHY absolute paths: Swarm services have no well-defined working directory.
|
|
# Relative paths (e.g. ./data) are unsafe in Swarm stacks.
|
|
#
|
|
# Device passthrough — requires Docker Engine >= 20.10 and single-node placement.
|
|
# If a device is absent: Docker ignores it and Plex falls back to CPU transcoding.
|
|
# Run deploy_plex.yml to see preflight warnings if GPU devices are absent.
|
|
devices:
|
|
- /dev/renderD128:/dev/renderD128
|
|
- /dev/dri:/dev/dri
|
|
- /dev/dvb:/dev/dvb
|
|
networks:
|
|
- proxy-net
|
|
# Top-level labels: used by homepage widget discovery (non-Swarm consumers).
|
|
labels:
|
|
- "homepage.name=Plex"
|
|
- "homepage.icon=si:plex"
|
|
- "homepage.url=https://plex.castaldifamily.com"
|
|
- "homepage.description=Movies & shows"
|
|
deploy:
|
|
replicas: 1
|
|
placement:
|
|
constraints:
|
|
# WHY pinned to swarm-manager-1: media volumes and hardware device
|
|
# nodes are local to this host. Update if media/GPU lives elsewhere.
|
|
- node.hostname == swarm-manager-1
|
|
labels:
|
|
# WHY deploy.labels (not top-level): traefik-kop reads Swarm *service*
|
|
# labels via the Docker API. Top-level labels are on the container image,
|
|
# not the Swarm service — traefik-kop will ignore them.
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.plex.rule=Host(`plex.castaldifamily.com`)"
|
|
- "traefik.http.routers.plex.entrypoints=websecure"
|
|
- "traefik.http.routers.plex.tls=true"
|
|
- "traefik.http.routers.plex.tls.certresolver=cloudflare"
|
|
# WHY server.url (not server.port): routes external Traefik to the Swarm
|
|
# routing mesh IP rather than guessing a container IP. Consistent with
|
|
# gitea.stack.yml pattern.
|
|
- "traefik.http.services.plex.loadbalancer.server.url=http://{{ edge_routing.swarm.bind_ip }}:32400"
|
|
resources:
|
|
limits:
|
|
memory: 2G
|
|
cpus: "2.0"
|
|
restart_policy:
|
|
condition: on-failure
|
|
delay: 10s
|
|
max_attempts: 3
|
|
window: 60s
|
|
update_config:
|
|
parallelism: 1
|
|
order: start-first
|
|
failure_action: rollback
|
|
delay: 10s
|
|
monitor: 30s
|
|
rollback_config:
|
|
parallelism: 1
|
|
order: stop-first
|
|
|
|
networks:
|
|
proxy-net:
|
|
external: true
|
|
name: proxy-net
|