feat(streaming): add jellyfin stack
New Portainer stack: jellyfin, jellystat + postgres, wizarr and jellyplex-watched. Bulk data (metadata, trickplay, cache, transcodes) binds to /storage1; only SQLite config lands on the root disk. Trickplay gets an explicit sub-bind because 10.11 moved it to /config/data/trickplay, which is not relocatable from the UI. Transcodes are disk-backed rather than tmpfs because jellyfin#16608 orphans segments on the Remux/DirectStream jobs that are routine on this server.
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
# streaming stack — Jellyfin and its satellites.
|
||||
#
|
||||
# Storage split is deliberate: SQLite config on the root SSD, all bulk data
|
||||
# (metadata, trickplay, cache, transcodes) on /storage1. The root disk is only
|
||||
# 194G and has filled twice; nothing here may grow unbounded on it.
|
||||
#
|
||||
# Trickplay gets an explicit sub-bind because Jellyfin 10.11 moved it to
|
||||
# /config/data/trickplay and it is NOT relocatable from the UI.
|
||||
#
|
||||
# Transcodes are disk-backed, not tmpfs: jellyfin#16608 means Remux and
|
||||
# DirectStream jobs finish before the segment cleaner's first check, orphaning
|
||||
# segments. Plex already writes transcodes to virtiofs at a 48% transcode rate.
|
||||
#
|
||||
# Env convention: every service gets stack.env via env_file; var names there are
|
||||
# exactly what the containers read. No ${VAR} interpolation, no Portainer UI
|
||||
# env vars.
|
||||
|
||||
services:
|
||||
jellyfin:
|
||||
container_name: jellyfin
|
||||
image: lscr.io/linuxserver/jellyfin:latest
|
||||
restart: unless-stopped
|
||||
networks: [streaming, edge]
|
||||
env_file:
|
||||
- stack.env
|
||||
environment:
|
||||
- JELLYFIN_PublishedServerUrl=https://jellyfin.ginnoir.com
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /config/jellyfin:/config
|
||||
- /storage1/labdata/jellyfin/metadata:/config/metadata
|
||||
- /storage1/labdata/jellyfin/cache:/config/cache
|
||||
- /storage1/labdata/jellyfin/trickplay:/config/data/trickplay
|
||||
- /storage1/labdata/jellyfin/transcodes:/transcode
|
||||
- /storage1/Movies:/data/movies:ro
|
||||
- /storage1/TV:/data/tv:ro
|
||||
- /storage1/Anime:/data/anime:ro
|
||||
ports:
|
||||
- "8096:8096"
|
||||
|
||||
jellystat-db:
|
||||
container_name: jellystat-db
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
networks: [streaming]
|
||||
env_file:
|
||||
- stack.env
|
||||
labels:
|
||||
- "com.centurylabs.watchtower.enable=false"
|
||||
volumes:
|
||||
- /config/jellystat-db:/var/lib/postgresql/data
|
||||
|
||||
jellystat:
|
||||
container_name: jellystat
|
||||
image: cyfershepard/jellystat:latest
|
||||
restart: unless-stopped
|
||||
networks: [streaming, edge]
|
||||
depends_on:
|
||||
- jellystat-db
|
||||
env_file:
|
||||
- stack.env
|
||||
volumes:
|
||||
- /config/jellystat:/app/backend/backup-data
|
||||
ports:
|
||||
- "3009:3000"
|
||||
|
||||
wizarr:
|
||||
container_name: wizarr
|
||||
image: ghcr.io/wizarrrr/wizarr:latest
|
||||
restart: unless-stopped
|
||||
networks: [streaming, edge]
|
||||
env_file:
|
||||
- stack.env
|
||||
volumes:
|
||||
- /config/wizarr:/data/database
|
||||
ports:
|
||||
- "5690:5690"
|
||||
|
||||
jellyplex-watched:
|
||||
container_name: jellyplex-watched
|
||||
image: luigi311/jellyplex-watched:latest
|
||||
restart: unless-stopped
|
||||
networks: [streaming, edge]
|
||||
env_file:
|
||||
- stack.env
|
||||
|
||||
networks:
|
||||
streaming:
|
||||
name: streaming
|
||||
driver: bridge
|
||||
edge:
|
||||
name: edge
|
||||
external: true
|
||||
@@ -0,0 +1,31 @@
|
||||
# streaming stack config — injected into every service via env_file.
|
||||
# Var names are exactly what the containers read; no ${VAR} interpolation,
|
||||
# no Portainer UI env vars needed.
|
||||
|
||||
# --- shared ---
|
||||
TZ=America/Chicago
|
||||
PUID=1000
|
||||
PGID=1000
|
||||
|
||||
# --- jellystat-db (postgres:16-alpine) ---
|
||||
POSTGRES_DB=jfstat
|
||||
POSTGRES_USER=jellystat
|
||||
POSTGRES_PASSWORD=bf2d47d8e1a87baf2b4942704a5acfaf5c2aad336fdd480e
|
||||
|
||||
# --- jellystat ---
|
||||
POSTGRES_IP=jellystat-db
|
||||
POSTGRES_PORT=5432
|
||||
JWT_SECRET=0dd9fcdb632277b76977dbada8226e547cc773e1deafc8d778d4038f8d59393b
|
||||
|
||||
# --- jellyplex-watched ---
|
||||
# Plex is host-native, not containerised, so it is reached on the LAN IP.
|
||||
PLEX_URL=http://192.168.1.69:32400
|
||||
PLEX_TOKEN=hM9aycswHKSsUrxiHqwq
|
||||
JELLYFIN_BASEURL=http://jellyfin:8096
|
||||
JELLYFIN_TOKEN=
|
||||
SYNC_FROM_PLEX_TO_JELLYFIN=True
|
||||
SYNC_FROM_JELLYFIN_TO_PLEX=True
|
||||
# Start in dry-run. Task 16 flips this to False after the mapping is verified.
|
||||
DRYRUN=True
|
||||
SLEEP_DURATION=21600
|
||||
LOG_LEVEL=INFO
|
||||
Reference in New Issue
Block a user