immich: add the service and import the ZimaOS library
jupiter had a leftover docker-compose Immich on the RAID (/mnt/data/Immich, 9.9G) that survived the NixOS install. Native module now, media at /mnt/data/AppData/immich, caddy vhost on 2283 with a 50GB body limit (caddy's default rejects video uploads). The package comes from nixpkgs-unstable, the module from the 26.05 pin: 26.05 ships immich 2.7.5, but that database was last written by 3.0.0 and migrations only run forward -- corrupted migrations: previously executed migration 1776217577402-DropAuditTable is missing Safe because the two module files are byte-identical at these revisions; services/media/immich.nix carries the diff command to re-check on a bump. Drop the input once the stable pin ships >= 3.0.0. immich needs group "users" only to traverse /mnt/data/AppData (drwx--x---); its own dir stays 0700 immich:immich. mediaLocation is outside /var/lib, so the module's tmpfiles entry only ADJUSTS it -- add a rule that creates it. scripts/immich-import-legacy-db does the database half: boots a copy of the legacy PGDATA under the matching image (PG14 + vchord 0.3.0 + pgvector 0.8.1), dumps it with the local pg_dump 17, restores into a scratch DB, fixes ownership, and only swaps after confirmation. Never touches the original. The old cluster ran VectorChord, not pgvecto.rs, so the smart search and face embeddings survive -- no ML re-run. Imported: 666 assets, 25 people, 647 clip + 359 face embeddings, 2 users.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
{ pkgs, inputs, ... }:
|
||||
|
||||
# Immich photo/video library. Native nixpkgs module (not the upstream compose
|
||||
# stack) — it owns its own postgres (with the pgvector + vectorchord extensions
|
||||
# it needs for search) and a unix-socket redis, so nothing else is required here.
|
||||
#
|
||||
# Storage: everything lives under /mnt/data/AppData/immich, which is the media
|
||||
# store MIGRATED from the old ZimaOS/CasaOS install's UPLOAD_LOCATION
|
||||
# (/mnt/data/Immich/upload — same layout: library/ upload/ thumbs/
|
||||
# encoded-video/ profile/ backups/). See scripts/immich-import-legacy-db for the
|
||||
# matching database import. The postgres cluster itself stays on the OS disk.
|
||||
#
|
||||
# ⚠️ The immich DB is the only copy of albums/faces/dates — the files alone
|
||||
# can't rebuild it. It joins the other unbacked databases on this network.
|
||||
let
|
||||
# The PACKAGE comes from nixpkgs-unstable (3.0.3); the MODULE comes from the
|
||||
# 26.05 pin (which ships 2.7.5). That combination is safe because the two
|
||||
# module files are byte-identical — verified by diffing them at the revisions
|
||||
# in flake.lock. RE-CHECK THAT DIFF on any input bump:
|
||||
# diff <(nixpkgs)/nixos/modules/services/web-apps/immich.nix \
|
||||
# <(unstable)/nixos/modules/services/web-apps/immich.nix
|
||||
#
|
||||
# Why: jupiter's imported database was last written by immich 3.0.0, and
|
||||
# immich runs its migrations forward only — 2.7.5 refuses to start against it
|
||||
# with "corrupted migrations: previously executed migration
|
||||
# 1776217577402-DropAuditTable is missing". Drop this override once nixos-26.11
|
||||
# (or whatever the pin becomes) ships >= 3.0.0.
|
||||
unstable = import inputs.nixpkgs-unstable {
|
||||
inherit (pkgs.stdenv.hostPlatform) system;
|
||||
};
|
||||
in
|
||||
{
|
||||
services.immich = {
|
||||
enable = true;
|
||||
# Both the server and immich-machine-learning follow this: the module takes
|
||||
# the ML service from cfg.package.machine-learning (passthru).
|
||||
package = unstable.immich;
|
||||
# Listens on all interfaces: :2283 stays closed on the LAN (no
|
||||
# openFirewall), reachable over tailscale0 and via localhost (caddy).
|
||||
host = "0.0.0.0";
|
||||
port = 2283;
|
||||
mediaLocation = "/mnt/data/AppData/immich";
|
||||
machine-learning.enable = true;
|
||||
# Hardware transcoding would need the iGPU passed in explicitly, e.g.
|
||||
# accelerationDevices = [ "/dev/dri/renderD128" ]; the default [ ] means
|
||||
# PrivateDevices=yes and CPU-only transcode. The ZimaBlade's Celeron does
|
||||
# this slowly but it only runs on upload.
|
||||
};
|
||||
|
||||
# /mnt/data/AppData is drwx--x--- darman:users — immich needs group "users"
|
||||
# just to TRAVERSE into its own media dir. The dir itself stays 0700
|
||||
# immich:immich (the module's tmpfiles rule re-asserts that every rebuild,
|
||||
# and UMask=0077 keeps new files private), so this grants nothing else.
|
||||
users.users.immich.extraGroups = [ "users" ];
|
||||
|
||||
# mediaLocation is outside /var/lib, so the module won't create it — its own
|
||||
# tmpfiles entry only ADJUSTS an existing dir. Harmless no-op after the
|
||||
# legacy import, which puts the real store here.
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /mnt/data/AppData/immich 0700 immich immich -"
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user