services: jellyfin: image: jellyfin/jellyfin:latest container_name: jellyfin restart: unless-stopped environment: - PUID=1000 - PGID=1000 - TZ=Europe/Berlin volumes: - ./config/jellyfin:/config - ./cache/jellyfin:/cache # Hetzner Storage Box - all media served from here - /mnt/hetzner-media/media:/media networks: - media-network - traefik-public labels: - "traefik.enable=true" - "traefik.http.routers.jellyfin.rule=Host(`movies.jeffemmett.com`) || Host(`movies.jefflix.lol`)" - "traefik.http.routers.jellyfin.entrypoints=web" - "traefik.http.routers.jellyfin.middlewares=jellyfin-headers" - "traefik.http.services.jellyfin.loadbalancer.server.port=8096" - "traefik.http.middlewares.jellyfin-headers.headers.customRequestHeaders.X-Forwarded-Proto=https" - "traefik.docker.network=traefik-public" # Request Management - User-facing interface for media requests jellyseerr: image: fallenbagel/jellyseerr:latest container_name: jellyseerr restart: unless-stopped environment: - LOG_LEVEL=debug - TZ=Europe/Berlin volumes: - ./config/jellyseerr:/app/config networks: - media-network - traefik-public labels: - "traefik.enable=true" - "traefik.http.routers.jellyseerr.rule=Host(`requests.jefflix.lol`)" - "traefik.http.routers.jellyseerr.entrypoints=web" - "traefik.http.routers.jellyseerr.middlewares=jellyseerr-headers" - "traefik.http.services.jellyseerr.loadbalancer.server.port=5055" - "traefik.http.middlewares.jellyseerr-headers.headers.customRequestHeaders.X-Forwarded-Proto=https" - "traefik.docker.network=traefik-public" navidrome: image: deluan/navidrome:latest container_name: navidrome restart: unless-stopped user: 1000:1000 environment: - ND_SCANSCHEDULE=1h - ND_LOGLEVEL=info - ND_SESSIONTIMEOUT=24h - ND_BASEURL= - ND_ENABLETRANSCODINGCONFIG=true - ND_TRANSCODINGCACHESIZE=1GB - ND_IMAGECACHESIZE=500MB volumes: - ./config/navidrome:/data # Hetzner Storage Box - music library - /mnt/hetzner-media/media/music:/music:ro networks: - media-network - music-net labels: # Traefik disabled — traffic routed through soulsync-player container - "traefik.enable=false" sonarr: image: linuxserver/sonarr:latest container_name: sonarr restart: unless-stopped environment: - PUID=1000 - PGID=1000 - TZ=Europe/Berlin volumes: - ./config/sonarr:/config # Hetzner Storage Box - TV shows and downloads - /mnt/hetzner-media/media/shows:/tv - /mnt/hetzner-media/downloads:/downloads networks: - media-network - traefik-public labels: - "traefik.enable=true" - "traefik.http.routers.sonarr.rule=Host(`sonarr.jefflix.lol`)" - "traefik.http.routers.sonarr.entrypoints=web" - "traefik.http.services.sonarr.loadbalancer.server.port=8989" - "traefik.docker.network=traefik-public" radarr: image: linuxserver/radarr:latest container_name: radarr restart: unless-stopped environment: - PUID=1000 - PGID=1000 - TZ=Europe/Berlin volumes: - ./config/radarr:/config # Hetzner Storage Box - movies and downloads - /mnt/hetzner-media/media/movies:/movies - /mnt/hetzner-media/downloads:/downloads networks: - media-network - traefik-public labels: - "traefik.enable=true" - "traefik.http.routers.radarr.rule=Host(`radarr.jefflix.lol`)" - "traefik.http.routers.radarr.entrypoints=web" - "traefik.http.services.radarr.loadbalancer.server.port=7878" - "traefik.docker.network=traefik-public" prowlarr: image: linuxserver/prowlarr:latest container_name: prowlarr restart: unless-stopped environment: - PUID=1000 - PGID=1000 - TZ=Europe/Berlin volumes: - ./config/prowlarr:/config networks: - media-network - traefik-public labels: - "traefik.enable=true" - "traefik.http.routers.prowlarr.rule=Host(`prowlarr.jefflix.lol`)" - "traefik.http.routers.prowlarr.entrypoints=web" - "traefik.http.services.prowlarr.loadbalancer.server.port=9696" - "traefik.docker.network=traefik-public" lidarr: image: linuxserver/lidarr:latest container_name: lidarr restart: unless-stopped environment: - PUID=1000 - PGID=1000 - TZ=Europe/Berlin volumes: - ./config/lidarr:/config # Hetzner Storage Box - music and downloads - /mnt/hetzner-media/media/music:/music - /mnt/hetzner-media/downloads:/downloads networks: - media-network - traefik-public labels: - "traefik.enable=true" - "traefik.http.routers.lidarr.rule=Host(`lidarr.jefflix.lol`)" - "traefik.http.routers.lidarr.entrypoints=web" - "traefik.http.services.lidarr.loadbalancer.server.port=8686" - "traefik.docker.network=traefik-public" # VPN for download privacy (optional - enable in .env) gluetun: image: qmcgaw/gluetun:latest container_name: gluetun restart: unless-stopped cap_add: - NET_ADMIN devices: - /dev/net/tun:/dev/net/tun environment: - VPN_SERVICE_PROVIDER=${VPN_PROVIDER:-mullvad} - VPN_TYPE=wireguard - WIREGUARD_PRIVATE_KEY=${VPN_WIREGUARD_PRIVATE_KEY:-} - WIREGUARD_ADDRESSES=${VPN_WIREGUARD_ADDRESS:-} - SERVER_COUNTRIES=${VPN_COUNTRY:-Germany} - TZ=Europe/Berlin volumes: - ./config/gluetun:/gluetun ports: # qBittorrent WebUI - 8080:8080 # BitTorrent ports - 6881:6881 - 6881:6881/udp networks: - media-network profiles: - vpn # Download client - downloads directly to Hetzner Storage Box qbittorrent: image: linuxserver/qbittorrent:latest container_name: qbittorrent restart: unless-stopped environment: - PUID=1000 - PGID=1000 - TZ=Europe/Berlin - WEBUI_PORT=8080 volumes: - ./config/qbittorrent:/config # Hetzner Storage Box - all downloads go here - /mnt/hetzner-media/downloads:/downloads # When VPN enabled, use gluetun network # network_mode: "service:gluetun" networks: - media-network - traefik-public labels: - "traefik.enable=true" - "traefik.http.routers.qbittorrent.rule=Host(`downloads.jefflix.lol`)" - "traefik.http.routers.qbittorrent.entrypoints=web" - "traefik.http.services.qbittorrent.loadbalancer.server.port=8080" - "traefik.docker.network=traefik-public" # User Invitation System - Generate invite links for friends wizarr: image: ghcr.io/wizarrrr/wizarr:latest container_name: wizarr restart: unless-stopped environment: - APP_URL=https://invite.jefflix.lol - TZ=Europe/Berlin volumes: - ./config/wizarr:/data/database networks: - media-network - traefik-public labels: - "traefik.enable=true" - "traefik.http.routers.wizarr.rule=Host(`invite.jeffemmett.com`) || Host(`invite.jefflix.lol`)" - "traefik.http.routers.wizarr.entrypoints=web" - "traefik.http.routers.wizarr.middlewares=wizarr-headers" - "traefik.http.routers.wizarr.priority=1" - "traefik.http.services.wizarr.loadbalancer.server.port=5690" - "traefik.http.middlewares.wizarr-headers.headers.customRequestHeaders.X-Forwarded-Proto=https" - "traefik.http.routers.wizarr-root.rule=(Host(`invite.jefflix.lol`) && Path(`/`))" - "traefik.http.routers.wizarr-root.entrypoints=web" - "traefik.http.routers.wizarr-root.middlewares=wizarr-root-redirect" - "traefik.http.routers.wizarr-root.priority=10" - "traefik.http.middlewares.wizarr-root-redirect.redirectregex.regex=^https?://invite.jefflix.lol/?$" - "traefik.http.middlewares.wizarr-root-redirect.redirectregex.replacement=https://invite.jefflix.lol/j/RA05YZFRGD" - "traefik.http.middlewares.wizarr-root-redirect.redirectregex.permanent=false" - "traefik.docker.network=traefik-public" # Legacy Transmission (kept for compatibility, prefer qBittorrent) transmission: image: linuxserver/transmission:latest container_name: transmission restart: unless-stopped environment: - PUID=1000 - PGID=1000 - TZ=Europe/Berlin - TRANSMISSION_WEB_HOME=/web volumes: - ./config/transmission:/config - /mnt/hetzner-media/downloads:/downloads - ./watch:/watch ports: - 9091:9091 - 51413:51413 - 51413:51413/udp networks: - media-network profiles: - legacy # File Browser - Web upload interface for community contributions filebrowser: image: filebrowser/filebrowser:latest container_name: filebrowser restart: unless-stopped user: "0:0" environment: - TZ=Europe/Berlin - FB_PORT=8080 - FB_ADDRESS=0.0.0.0 volumes: - /mnt/hetzner-media/uploads:/srv/uploads - ./config/filebrowser:/database - ./config/filebrowser/settings.json:/config/settings.json:ro command: - --root=/srv/uploads - --database=/database/filebrowser.db - --address=0.0.0.0 - --port=8080 healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8080/health"] interval: 30s timeout: 10s retries: 3 start_period: 10s labels: - "traefik.enable=true" - "traefik.http.routers.filebrowser.rule=Host(`upload.jefflix.lol`)" - "traefik.http.routers.filebrowser.entrypoints=web" - "traefik.http.routers.filebrowser.middlewares=filebrowser-headers" - "traefik.http.services.filebrowser.loadbalancer.server.port=8080" - "traefik.http.middlewares.filebrowser-headers.headers.customRequestHeaders.X-Forwarded-Proto=https" - "traefik.docker.network=traefik-public" networks: - media-network - traefik-public networks: media-network: driver: bridge music-net: external: true traefik-public: external: true