175 lines
7.2 KiB
Nix
175 lines
7.2 KiB
Nix
{ 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
|
|
|
|
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 '{"Name": "$DEFAULT_ADMIN_USERNAME", "Password": "$DEFAULT_ADMIN_PASSWORD"}'; 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 -H "Authorization: MediaBrowser Token=\"$JELLYFIN_TOKEN\"" \
|
|
"$JELLYFIN_URL/Plugins" | ${pkgs.gnugrep}/bin/grep -q "958aad6637844d2ab89aa7b6fab6e25c"; then
|
|
echo "LDAP Plugin is already installed. Skipping setup."
|
|
else
|
|
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
|
|
fi
|
|
|
|
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 '{"LdapUsers":[],"LdapServer":"authentik-ldap","LdapPort":6636,"UseSsl":true,"UseStartTls":false,"SkipSslVerify":true,
|
|
"LdapBindUser":"cn=ldap-service,ou=users,${LDAP_DC_DOMAIN}","LdapBindPassword": "$DEFAULT_LDAP_PASSWORD",
|
|
"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":""}'; then
|
|
echo "ERROR: LDAP Plugin Setup Failed."
|
|
exit 1
|
|
fi
|
|
|
|
echo "Completed Setup"
|
|
|
|
'';
|
|
};
|
|
|
|
} |