{ config, containerCfg, pkgs, lib, builder, name, ... }: let serverCfg = config.syscfg.server; LDAP_DC_DOMAIN = "dc=ldap," + (lib.concatMapStringsSep "," (x: "dc=${x}") (lib.splitString "." serverCfg.hostDomain)); nss = pkgs.dockerTools.fakeNss.override { extraPasswdLines = [ "jellyfin:x:1000:1000:Jellyfin Daemon:/config/data:/bin/false" ]; extraGroupLines = [ "jellyfin:x:1000:" ]; }; image = pkgs.dockerTools.streamLayeredImage { # pkgs.dockerTools.buildImage{# name = pkgs.jellyfin.name; tag = pkgs.jellyfin.version; contents = [ pkgs.cacert nss pkgs.jellyfin pkgs.bashInteractive ]; config = { User = "jellyfin:jellyfin"; Entrypoint = [ "${pkgs.jellyfin}/bin/jellyfin" ]; ExposedPorts = { "8096/tcp" = { }; }; Env = [ "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" "NIX_SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" ]; }; }; in { paths = [ { path = "${serverCfg.dataPath}/media/"; owner = "1000:1000"; mode = "0755"; } { path = "${serverCfg.configPath}/jellyfin/"; owner = "1000:1000"; mode = "0755"; } ]; containers = { server = builder.mkContainer { subdomain = containerCfg.subdomain; imageStream = image; port = 8096; extraEnv = { HOME = "/config/data"; DOTNET_SYSTEM_GLOBALIZATION_INVARIANT = "1"; JELLYFIN_HttpListenerHost__BindAddress= "0.0.0.0"; #we can use settings.xml override JELLYFIN_ServerName = if containerCfg.extra?name then containerCfg.extra.name else "Flix"; }; extraOptions = [ "--tmpfs=/tmp:rw,noexec,nosuid,size=512m" ]; overrides = { cmd = [ "--datadir" "/config/data" "--cachedir" "/config/cache" "--configdir" "/config/config" "--logdir" "/config/log" ]; volumes = [ "${serverCfg.dataPath}/media:/media:ro" "${serverCfg.configPath}/jellyfin:/config" ]; # If you have an Intel/AMD GPU for transcoding, add the device: devices = lib.optionals (builtins.pathExists "/dev/dri") [ "/dev/dri:/dev/dri" ]; }; }; }; setup = { trigger = "server"; envFile = config.sops.secrets."CUSTOM".path; script = pkgs.writeShellScript "setup" '' JELLYFIN_URL="https://${containerCfg.subdomain}.${serverCfg.hostDomain}" until [ "$(${pkgs.curl}/bin/curl -sf "$JELLYFIN_URL/health")" = "Healthy" ]; do sleep 5 done echo "Jellyfin is up. Sleeping for 20 seconds..." sleep 20 WIZARD_COMPLETE=$(${pkgs.curl}/bin/curl -sSf "$JELLYFIN_URL/System/Info/Public" 2>/dev/null | \ ${pkgs.jq}/bin/jq -r '.StartupWizardCompleted // false') if [ "$WIZARD_COMPLETE" = "false" ]; then if ! ${pkgs.curl}/bin/curl -sSf -X POST "$JELLYFIN_URL/Startup/Configuration" \ -H "Content-Type: application/json" \ -d '{"ServerName":"Flix","UICulture":"en-US","MetadataCountryCode":"US","PreferredMetadataLanguage":"en"}'; then echo "ERROR: Failed to set startup configuration." exit 1 fi SETUP_USER_PAYLOAD=$(${pkgs.jq}/bin/jq -n \ --arg name "$DEFAULT_ADMIN_USERNAME" \ --arg pass "$DEFAULT_ADMIN_PASSWORD" \ '{"Name": $name, "Password": $pass}') if ! ${pkgs.curl}/bin/curl -sSf -X GET "$JELLYFIN_URL/Startup/User"; then echo "ERROR: Failed to get base user." exit 1 fi if ! ${pkgs.curl}/bin/curl -sSf -X POST "$JELLYFIN_URL/Startup/User" \ -H 'accept: */*' \ -H "Content-Type: application/json" \ -d "$SETUP_USER_PAYLOAD"; then echo "ERROR: Failed to set admin user." exit 1 fi if ! ${pkgs.curl}/bin/curl -sSf -X POST "$JELLYFIN_URL/Startup/RemoteAccess" \ -H "Content-Type: application/json" \ -d '{"EnableRemoteAccess":true,"EnableAutomaticPortMapping":false}'; then echo "ERROR: Failed to configure remote access." exit 1 fi if ! ${pkgs.curl}/bin/curl -sSf -X POST "''$JELLYFIN_URL/Startup/Complete"; then echo "ERROR: Failed to complete wizard." exit 1 fi echo "Jellyfin initialization successfully completed!" fi JELLYFIN_TOKEN=$(${pkgs.curl}/bin/curl -sSf -X POST "$JELLYFIN_URL/Users/AuthenticateByName" \ -H "Content-Type: application/json" \ -H "Authorization: MediaBrowser Client=\"Bash Script\", Device=\"Server Terminal\", DeviceId=\"script-12345\", Version=\"1.0.0\"" \ -d "{\"Username\": \"$DEFAULT_ADMIN_USERNAME\", \"Pw\": \"$DEFAULT_ADMIN_PASSWORD\"}" \ | ${pkgs.jq}/bin/jq -r '.AccessToken') # Verify we got a token if [ "$JELLYFIN_TOKEN" = "null" ] || [ -z "$JELLYFIN_TOKEN" ]; then echo "ERROR: Authentication failed." exit 1 fi if ! ${pkgs.curl}/bin/curl -sSf -X POST "$JELLYFIN_URL/Packages/Installed/LDAP%20Authentication?assemblyGuid=958aad6637844d2ab89aa7b6fab6e25c" \ -H "Authorization: MediaBrowser Token=\"$JELLYFIN_TOKEN\"" \ -H "Content-Length: 0"; then echo "ERROR: LDAP Plugin Setup Failed." exit 1 fi if ! ${pkgs.curl}/bin/curl -sSf -X POST "$JELLYFIN_URL/System/Restart" \ -H "Authorization: MediaBrowser Token=\"$JELLYFIN_TOKEN\"" \ -H "Content-Length: 0"; then echo "ERROR: Server failed to accept restart command." exit 1 fi sleep 5 until [ "$(${pkgs.curl}/bin/curl -sf "$JELLYFIN_URL/health")" = "Healthy" ]; do sleep 5 done echo "Jellyfin is up. Sleeping for 20 seconds..." sleep 20 SETUP_LDAP_PAYLOAD=$(${pkgs.jq}/bin/jq -n \ --arg ldap_pass "$DEFAULT_LDAP_PASSWORD" \ '{"LdapUsers":[],"LdapServer":"authentik-ldap","LdapPort":6636,"UseSsl":true,"UseStartTls":false,"SkipSslVerify":true, "LdapBindUser":"cn=ldap-service,ou=users,${LDAP_DC_DOMAIN}","LdapBindPassword":$ldap_pass, "LdapBaseDn":"${LDAP_DC_DOMAIN}","LdapSearchFilter":"(memberOf=cn=flix,ou=groups,${LDAP_DC_DOMAIN})", "LdapSearchAttributes":"uid, cn, mail, displayName", "LdapAdminBaseDn":"","LdapAdminFilter":"(memberOf=cn=admin,ou=groups,${LDAP_DC_DOMAIN})", "EnableLdapAdminFilterMemberUid":false,"LdapUidAttribute":"uid","LdapUsernameAttribute":"cn","LdapPasswordAttribute":"userPassword", "EnableLdapProfileImageSync":false,"RemoveImagesNotInLdap":false,"LdapProfileImageAttribute":"jpegphoto","LdapProfileImageFormat":"Default", "LdapClientCertPath":"","LdapClientKeyPath":"","LdapRootCaPath":"","CreateUsersFromLdap":true,"AllowPassChange":false, "EnableAllFolders":true,"EnabledFolders":[],"PasswordResetUrl":""}') if ! ${pkgs.curl}/bin/curl -sSf -X POST "$JELLYFIN_URL/Plugins/958aad66-3784-4d2a-b89a-a7b6fab6e25c/Configuration" \ -H "Authorization: MediaBrowser Token=\"$JELLYFIN_TOKEN\"" \ -H "Content-Type: application/json" -H 'accept: */*' \ -d "$SETUP_USER_PAYLOAD"; then echo "ERROR: LDAP Plugin Setup Failed." exit 1 fi echo "Completed Setup" ''; }; }