{ config , pkgs , lib , ... }: { options.services.immich-server = { enable = lib.mkEnableOption "Immich photo management server"; port = lib.mkOption { type = lib.types.port; default = 2283; description = "Port for Immich server"; }; mediaLocation = lib.mkOption { type = lib.types.path; default = "/data/immich"; description = "Directory for storing uploaded photos and videos"; }; }; config = lib.mkIf config.services.immich-server.enable { services.immich = { enable = true; host = "0.0.0.0"; port = config.services.immich-server.port; mediaLocation = config.services.immich-server.mediaLocation; # Firewall is managed by the host (homeserver-1 restricts to tailscale). openFirewall = false; # Restrict hardware-acceleration access to the explicit NVIDIA device # nodes needed for NVENC/CUDA transcoding (GTX 960). null would grant # access to ALL devices; an explicit list is the secure alternative. accelerationDevices = [ "/dev/nvidia0" "/dev/nvidiactl" "/dev/nvidia-modeset" "/dev/nvidia-uvm" "/dev/nvidia-uvm-tools" ]; }; # The upstream services.immich module creates a tmpfiles `e` rule that # sets the media directory to 0700 on every rebuild/switch. Setting that # mode clobbers the POSIX ACL mask (to `---`), which in turn nullifies the # `user:backrest` read ACL that lets the backup service read this directory. # Override it to keep the directory group-readable/traversable so the ACL # mask stays effective (matches the rule just above). systemd.tmpfiles.settings.immich.${config.services.immich-server.mediaLocation}.e.mode = lib.mkForce "0770"; systemd.tmpfiles.rules = [ "d ${config.services.immich-server.mediaLocation} 0770 immich immich -" ]; }; }