From a0f178530d937c85fdfbc0392be4ff3846351655 Mon Sep 17 00:00:00 2001 From: Tom Vincent Date: Wed, 22 Oct 2025 09:12:07 +0100 Subject: [PATCH] nixos/immich-kiosk: init module --- nixos/modules/module-list.nix | 1 + .../services/web-apps/immich-kiosk.nix | 132 ++++++++++++++++++ nixos/tests/all-tests.nix | 1 + nixos/tests/web-apps/immich-kiosk.nix | 31 ++++ 4 files changed, 165 insertions(+) create mode 100644 nixos/modules/services/web-apps/immich-kiosk.nix create mode 100644 nixos/tests/web-apps/immich-kiosk.nix diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 50323f0dd888..c05bdb3b5149 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1628,6 +1628,7 @@ ./services/web-apps/icingaweb2/icingaweb2.nix ./services/web-apps/icingaweb2/module-monitoring.nix ./services/web-apps/ifm.nix + ./services/web-apps/immich-kiosk.nix ./services/web-apps/immich-public-proxy.nix ./services/web-apps/immich.nix ./services/web-apps/invidious.nix diff --git a/nixos/modules/services/web-apps/immich-kiosk.nix b/nixos/modules/services/web-apps/immich-kiosk.nix new file mode 100644 index 000000000000..97aef228d73b --- /dev/null +++ b/nixos/modules/services/web-apps/immich-kiosk.nix @@ -0,0 +1,132 @@ +{ + config, + lib, + pkgs, + utils, + ... +}: +let + cfg = config.services.immich-kiosk; + format = pkgs.formats.json { }; + secretsReplacement = utils.genJqSecretsReplacement { + loadCredential = true; + } cfg.settings "/run/immich-kiosk/config.yaml"; +in +{ + meta.maintainers = with lib.maintainers; [ tlvince ]; + + options.services.immich-kiosk = { + enable = lib.mkEnableOption "Immich Kiosk slideshow service"; + + package = lib.mkPackageOption pkgs "immich-kiosk" { }; + + openFirewall = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether to open the firewall for the immich-kiosk port. + ''; + }; + + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = format.type; + options = { + immich_url = lib.mkOption { + type = lib.types.str; + default = config.services.immich.settings.server.externalDomain; + defaultText = lib.literalExpression "config.services.immich.settings.server.externalDomain"; + description = '' + URL of the immich instance. + ''; + }; + + kiosk.port = lib.mkOption { + type = lib.types.port; + default = 3000; + description = '' + Port on which immich-kiosk will listen. + ''; + }; + }; + }; + default = { }; + description = '' + Configuration for immich-kiosk. See + + for available options. Secret values can be loaded from files using + `._secret = "/path/to/secret";`. + ''; + example = lib.literalExpression '' + { + immich_url = "https://immich.example.com"; + immich_api_key._secret = "/run/secrets/immich-kiosk-api-key"; + albums = [ + "4fa933cf-051f-4621-9ac7-8d06776c261c" + "6466548c-4995-4fb5-ab1f-f63cc9ff3e5f" + ]; + duration = 30; + layout = "splitview"; + disable_ui = true; + } + ''; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.immich-kiosk = { + description = "Immich Kiosk slideshow service"; + after = [ "immich-server.service" ]; + wantedBy = [ "multi-user.target" ]; + + preStart = secretsReplacement.script; + + serviceConfig = { + DynamicUser = true; + ExecStart = lib.getExe cfg.package; + Group = "immich-kiosk"; + LoadCredential = secretsReplacement.credentials; + Restart = "on-failure"; + RestartSec = 10; + RuntimeDirectory = "immich-kiosk"; + RuntimeDirectoryMode = "0700"; + SyslogIdentifier = "immich-kiosk"; + Type = "simple"; + User = "immich-kiosk"; + WorkingDirectory = "/run/immich-kiosk"; + + # Hardening + CapabilityBoundingSet = [ "" ]; + LockPersonality = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + PrivateUsers = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + "~@resources" + ]; + UMask = "0077"; + }; + }; + + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.settings.kiosk.port ]; + }; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 9902d3e7e686..ee5b31bc8872 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -752,6 +752,7 @@ in iftop = runTest ./iftop.nix; image-contents = handleTest ./image-contents.nix { }; immich = runTest ./web-apps/immich.nix; + immich-kiosk = runTest ./web-apps/immich-kiosk.nix; immich-public-proxy = runTest ./web-apps/immich-public-proxy.nix; immich-vectorchord-migration = runTest ./web-apps/immich-vectorchord-migration.nix; immich-vectorchord-reindex = runTest ./web-apps/immich-vectorchord-reindex.nix; diff --git a/nixos/tests/web-apps/immich-kiosk.nix b/nixos/tests/web-apps/immich-kiosk.nix new file mode 100644 index 000000000000..0679d78b636d --- /dev/null +++ b/nixos/tests/web-apps/immich-kiosk.nix @@ -0,0 +1,31 @@ +{ ... }: +{ + name = "immich-kiosk"; + + nodes.machine = + { pkgs, ... }: + { + environment.systemPackages = [ pkgs.jq ]; + + services.immich-kiosk = { + enable = true; + settings = { + immich_url = "http://localhost:2283"; + immich_api_key = { + _secret = pkgs.writeText "immich-kiosk-api-key" "dummy-api-key"; + }; + kiosk = { + port = 3100; + demo_mode = true; + }; + }; + }; + }; + + testScript = '' + machine.wait_for_unit("immich-kiosk.service") + machine.wait_for_open_port(3100) + machine.succeed("pgrep -x immich-kiosk") + machine.succeed("jq -r .immich_api_key /run/immich-kiosk/config.yaml | grep dummy-api-key") + ''; +}