Comments had drifted into multi-paragraph narrative (git commit lineage, debugging stories, restated code) in several hot spots (scripts/deploy, hermes-agent.nix, flake.nix, gitea.nix, headscale.nix). Trim every comment to its load-bearing "why" — gotchas, safety warnings, and non-obvious rationale survive verbatim in substance, just tightened to 1-2 sentences; historical narrative and anything already covered in CLAUDE.md is cut. No code/logic changed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UJqEmY1y3AYX3JoX4Y6b21
104 lines
5.4 KiB
Nix
104 lines
5.4 KiB
Nix
{ config, pkgs, inputs, ... }:
|
|
|
|
# Immich photo/video library. Native nixpkgs module, not the upstream compose
|
|
# stack — it owns its own postgres (pgvector + vectorchord) and a unix-socket redis.
|
|
#
|
|
# Storage lives under /mnt/data/AppData/immich, migrated from the old ZimaOS/CasaOS
|
|
# UPLOAD_LOCATION (same subfolder layout); see scripts/immich-import-legacy-db for
|
|
# the matching DB 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
|
|
# Package pinned to nixpkgs-unstable (3.0.3) while the module stays on the 26.05
|
|
# pin (2.7.5) — safe only because the two module files are byte-identical
|
|
# (verified by diff; re-check on any input bump). Needed because immich's
|
|
# migrations are forward-only and jupiter's imported DB was last written by
|
|
# 3.0.0, which 2.7.5 refuses to start against; drop once the pin ships >= 3.0.0.
|
|
# diff <(nixpkgs)/nixos/modules/services/web-apps/immich.nix \
|
|
# <(unstable)/nixos/modules/services/web-apps/immich.nix
|
|
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;
|
|
|
|
# ⚠️ Setting `settings` at all switches immich to IMMICH_CONFIG_FILE mode,
|
|
# which is all-or-nothing: undeclared keys fall back to immich's defaults, not
|
|
# the admin UI's saved values (which stay in system_metadata and return if
|
|
# this block is deleted), and the admin settings UI goes read-only. An
|
|
# unknown/misspelled key is a hard startup failure here (just a warning
|
|
# without a config file), so keys are copied verbatim from `defaults` in
|
|
# immich's dist/config.js.
|
|
settings = {
|
|
server.externalDomain = "https://immich.mgaction.town";
|
|
newVersionCheck.enabled = false; # nixpkgs pins the version, not immich
|
|
|
|
# OIDC via Authentik on neptun; the application/provider is created by hand
|
|
# in its UI (like headscale's and headplane's, separate apps) — only the
|
|
# client secret is managed here (hosts/neptun/secrets.nix).
|
|
oauth = {
|
|
enabled = true;
|
|
# Authentik's per-application issuer. Trailing slash matters: immich
|
|
# appends /.well-known/openid-configuration to it.
|
|
issuerUrl = "https://auth.mgaction.town/application/o/immich/";
|
|
# Authentik generates this; not a secret (it is sent in the browser
|
|
# redirect), so it lives here rather than in sops.
|
|
clientId = "FxrkWFe8keBrN83tu03UbAshSck52he2GphJDYSQ";
|
|
# Read at runtime via systemd LoadCredential — never lands in the
|
|
# world-readable /nix/store copy of the rendered config.
|
|
clientSecret._secret = config.sops.secrets.immich_oauth_client_secret.path;
|
|
scope = "openid email profile";
|
|
buttonText = "Login with Authentik";
|
|
# Matches by email, so the 2 imported users adopt their Authentik account
|
|
# instead of getting a duplicate.
|
|
autoRegister = true;
|
|
# Leave the password form reachable — autoLaunch would bounce straight
|
|
# to Authentik, locking everyone out if the OIDC app is misconfigured.
|
|
autoLaunch = false;
|
|
# Without this, immich falls back to the IdP's discovered
|
|
# end_session_endpoint and logout dumps you on Authentik's own page
|
|
# instead of back here — must be an absolute url, mirroring immich's
|
|
# internal LOGIN_URL. This ends the immich session only; the Authentik
|
|
# SSO session survives, so the next login skips the credential prompt —
|
|
# drop this line to end both.
|
|
endSessionEndpoint = "https://auth.mgaction.town/application/o/immich/end-session?post_logout_redirect_url=https://immich.mgaction.town";
|
|
# The mobile app can't follow a browser redirect back to a custom
|
|
# scheme through Authentik, so immich bounces it via this endpoint.
|
|
mobileOverrideEnabled = true;
|
|
mobileRedirectUri = "https://immich.mgaction.town/api/oauth/mobile-redirect";
|
|
};
|
|
};
|
|
# Hardware transcoding needs accelerationDevices set explicitly (e.g.
|
|
# "/dev/dri/renderD128"); default CPU-only transcode is slow on the
|
|
# ZimaBlade's Celeron but only runs on upload.
|
|
};
|
|
|
|
# /mnt/data/AppData is drwx--x--- darman:users; immich only needs group "users"
|
|
# to traverse into it — the dir itself stays 0700 immich:immich (tmpfiles +
|
|
# UMask=0077 reassert that), so this grants nothing else.
|
|
users.users.immich.extraGroups = [ "users" ];
|
|
|
|
# mediaLocation is outside /var/lib, so the module won't create it — this rule
|
|
# only adjusts perms on the dir the legacy import already created.
|
|
systemd.tmpfiles.rules = [
|
|
"d /mnt/data/AppData/immich 0700 immich immich -"
|
|
];
|
|
|
|
# The unit's automatic RequiresMountsFor doesn't cover mediaLocation — without
|
|
# this, immich starts before /mnt/data mounts and writes uploads onto the 29G
|
|
# eMMC, invisibly, under the future mountpoint.
|
|
systemd.services.immich-server.unitConfig.RequiresMountsFor = [ "/mnt/data" ];
|
|
}
|