diff --git a/hosts/index/config/web/immich.nix b/hosts/index/config/web/immich.nix new file mode 100644 index 0000000..899b3e8 --- /dev/null +++ b/hosts/index/config/web/immich.nix @@ -0,0 +1,35 @@ +{ flakeRoot, ... }: + +let + host = "photos.encrypted.group"; + + immichModule = import (flakeRoot + /packages/server/web/immich.nix) { + hosts = [ + { + name = "immich.lan"; + ssl = "internal"; + } + { + name = host; + ssl = "cloudflare"; + } + ]; + }; +in +{ + imports = [ + immichModule + ]; + + services.immich = { + settings = { + server = { + externalDomain = "https://${host}"; + }; + }; + + mediaLocation = "/mnt/data/immich"; + }; + + systemd.services.immich-server.serviceConfig.ReadWritePaths = [ "/mnt/data/immich" ]; +} diff --git a/hosts/index/default.nix b/hosts/index/default.nix index c4faeda..a212112 100644 --- a/hosts/index/default.nix +++ b/hosts/index/default.nix @@ -40,6 +40,7 @@ ./config/web/caddy.nix ./config/web/forgejo.nix + ./config/web/immich.nix ./config/web/miniflux.nix ./config/web/searx.nix ./config/web/vaultwarden.nix diff --git a/packages/server/web/immich.nix b/packages/server/web/immich.nix new file mode 100644 index 0000000..9512208 --- /dev/null +++ b/packages/server/web/immich.nix @@ -0,0 +1,90 @@ +{ + hosts ? [ ], +}: + +{ + config, + flakeLib, + ... +}: + +let + videoDevice = "/dev/dri/renderD128"; +in +{ + imports = [ + ../databases/postgresql.nix + ../databases/redis.nix + ]; + + services.immich = { + enable = true; + + host = "127.0.0.1"; + + accelerationDevices = [ videoDevice ]; + + database = { + enableVectors = false; + enableVectorChord = true; + }; + + settings = { + trash.days = 31; + + image = { + thumbnail = { + size = 240; + quality = 50; + }; + + preview = { + format = "webp"; + size = 1080; + quality = 75; + }; + }; + + ffmpeg = { + acceptedContainers = [ "webm" ]; + acceptedVideoCodecs = [ "hevc" "vp9" "av1" ]; + acceptedAudioCodecs = [ "libopus" ]; + + targetVideoCodec = "hevc"; + targetAudioCodec = "libopus"; + + crf = 31; + #maxBitrate = 2600; + twoPass = true; + + # assumes AMD GPU, to modularize + accel = "vaapi"; + preferredHwDevice = videoDevice; + accelDecode = true; + }; + + machineLearning = { + # Assumes the machine is powerful, while balancing speed + # "ViT-B-32__laion2b-s34b-b79k" uses a third of the memory and is ~twice as fast, but is ~10% less accurate + clip.modelName = "ViT-B-16-SigLIP2__webli"; + + facialRecognition = { + # Largest model, generally very accurate + modelName = "antelopev2"; + + minScore = 0.5; + minFaces = 5; + }; + }; + + # Assumes we're keeping copies elsewhere (zfs snapshots) + backup.database.enabled = false; + }; + }; + + users.users.immich.extraGroups = [ "video" "render" ]; + + services.caddy.virtualHosts = flakeLib.mkProxies hosts '' + reverse_proxy :${toString config.services.immich.port} + ''; +}