{ pkgs, config, service_configs, lib, ... }: { imports = [ (lib.serviceMountWithZpool "jellyfin" service_configs.zpool_ssds [ config.services.jellyfin.dataDir config.services.jellyfin.cacheDir ]) ]; services.jellyfin = { enable = true; # used for local streaming openFirewall = true; package = pkgs.jellyfin.override { jellyfin-ffmpeg = (lib.optimizePackage pkgs.jellyfin-ffmpeg); }; inherit (service_configs.jellyfin) dataDir cacheDir; }; services.caddy.virtualHosts."jellyfin.${service_configs.https.domain}".extraConfig = '' reverse_proxy :${builtins.toString service_configs.ports.jellyfin} { header_up X-Real-IP {remote_host} header_up X-Forwarded-For {remote_host} header_up X-Forwarded-Proto {scheme} } request_body { max_size 4096MB } ''; systemd.tmpfiles.rules = [ "Z ${config.services.jellyfin.dataDir} 0700 ${config.services.jellyfin.user} ${config.services.jellyfin.group}" "Z ${config.services.jellyfin.cacheDir} 0700 ${config.services.jellyfin.user} ${config.services.jellyfin.group}" ]; users.users.${config.services.jellyfin.user}.extraGroups = [ "video" "render" service_configs.media_group ]; # Protect Jellyfin login from brute force attacks services.fail2ban.jails.jellyfin = { enabled = true; settings = { backend = "auto"; port = "http,https"; logpath = "${config.services.jellyfin.dataDir}/log/log_*.log"; # defaults: maxretry=5, findtime=10m, bantime=10m }; filter.Definition = { failregex = ''^.*Authentication request for .* has been denied \(IP: ""\)\..*$''; ignoreregex = ""; }; }; }