services: # Jellyfin — open source media server (recommended) jellyfin: profiles: ["jellyfin"] image: lscr.io/linuxserver/jellyfin:10.11.11 container_name: jellyfin environment: - PUID=${PUID} - PGID=${PGID} - TZ=${TZ} - VERSION=docker volumes: - /etc/localtime:/etc/localtime:ro - ${MEDIA_DIRECTORY}:/data - ${INSTALL_DIRECTORY}/config/jellyfin:/config ports: - 8096:8096 healthcheck: test: ["CMD", "curl", "-sf", "http://127.0.0.1:8096/health"] interval: 10s timeout: 5s retries: 3 start_period: 30s start_interval: 2s restart: unless-stopped networks: assemblrr_network: ipv4_address: 172.60.0.11 # Emby — UNSUPPORTED optional profile (express/default is Jellyfin only). emby: profiles: ["emby"] image: lscr.io/linuxserver/emby container_name: emby environment: - PUID=${PUID} - PGID=${PGID} - TZ=${TZ} - VERSION=docker volumes: - /etc/localtime:/etc/localtime:ro - ${MEDIA_DIRECTORY}:/data - ${INSTALL_DIRECTORY}/config/emby:/config ports: - 8096:8096 healthcheck: test: ["CMD", "curl", "-sf", "http://127.0.0.1:8096/emby/System/Ping"] interval: 10s timeout: 5s retries: 3 start_period: 30s start_interval: 2s restart: unless-stopped networks: assemblrr_network: ipv4_address: 172.60.0.11 # Plex — UNSUPPORTED optional profile (express/default is Jellyfin only). plex: profiles: ["plex"] image: lscr.io/linuxserver/plex container_name: plex network_mode: host environment: - PUID=${PUID} - PGID=${PGID} - TZ=${TZ} - VERSION=docker volumes: - /etc/localtime:/etc/localtime:ro - ${MEDIA_DIRECTORY}:/data - ${INSTALL_DIRECTORY}/config/plex:/config restart: unless-stopped healthcheck: test: ["CMD", "curl", "-sf", "http://127.0.0.1:32400/identity"] interval: 10s timeout: 5s retries: 3 start_period: 30s start_interval: 2s # qBittorrent — torrent client (ports added by overlay) qbittorrent: image: lscr.io/linuxserver/qbittorrent:5.2.3 container_name: qbittorrent environment: - PUID=${PUID} - PGID=${PGID} - TZ=${TZ} - WEBUI_PORT=8081 volumes: - /etc/localtime:/etc/localtime:ro - ${MEDIA_DIRECTORY}:/data - ${INSTALL_DIRECTORY}/config/qbittorrent:/config restart: unless-stopped healthcheck: test: ["CMD", "curl", "-sf", "http://127.0.0.1:8081"] interval: 5s timeout: 3s retries: 3 start_period: 20s start_interval: 2s # Sonarr — TV show management and automation sonarr: image: lscr.io/linuxserver/sonarr:4.0.19.2979-ls321 container_name: sonarr environment: - PUID=${PUID} - PGID=${PGID} - TZ=${TZ} volumes: - /etc/localtime:/etc/localtime:ro - ${MEDIA_DIRECTORY}:/data - ${INSTALL_DIRECTORY}/config/sonarr:/config - ${INSTALL_DIRECTORY}/scripts:/scripts:ro - ${INSTALL_DIRECTORY}/secrets:/run/secrets:ro ports: - 8989:8989 healthcheck: test: ["CMD", "curl", "-sf", "http://127.0.0.1:8989/ping"] interval: 10s timeout: 5s retries: 3 start_period: 60s start_interval: 2s restart: unless-stopped networks: assemblrr_network: ipv4_address: 172.60.0.13 # Radarr — movie management and automation radarr: image: lscr.io/linuxserver/radarr:6.3.0.10514-ls313 container_name: radarr environment: - PUID=${PUID} - PGID=${PGID} - TZ=${TZ} volumes: - /etc/localtime:/etc/localtime:ro - ${MEDIA_DIRECTORY}:/data - ${INSTALL_DIRECTORY}/config/radarr:/config - ${INSTALL_DIRECTORY}/scripts:/scripts:ro - ${INSTALL_DIRECTORY}/secrets:/run/secrets:ro ports: - 7878:7878 healthcheck: test: ["CMD", "curl", "-sf", "http://127.0.0.1:7878/ping"] interval: 10s timeout: 5s retries: 3 start_period: 60s start_interval: 2s restart: unless-stopped networks: assemblrr_network: ipv4_address: 172.60.0.14 # Prowlarr — indexer management for *arr apps prowlarr: image: lscr.io/linuxserver/prowlarr:2.5.2.5491-ls156 container_name: prowlarr environment: - PUID=${PUID} - PGID=${PGID} - TZ=${TZ} volumes: - /etc/localtime:/etc/localtime:ro - ${INSTALL_DIRECTORY}/config/prowlarr:/config ports: - 9696:9696 healthcheck: test: ["CMD", "curl", "-sf", "http://127.0.0.1:9696/ping"] interval: 10s timeout: 5s retries: 3 start_period: 60s start_interval: 2s restart: unless-stopped networks: assemblrr_network: ipv4_address: 172.60.0.15 # Seerr — media request management (successor to Jellyseerr/Overseerr) # Host port 5055 is published by seerr-gateway (not seerr) so DELETE /request # can cancel in-flight *arr/qB grabs. Seerr stays on the Docker network only. # Retirement: see docs/seerr-delete-request.md seerr: image: ghcr.io/seerr-team/seerr:v3.4.1 container_name: seerr init: true environment: - TZ=${TZ} volumes: - /etc/localtime:/etc/localtime:ro - ${INSTALL_DIRECTORY}/config/seerr:/app/config expose: - "5055" healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5055/api/v1/settings/public"] interval: 10s timeout: 5s retries: 5 start_period: 60s start_interval: 2s restart: unless-stopped networks: assemblrr_network: ipv4_address: 172.60.0.17 # Thin reverse proxy in front of Seerr: pass-through + delete-request queue drain. # TV: season-scoped via Sonarr when the request is a subset of remaining seasons. # SEERR_DELETE_REQUEST_PURGE=0 disables intercept (stock Seerr semantics). seerr-gateway: image: python:3.12.14-alpine container_name: seerr-gateway environment: - TZ=${TZ} - SEERR_UPSTREAM=http://seerr:5055 - SEERR_GATEWAY_LISTEN=0.0.0.0 - SEERR_GATEWAY_PORT=5055 - SEERR_DELETE_REQUEST_PURGE=${SEERR_DELETE_REQUEST_PURGE:-1} - SONARR_URL=http://sonarr:8989 - SONARR_CONFIG=/config/sonarr/config.xml - RADARR_URL=http://radarr:7878 - RADARR_CONFIG=/config/radarr/config.xml volumes: - /etc/localtime:/etc/localtime:ro - ${INSTALL_DIRECTORY}/scripts/seerr-gateway.py:/scripts/seerr-gateway.py:ro # Bind the dir, not config.xml — Docker creates a directory if the file is missing. - ${INSTALL_DIRECTORY}/config/sonarr:/config/sonarr:ro - ${INSTALL_DIRECTORY}/config/radarr:/config/radarr:ro ports: - 5055:5055 depends_on: seerr: condition: service_healthy healthcheck: test: [ "CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:5055/_assemblrr/ready', timeout=5)", ] interval: 10s timeout: 5s retries: 3 start_period: 30s start_interval: 2s command: ["python3", "/scripts/seerr-gateway.py"] restart: unless-stopped networks: assemblrr_network: ipv4_address: 172.60.0.24 # Recyclarr - automatically syncs TRaSH guides # :latest is no longer published; pin a 8.x release (see recyclarr.dev). recyclarr: image: ghcr.io/recyclarr/recyclarr:8.7.1 container_name: recyclarr user: ${PUID}:${PGID} environment: - TZ=${TZ} - CRON_SCHEDULE=@daily volumes: - /etc/localtime:/etc/localtime:ro - ${INSTALL_DIRECTORY}/config/recyclarr:/config restart: unless-stopped networks: assemblrr_network: ipv4_address: 172.60.0.18 # Deletes under /data/media → purge *arr entry + qB torrent/files media-purge-watch: image: assemblrr/media-purge-watch:local pull_policy: build build: context: ${INSTALL_DIRECTORY}/compose/sidecars dockerfile: media-purge-watch.Dockerfile container_name: media-purge-watch environment: - TZ=${TZ} - MEDIA_ROOT=/data - CONFIG_DIR=/config - RADARR_URL=http://radarr:7878 - SONARR_URL=http://sonarr:8989 - AUTH_USERNAME_FILE=/run/secrets/auth_username.txt - AUTH_PASSWORD_FILE=/run/secrets/auth_password.txt - MEDIA_PURGE_WATCH=${MEDIA_PURGE_WATCH:-1} volumes: - /etc/localtime:/etc/localtime:ro - ${MEDIA_DIRECTORY}:/data - ${INSTALL_DIRECTORY}/config:/config:ro - ${INSTALL_DIRECTORY}/scripts:/scripts:ro - ${INSTALL_DIRECTORY}/secrets:/run/secrets:ro command: ["/scripts/media-purge-watch.sh"] restart: unless-stopped networks: assemblrr_network: ipv4_address: 172.60.0.23 # Bazarr — automatic subtitle management (Sonarr/Radarr companion) bazarr: image: lscr.io/linuxserver/bazarr:1.6.0 container_name: bazarr environment: - PUID=${PUID} - PGID=${PGID} - TZ=${TZ} volumes: - /etc/localtime:/etc/localtime:ro - ${MEDIA_DIRECTORY}:/data - ${INSTALL_DIRECTORY}/config/bazarr:/config ports: - 6767:6767 healthcheck: test: ["CMD", "curl", "-sf", "http://127.0.0.1:6767/api/system/ping"] interval: 10s timeout: 5s retries: 3 start_period: 30s start_interval: 2s restart: unless-stopped networks: assemblrr_network: ipv4_address: 172.60.0.22 networks: assemblrr_network: name: assemblrr_network ipam: config: - subnet: 172.60.0.0/24