diff --git a/checks/default.nix b/checks/default.nix index 1ea5427..d4de7c0 100644 --- a/checks/default.nix +++ b/checks/default.nix @@ -17,13 +17,13 @@ projectRootFile = ".git/config"; programs = { nixfmt-rfc-style.enable = true; - deadnix.enable = false; + deadnix.enable = true; }; }; pre-commit.settings.hooks = { nixfmt-rfc-style.enable = true; - deadnix.enable = false; + deadnix.enable = true; }; }; diff --git a/flake.lock b/flake.lock index 8a2a579..c270768 100644 --- a/flake.lock +++ b/flake.lock @@ -119,26 +119,6 @@ "type": "github" } }, - "emacs-overlay": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs_3", - "nixpkgs-stable": "nixpkgs-stable" - }, - "locked": { - "lastModified": 1728638138, - "narHash": "sha256-9BNhvMzh/bQmm0VhhRrl3fmiIjQnvRrVUwXIM5mtYY4=", - "owner": "nix-community", - "repo": "emacs-overlay", - "rev": "b3101a3a0f3883f97fa867ef56b0f29fa2b2b7f1", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "emacs-overlay", - "type": "github" - } - }, "fan-control": { "flake": false, "locked": { @@ -287,24 +267,6 @@ "inputs": { "systems": "systems_3" }, - "locked": { - "lastModified": 1726560853, - "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_3": { - "inputs": { - "systems": "systems_4" - }, "locked": { "lastModified": 1681202837, "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", @@ -359,7 +321,7 @@ "nixpkgs": [ "nixpkgs" ], - "nixpkgs-stable": "nixpkgs-stable_2" + "nixpkgs-stable": "nixpkgs-stable" }, "locked": { "lastModified": 1726745158, @@ -421,7 +383,7 @@ "hercules-ci-effects": { "inputs": { "flake-parts": "flake-parts_3", - "nixpkgs": "nixpkgs_6" + "nixpkgs": "nixpkgs_5" }, "locked": { "lastModified": 1701009247, @@ -595,7 +557,7 @@ }, "lix-module": { "inputs": { - "flake-utils": "flake-utils_2", + "flake-utils": "flake-utils", "flakey-profile": "flakey-profile", "lix": [ "lix" @@ -664,7 +626,7 @@ "inputs": { "home-manager": "home-manager_2", "nix-formatter-pack": "nix-formatter-pack", - "nixpkgs": "nixpkgs_4", + "nixpkgs": "nixpkgs_3", "nixpkgs-docs": "nixpkgs-docs", "nixpkgs-for-bootstrap": "nixpkgs-for-bootstrap", "nmd": "nmd" @@ -685,7 +647,7 @@ }, "nixDarwin": { "inputs": { - "nixpkgs": "nixpkgs_5" + "nixpkgs": "nixpkgs_4" }, "locked": { "lastModified": 1727003835, @@ -852,22 +814,6 @@ } }, "nixpkgs-stable": { - "locked": { - "lastModified": 1728500571, - "narHash": "sha256-dOymOQ3AfNI4Z337yEwHGohrVQb4yPODCW9MDUyAc4w=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "d51c28603def282a24fa034bcb007e2bcb5b5dd0", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-24.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-stable_2": { "locked": { "lastModified": 1720386169, "narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=", @@ -883,7 +829,7 @@ "type": "github" } }, - "nixpkgs-stable_3": { + "nixpkgs-stable_2": { "locked": { "lastModified": 1720386169, "narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=", @@ -916,22 +862,6 @@ } }, "nixpkgs_3": { - "locked": { - "lastModified": 1728492678, - "narHash": "sha256-9UTxR8eukdg+XZeHgxW5hQA9fIKHsKCdOIUycTryeVw=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "5633bcff0c6162b9e4b5f1264264611e950c8ec7", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_4": { "locked": { "lastModified": 1708172716, "narHash": "sha256-3M94oln0b61m3dUmLyECCA9hYAHXZEszM4saE3CmQO4=", @@ -946,7 +876,7 @@ "type": "github" } }, - "nixpkgs_5": { + "nixpkgs_4": { "locked": { "lastModified": 0, "narHash": "sha256-bvGoiQBvponpZh8ClUcmJ6QnsNKw0EMrCQJARK3bI1c=", @@ -958,7 +888,7 @@ "type": "indirect" } }, - "nixpkgs_6": { + "nixpkgs_5": { "locked": { "lastModified": 1697723726, "narHash": "sha256-SaTWPkI8a5xSHX/rrKzUe+/uVNy6zCGMXgoeMb7T9rg=", @@ -974,13 +904,13 @@ "type": "github" } }, - "nixpkgs_7": { + "nixpkgs_6": { "locked": { - "lastModified": 1728492678, - "narHash": "sha256-9UTxR8eukdg+XZeHgxW5hQA9fIKHsKCdOIUycTryeVw=", + "lastModified": 1728241625, + "narHash": "sha256-yumd4fBc/hi8a9QgA9IT8vlQuLZ2oqhkJXHPKxH/tRw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5633bcff0c6162b9e4b5f1264264611e950c8ec7", + "rev": "c31898adf5a8ed202ce5bea9f347b1c6871f32d1", "type": "github" }, "original": { @@ -990,7 +920,7 @@ "type": "github" } }, - "nixpkgs_8": { + "nixpkgs_7": { "locked": { "lastModified": 1678470307, "narHash": "sha256-OEeMUr3ueLIXyW/OaFUX5jUdimyQwMg/7e+/Q0gC/QE=", @@ -1006,7 +936,7 @@ "type": "github" } }, - "nixpkgs_9": { + "nixpkgs_8": { "locked": { "lastModified": 1682134069, "narHash": "sha256-TnI/ZXSmRxQDt2sjRYK/8j8iha4B4zP2cnQCZZ3vp7k=", @@ -1101,7 +1031,7 @@ "lanzaboote", "nixpkgs" ], - "nixpkgs-stable": "nixpkgs-stable_3" + "nixpkgs-stable": "nixpkgs-stable_2" }, "locked": { "lastModified": 1721042469, @@ -1161,7 +1091,7 @@ "fan-control": "fan-control", "flake-parts": "flake-parts_4", "kernel-src": "kernel-src", - "nixpkgs": "nixpkgs_8", + "nixpkgs": "nixpkgs_7", "nixpkgs-kernel": "nixpkgs-kernel", "panfork": "panfork", "tow-boot": "tow-boot", @@ -1187,7 +1117,6 @@ "catppuccin": "catppuccin", "disko": "disko", "dream2nix": "dream2nix", - "emacs-overlay": "emacs-overlay", "flakeParts": "flakeParts", "git-hooks-nix": "git-hooks-nix", "homeManager": "homeManager", @@ -1201,7 +1130,7 @@ "nixDarwin": "nixDarwin", "nixThePlanet": "nixThePlanet", "nixosHardware": "nixosHardware", - "nixpkgs": "nixpkgs_7", + "nixpkgs": "nixpkgs_6", "rock5b": "rock5b", "treefmt-nix": "treefmt-nix_2", "vscode-server": "vscode-server" @@ -1311,21 +1240,6 @@ "type": "github" } }, - "systems_4": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, "tow-boot": { "flake": false, "locked": { @@ -1386,8 +1300,8 @@ }, "vscode-server": { "inputs": { - "flake-utils": "flake-utils_3", - "nixpkgs": "nixpkgs_9" + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_8" }, "locked": { "lastModified": 1713958148, diff --git a/flake.nix b/flake.nix index 72b2a1f..bc75454 100644 --- a/flake.nix +++ b/flake.nix @@ -57,7 +57,6 @@ inputs.nixpkgs.follows = "nixpkgs"; }; catppuccin.url = "github:catppuccin/nix"; - emacs-overlay.url = "github:nix-community/emacs-overlay"; }; outputs = diff --git a/hmModules/emacs/default.nix b/hmModules/emacs/default.nix index fa8d312..98463cc 100644 --- a/hmModules/emacs/default.nix +++ b/hmModules/emacs/default.nix @@ -1,49 +1,10 @@ { lib, - fleetFlake, - pkgs, + age, ... }: -let - emacs = fleetFlake.packages.${pkgs.system}.emacs; -in { - home.sessionVariables.EDITOR = lib.mkForce "emacsclient -c"; - programs.emacs = { - enable = true; - package = emacs; - }; - services.emacs = { - enable = true; - client.enable = true; - defaultEditor = true; - socketActivation.enable = false; - startWithUserSession = true; - package = emacs; - }; - home.packages = - with pkgs; - [ - binutils - delta - (ripgrep.override { withPCRE2 = true; }) - gnutls - fd - hunspell - python3 - imagemagick - ghostscript_headless - mupdf-headless - poppler_utils - ffmpegthumbnailer - mediainfo - unzipNLS - nodejs_20 - pkgs.qadwaitadecorations - pkgs.kdePackages.qtwayland - ] - ++ (with hunspellDicts; [ - en_US-large - it_IT - ]); + ccrEmacs.enable = true; + home.sessionVariables.EDITOR = lib.mkForce "emacsclient"; + systemd.user.services.emacs.Service.EnvironmentFile = age.secrets.chatgpt-token.path; } diff --git a/hmModules/email/default.nix b/hmModules/email/default.nix index 5ae160a..829f6c7 100644 --- a/hmModules/email/default.nix +++ b/hmModules/email/default.nix @@ -8,19 +8,7 @@ { programs.mbsync.enable = true; programs.msmtp.enable = true; - services.mbsync = { - enable = true; - postExec = lib.getExe ( - pkgs.writeShellScriptBin "mbsync-post-exec" '' - ${lib.getExe pkgs.notmuch} new - for _ in _ _ - do - afew -C ~/.config/notmuch/default/config --tag --new -vv - afew -C ~/.config/notmuch/default/config --move --new -vv - done - '' - ); - }; + services.mbsync.enable = true; home.file.".config/aerc/stylesets" = let @@ -200,58 +188,6 @@ }; }; - programs.notmuch = { - enable = true; - new.tags = [ "new" ]; - search.excludeTags = [ - "trash" - "deleted" - "spam" - ]; - maildir.synchronizeFlags = true; - }; - - programs.afew = { - enable = true; - extraConfig = '' - [Filter.1] - message = "Tag GitHub notifications" - tags = +github - query = from:noreply@github.com OR from:notifications@github.com - - [Filter.2] - query = "folder:autistici/Inbox" - tags = +autistici - message = "Tag personal autistici emails" - - [Filter.3] - query = "not folder:autistici/Inbox" - tag = -new - message = "Sanity check: remove the new tag for emails moved out from Inbox" - - [Filter.4] - query = "not folder:autistici/Inbox" - tag = -new - message = "Sanity check: remove the new tag for emails moved out from Inbox" - - [Filter.5] - query = "not folder:autistici/Sent" - tag = +sent - message = "Sanity check: add the sent tag for emails in Sent" - - [Filter.6] - query = "not folder:autistici/Drafts" - tag = +draft - message = "Sanity check: add the draft tag for emails in Draft" - - [MailMover] - folders = autistici/Inbox - rename = true - - autistici/Inbox = 'tag:archive':autistici/Archive 'tag:github':autistici/GitHub 'NOT tag:new':autistici/Trash - ''; - }; - systemd.user.services.emails-watcher = { Unit.Description = "Send notifications when new emails arrive"; Install = { @@ -278,8 +214,6 @@ mbsync = { enable = true; create = "maildir"; - expunge = "both"; - remove = "both"; }; msmtp.enable = true; notmuch.enable = true; diff --git a/hmModules/hyprland/hyprland.conf b/hmModules/hyprland/hyprland.conf index 543355b..c8c20af 100644 --- a/hmModules/hyprland/hyprland.conf +++ b/hmModules/hyprland/hyprland.conf @@ -36,7 +36,6 @@ bind = $mod, m, exec, footclient $SHELL -C "aerc" bind = $mod, d, exec, fuzzel --background-color=253559cc --border-radius=5 --border-width=0 bind = $mod, s, exec, screenshot.sh bind = $mod, n, exec, logseq -bind = $mod, x, exec, emacsclient -c bind = , XF86MonBrightnessUp, exec, brightnessctl s +5% bind = , XF86MonBrightnessDown, exec, brightnessctl s 5%- bind = $mod, code:60, exec, brightnessctl s +5% diff --git a/hmModules/logseq/default.nix b/hmModules/logseq/default.nix index dffb462..f8ff624 100644 --- a/hmModules/logseq/default.nix +++ b/hmModules/logseq/default.nix @@ -8,7 +8,7 @@ let hash = "sha256-Hy/zk8ZCkWajsMRUMsewLvkKpMpsBZYnFootPU9y6Z0="; }; }; - logseq-wayland = pkgs.writeScriptBin "logseq" "${lib.getExe' logseq "logseq"} --enable-features=UseOzonePlatform --ozone-platform=wayland"; + logseq-wayland = pkgs.writeScriptBin "logseq" "${lib.getExe logseq} --enable-features=UseOzonePlatform --ozone-platform=wayland"; in { home.packages = [ logseq-wayland ]; diff --git a/hosts/kirk/default.nix b/hosts/kirk/default.nix index 272dd30..7838975 100644 --- a/hosts/kirk/default.nix +++ b/hosts/kirk/default.nix @@ -1,7 +1,7 @@ { fleetModules, lib, - pkgs, + config, ... }: { @@ -27,14 +27,13 @@ "printing" "pam" "wireguard-client" + "restic" "greetd" "syncthing" - "mount-sisko" + "mount-rock5b" "adb" "binfmt" "prometheus-exporters" - "promtail" - "syncthing" ] ++ [ ./disko.nix @@ -72,9 +71,6 @@ "zathura" "imv" "catppuccin" - "libreoffice" - "logseq" - "emacs" ]; extraGroups = [ ]; backupPaths = [ ]; @@ -91,7 +87,7 @@ "kvm-intel" ]; - boot.kernelPackages = pkgs.linuxKernel.packages.linux_6_10; + boot.kernelPackages = config.boot.zfs.package.latestCompatibleLinuxPackages; boot.loader.efi.canTouchEfiVariables = true; boot.loader.systemd-boot = { @@ -105,13 +101,8 @@ powerManagement.cpuFreqGovernor = lib.mkDefault "schedutil"; hardware.enableRedistributableFirmware = lib.mkDefault true; - hardware.graphics = { + hardware.opengl = { enable = true; - enable32Bit = true; - }; - - zramSwap = { - enable = true; - algorithm = "zstd"; + driSupport32Bit = true; }; } diff --git a/hosts/picard/default.nix b/hosts/picard/default.nix index faa6571..c4128f7 100644 --- a/hosts/picard/default.nix +++ b/hosts/picard/default.nix @@ -31,13 +31,13 @@ "wireguard-client" "binfmt" "greetd" - "syncthing" + # "syncthing" "hass-poweroff" "forgejo-runners" "teamviewer" "macos-ventura" "sunshine" - "mount-sisko" + "mount-rock5b" "adb" "guix" "prometheus-exporters" @@ -91,7 +91,6 @@ "imv" "libreoffice" "logseq" - "emacs" ]; extraGroups = [ ]; backupPaths = [ ]; diff --git a/hosts/sisko/default.nix b/hosts/sisko/default.nix index 6295c63..298eb78 100644 --- a/hosts/sisko/default.nix +++ b/hosts/sisko/default.nix @@ -15,10 +15,10 @@ "home-assistant" "adguard-home" "cloudflare-dyndns" - "sisko-proxy" + "rock5b-proxy" "invidious" "searx" - "sisko-nfs" + "rock5b-samba" "forgejo" "prometheus" "grafana" @@ -29,8 +29,6 @@ "restic" "atuin" "immich" - "paperless" - "syncthing" ] ++ [ ./disko.nix diff --git a/modules/cloudflare-dyndns/default.nix b/modules/cloudflare-dyndns/default.nix index e86c6b6..b70c98d 100644 --- a/modules/cloudflare-dyndns/default.nix +++ b/modules/cloudflare-dyndns/default.nix @@ -12,10 +12,12 @@ "search.aciceri.dev" "invidious.aciceri.dev" "vpn.aciceri.dev" + "cache.aciceri.dev" + "matrix.aciceri.dev" + "syncv3.matrix.aciceri.dev" + "jellyfin.aciceri.dev" "photos.aciceri.dev" "status.aciceri.dev" - "paper.aciceri.dev" - "cloud.aciceri.dev" ]; apiTokenFile = config.age.secrets.cloudflare-dyndns-api-token.path; }; diff --git a/modules/forgejo/default.nix b/modules/forgejo/default.nix index d67ccc5..ae7f0c4 100644 --- a/modules/forgejo/default.nix +++ b/modules/forgejo/default.nix @@ -4,7 +4,6 @@ }: { services.forgejo = { - # TODO migrate to Postgres enable = true; settings = { DEFAULT = { diff --git a/modules/immich/env b/modules/immich/env new file mode 100644 index 0000000..5c8b109 --- /dev/null +++ b/modules/immich/env @@ -0,0 +1,5 @@ +PUBLIC_LOGIN_PAGE_MESSAGE= + +IMMICH_WEB_URL=http://immich-web:3000 +IMMICH_SERVER_URL=http://immich-server:3001 +IMMICH_MACHINE_LEARNING_URL=http://immich-machine-learning:3003 \ No newline at end of file diff --git a/modules/immich/module.nix b/modules/immich/module.nix new file mode 100644 index 0000000..230691a --- /dev/null +++ b/modules/immich/module.nix @@ -0,0 +1,584 @@ +{ + config, + lib, + pkgs, + ... +}: +let + inherit (lib) + hasAttr + hasPrefix + maintainers + mapAttrs + mkDefault + mkEnableOption + mkIf + mkMerge + mkOption + mkPackageOption + optional + optionalAttrs + optionalString + types + ; + + cfg = config.services.immich; + serverCfg = config.services.immich.server; + backendCfg = serverCfg.backend; + microservicesCfg = serverCfg.microservices; + webCfg = cfg.web; + mlCfg = cfg.machineLearning; + + isServerPostgresUnix = hasPrefix "/" serverCfg.postgres.host; + postgresEnv = + if isServerPostgresUnix then + { + # If passwordFile is given, this will be overwritten in ExecStart + DB_URL = "socket://${serverCfg.postgres.host}?dbname=${serverCfg.postgres.database}"; + } + else + { + DB_HOSTNAME = serverCfg.postgres.host; + DB_PORT = toString serverCfg.postgres.port; + DB_DATABASE_NAME = serverCfg.postgres.database; + DB_USERNAME = serverCfg.postgres.username; + }; + + typesenseEnv = + { + TYPESENSE_ENABLED = toString serverCfg.typesense.enable; + } + // optionalAttrs serverCfg.typesense.enable { + TYPESENSE_HOST = serverCfg.typesense.host; + TYPESENSE_PORT = toString serverCfg.typesense.port; + TYPESENSE_PROTOCOL = serverCfg.typesense.protocol; + }; + + # Don't start a redis instance if the user sets a custom redis connection + enableRedis = + !hasAttr "REDIS_URL" serverCfg.extraConfig && !hasAttr "REDIS_SOCKET" serverCfg.extraConfig; + redisServerCfg = config.services.redis.servers.immich; + redisEnv = optionalAttrs enableRedis { + REDIS_SOCKET = redisServerCfg.unixSocket; + }; + + serverEnv = + postgresEnv + // typesenseEnv + // redisEnv + // { + NODE_ENV = "production"; + + IMMICH_MEDIA_LOCATION = serverCfg.mediaDir; + IMMICH_MACHINE_LEARNING_URL = + if serverCfg.machineLearningUrl != null then serverCfg.machineLearningUrl else "false"; + }; + + serverStartWrapper = program: '' + set -euo pipefail + mkdir -p ${serverCfg.mediaDir} + + ${optionalString (serverCfg.postgres.passwordFile != null) ( + if isServerPostgresUnix then + ''export DB_URL="socket://${serverCfg.postgres.username}:$(cat ${serverCfg.postgres.passwordFile})@${serverCfg.postgres.host}?dbname=${serverCfg.postgres.database}"'' + else + "export DB_PASSWORD=$(cat ${serverCfg.postgres.passwordFile})" + )} + + ${optionalString serverCfg.typesense.enable '' + export TYPESENSE_API_KEY=$(cat ${serverCfg.typesense.apiKeyFile}) + ''} + + exec ${program} + ''; + + commonServiceConfig = { + Restart = "on-failure"; + + # Hardening + CapabilityBoundingSet = ""; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateUsers = true; + PrivateTmp = true; + PrivateDevices = true; + PrivateMounts = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProcSubset = "pid"; + # Would re-mount paths ignored by temporary root + # TODO ProtectSystem = "strict"; + RemoveIPC = true; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_UNIX" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + "@pkey" + ]; + UMask = "0077"; + }; + + serverServiceConfig = { + DynamicUser = true; + User = "immich"; + Group = "immich"; + SupplementaryGroups = optional enableRedis redisServerCfg.user; + + StateDirectory = "immich"; + StateDirectoryMode = "0750"; + WorkingDirectory = "/var/lib/immich"; + + MemoryDenyWriteExecute = false; # nodejs requires this. + EnvironmentFile = mkIf (serverCfg.environmentFile != null) serverCfg.environmentFile; + + TemporaryFileSystem = "/:ro"; + BindReadOnlyPaths = [ + "/nix/store" + "-/etc/resolv.conf" + "-/etc/nsswitch.conf" + "-/etc/hosts" + "-/etc/localtime" + "-/run/postgresql" + ] ++ optional enableRedis redisServerCfg.unixSocket; + }; +in +{ + options.services.immich = { + enable = mkEnableOption "immich" // { + description = '' + Enables immich which consists of a backend server, microservices, + machine-learning and web ui. You can disable or reconfigure components + individually using the subsections. + ''; + }; + + package = mkPackageOption pkgs "immich" { }; + + server = { + mediaDir = mkOption { + type = types.str; + default = "/var/lib/immich/media"; + description = "Directory used to store media files."; + }; + + backend = { + enable = mkEnableOption "immich backend server" // { + default = true; + }; + port = mkOption { + type = types.port; + default = 3001; + description = "Port to bind to."; + }; + + openFirewall = mkOption { + default = false; + type = types.bool; + description = "Whether to open the firewall for the specified port."; + }; + + extraConfig = mkOption { + type = types.attrs; + default = { }; + example = { + LOG_LEVEL = "debug"; + }; + description = '' + Extra configuration options (environment variables). + Refer to [the documented variables](https://documentation.immich.app/docs/install/environment-variables) tagged with 'server' for available options. + ''; + }; + + environmentFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Environment file as defined in systemd.exec(5). May be used to provide + additional secret variables to the service without adding them to the + world-readable Nix store. + ''; + }; + }; + + microservices = { + enable = mkEnableOption "immich microservices" // { + default = true; + }; + + port = mkOption { + type = types.port; + default = 3002; + description = "Port to bind to."; + }; + + openFirewall = mkOption { + default = false; + type = types.bool; + description = "Whether to open the firewall for the specified port."; + }; + + extraConfig = mkOption { + type = types.attrs; + default = { }; + example = { + REVERSE_GEOCODING_PRECISION = 1; + }; + description = '' + Extra configuration options (environment variables). + Refer to [the documented variables](https://documentation.immich.app/docs/install/environment-variables) tagged with 'microservices' for available options. + ''; + }; + + environmentFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Environment file as defined in systemd.exec(5). May be used to provide + additional secret variables to the service without adding them to the + world-readable Nix store. + ''; + }; + }; + + typesense = { + enable = mkEnableOption "typesense" // { + default = true; + }; + + host = mkOption { + type = types.str; + default = "127.0.0.1"; + example = "typesense.example.com"; + description = "Hostname/address of the typesense server to use."; + }; + + port = mkOption { + type = types.port; + default = 8108; + description = "The port of the typesense server to use."; + }; + + protocol = mkOption { + type = types.str; + default = "http"; + description = "The protocol to use when connecting to the typesense server."; + }; + + apiKeyFile = mkOption { + type = types.path; + description = "Sets the api key for authentication with typesense."; + }; + }; + + postgres = { + host = mkOption { + type = types.str; + default = "/run/postgresql"; + description = "Hostname/address of the postgres server to use. If an absolute path is given here, it will be interpreted as a unix socket path."; + }; + + port = mkOption { + type = types.port; + default = 5432; + description = "The port of the postgres server to use."; + }; + + username = mkOption { + type = types.str; + default = "immich"; + description = "The postgres username to use."; + }; + + passwordFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Sets the password for authentication with postgres. + May be unset when using socket authentication. + ''; + }; + + database = mkOption { + type = types.str; + default = "immich"; + description = "The postgres database to use."; + }; + }; + + useMachineLearning = mkOption { + description = "Use the given machine learning server endpoint to enable ML functionality in immich."; + default = true; + type = types.bool; + }; + + machineLearningUrl = mkOption { + type = types.str; + default = "http://127.0.0.1:3003"; + example = "https://immich-ml.internal.example.com"; + description = "The machine learning server endpoint to use."; + }; + + extraConfig = mkOption { + type = types.attrs; + default = { }; + example = { + REDIS_SOCKET = "/run/custom-redis"; + }; + description = '' + Extra configuration options (environment variables) for both backend and microservices. + Refer to [the documented variables](https://documentation.immich.app/docs/install/environment-variables) tagged with both 'server' and 'microservices' for available options. + ''; + }; + + environmentFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Environment file as defined in systemd.exec(5). May be used to provide + additional secret variables to the backend and microservices servers without + adding them to the world-readable Nix store. + ''; + }; + }; + + web = { + enable = mkEnableOption "immich web frontend" // { + default = true; + }; + + port = mkOption { + type = types.port; + default = 3000; + description = "Port to bind to."; + }; + + openFirewall = mkOption { + default = false; + type = types.bool; + description = "Whether to open the firewall for the specified port."; + }; + + serverUrl = mkOption { + type = types.str; + default = "http://127.0.0.1:3001"; + example = "https://immich-backend.internal.example.com"; + description = "The backend server url to use."; + }; + + apiUrlExternal = mkOption { + type = types.str; + default = "/web"; + description = "The api url to use for external requests."; + }; + + extraConfig = mkOption { + type = types.attrs; + default = { }; + example = { + PUBLIC_LOGIN_PAGE_MESSAGE = "My awesome Immich instance!"; + }; + description = '' + Extra configuration options (environment variables). + Refer to [the documented variables](https://documentation.immich.app/docs/install/environment-variables) tagged with 'web' for available options. + ''; + }; + }; + + machineLearning = { + enable = mkEnableOption "immich machine-learning server" // { + default = true; + }; + + port = mkOption { + type = types.port; + default = 3003; + description = "Port to bind to."; + }; + + openFirewall = mkOption { + default = false; + type = types.bool; + description = "Whether to open the firewall for the specified port."; + }; + + extraConfig = mkOption { + type = types.attrs; + default = { }; + example = { + MACHINE_LEARNING_MODEL_TTL = 600; + }; + description = '' + Extra configuration options (environment variables). + Refer to [the documented variables](https://documentation.immich.app/docs/install/environment-variables) tagged with 'machine learning' for available options. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + assertions = [ + { + assertion = !isServerPostgresUnix -> serverCfg.postgres.passwordFile != null; + message = "A database password must be provided when unix sockets are not used."; + } + ]; + + networking.firewall.allowedTCPPorts = mkMerge [ + (mkIf (backendCfg.enable && backendCfg.openFirewall) [ backendCfg.port ]) + (mkIf (microservicesCfg.enable && microservicesCfg.openFirewall) [ microservicesCfg.port ]) + (mkIf (webCfg.enable && webCfg.openFirewall) [ webCfg.port ]) + (mkIf (mlCfg.enable && mlCfg.openFirewall) [ mlCfg.port ]) + ]; + + services.redis.servers.immich.enable = mkIf enableRedis true; + services.redis.vmOverCommit = mkIf enableRedis (mkDefault true); + + systemd.services.immich-server = mkIf backendCfg.enable { + description = "Immich backend server (Self-hosted photo and video backup solution)"; + after = [ + "network.target" + "typesense.service" + "postgresql.service" + "immich-machine-learning.service" + ] ++ optional enableRedis "redis-immich.service"; + wantedBy = [ "multi-user.target" ]; + + environment = + serverEnv + // { + SERVER_PORT = toString backendCfg.port; + } + // mapAttrs (_: toString) serverCfg.extraConfig + // mapAttrs (_: toString) backendCfg.extraConfig; + + script = serverStartWrapper "${cfg.package}/bin/server"; + serviceConfig = mkMerge [ + (commonServiceConfig // serverServiceConfig) + { + EnvironmentFile = mkIf (backendCfg.environmentFile != null) backendCfg.environmentFile; + } + ]; + }; + + systemd.services.immich-microservices = mkIf microservicesCfg.enable { + description = "Immich microservices (Self-hosted photo and video backup solution)"; + after = [ + "network.target" + "typesense.service" + "postgresql.service" + "immich-machine-learning.service" + ] ++ optional enableRedis "redis-immich.service"; + wantedBy = [ "multi-user.target" ]; + + environment = + serverEnv + // { + MICROSERVICES_PORT = toString microservicesCfg.port; + } + // mapAttrs (_: toString) serverCfg.extraConfig + // mapAttrs (_: toString) microservicesCfg.extraConfig; + + script = serverStartWrapper "${cfg.package}/bin/microservices"; + serviceConfig = mkMerge [ + (commonServiceConfig // serverServiceConfig) + { + EnvironmentFile = mkIf (microservicesCfg.environmentFile != null) microservicesCfg.environmentFile; + } + ]; + }; + + systemd.services.immich-web = mkIf webCfg.enable { + description = "Immich web (Self-hosted photo and video backup solution)"; + after = [ + "network.target" + "immich-server.service" + ]; + wantedBy = [ "multi-user.target" ]; + + environment = { + NODE_ENV = "production"; + PORT = toString webCfg.port; + IMMICH_SERVER_URL = webCfg.serverUrl; + IMMICH_API_URL_EXTERNAL = webCfg.apiUrlExternal; + } // mapAttrs (_: toString) webCfg.extraConfig; + + script = '' + set -euo pipefail + export PUBLIC_IMMICH_SERVER_URL=$IMMICH_SERVER_URL + export PUBLIC_IMMICH_API_URL_EXTERNAL=$IMMICH_API_URL_EXTERNAL + exec ${cfg.package.web}/bin/web + ''; + serviceConfig = commonServiceConfig // { + DynamicUser = true; + User = "immich-web"; + Group = "immich-web"; + + MemoryDenyWriteExecute = false; # nodejs requires this. + + TemporaryFileSystem = "/:ro"; + BindReadOnlyPaths = [ + "/nix/store" + "-/etc/resolv.conf" + "-/etc/nsswitch.conf" + "-/etc/hosts" + "-/etc/localtime" + ]; + }; + }; + + systemd.services.immich-machine-learning = mkIf mlCfg.enable { + description = "Immich machine learning (Self-hosted photo and video backup solution)"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + environment = { + NODE_ENV = "production"; + MACHINE_LEARNING_PORT = toString mlCfg.port; + + MACHINE_LEARNING_CACHE_FOLDER = "/var/cache/immich-ml"; + TRANSFORMERS_CACHE = "/var/cache/immich-ml"; + } // mapAttrs (_: toString) mlCfg.extraConfig; + + serviceConfig = commonServiceConfig // { + ExecStart = "${cfg.package.machine-learning}/bin/machine-learning"; + DynamicUser = true; + User = "immich-ml"; + Group = "immich-ml"; + + MemoryDenyWriteExecute = false; # onnxruntime_pybind11 requires this. + ProcSubset = "all"; # Needs /proc/cpuinfo + + CacheDirectory = "immich-ml"; + CacheDirectoryMode = "0700"; + + # TODO gpu access + + TemporaryFileSystem = "/:ro"; + BindReadOnlyPaths = [ + "/nix/store" + "-/etc/resolv.conf" + "-/etc/nsswitch.conf" + "-/etc/hosts" + "-/etc/localtime" + ]; + }; + }; + + meta.maintainers = with maintainers; [ oddlama ]; + }; +} diff --git a/modules/mount-rock5b/default.nix b/modules/mount-rock5b/default.nix new file mode 100644 index 0000000..5ae34a0 --- /dev/null +++ b/modules/mount-rock5b/default.nix @@ -0,0 +1,21 @@ +{ + pkgs, + config, + ... +}: +{ + fileSystems."/home/${config.ccr.username}/torrent" = { + device = "//sisko.fleet/torrent"; + fsType = "cifs"; + options = + let + credentials = pkgs.writeText "credentials" '' + username=guest + password= + ''; + in + [ + "credentials=${credentials},x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s,uid=1000,gid=1000" + ]; + }; +} diff --git a/modules/mount-sisko/default.nix b/modules/mount-sisko/default.nix deleted file mode 100644 index 61671a5..0000000 --- a/modules/mount-sisko/default.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ - pkgs, - config, - ... -}: -{ - environment.systemPackages = with pkgs; [ nfs-utils ]; - boot.supportedFilesystems = [ "nfs" ]; - services.rpcbind.enable = true; - - security.wrappers."mount.nfs" = { - setuid = true; - owner = "root"; - group = "root"; - source = "${pkgs.nfs-utils.out}/bin/mount.nfs"; - }; - - fileSystems."/home/${config.ccr.username}/nas" = { - device = "sisko.fleet:/hd"; - fsType = "nfs"; - options = [ - "x-systemd.automount" - "noauto" - "user" - ]; - }; -} diff --git a/modules/paperless/default.nix b/modules/paperless/default.nix index 4918ed7..6770ce5 100644 --- a/modules/paperless/default.nix +++ b/modules/paperless/default.nix @@ -4,7 +4,8 @@ enable = true; address = "0.0.0.0"; passwordFile = builtins.toFile "paperless-initial-password" "paperless"; - mediaDir = "/mnt/hd/paperless/"; + mediaDir = "/mnt/hd/paperless/media"; + consumptionDir = "/mnt/hd/paperless/consume"; settings = { PAPERLESS_OCR_LANGUAGE = "ita+eng"; PAPERLESS_CONSUMER_IGNORE_PATTERN = builtins.toJSON [ @@ -14,12 +15,11 @@ PAPERLESS_OCR_USER_ARGS = builtins.toJSON { optimize = 1; pdfa_image_compression = "lossless"; - invalidate_digital_signatures = true; }; }; }; - environment.persistence."/persist".directories = [ + backup.paths = [ config.services.paperless.dataDir ]; } diff --git a/modules/restic/default.nix b/modules/restic/default.nix index c3ba948..3edb52d 100644 --- a/modules/restic/default.nix +++ b/modules/restic/default.nix @@ -25,21 +25,10 @@ in host }".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIICf9svRenC/PLKIL9nk6K/pxQgoiFC41wTNvoIncOxs"; - services.postgresqlBackup = { - enable = true; - backupAll = true; - location = "/var/backup/postgresql"; - }; - - environment.persistence."/persist".directories = [ - config.services.postgresqlBackup.location - ]; - services.restic.backups.sisko = { paths = [ "/persist" "/mnt/hd/immich" - "/mnt/hd/paperless" ]; exclude = [ " /persist/var/lib/containers" ]; passwordFile = config.age.secrets.SISKO_RESTIC_PASSWORD.path; diff --git a/modules/sisko-proxy/default.nix b/modules/rock5b-proxy/default.nix similarity index 92% rename from modules/sisko-proxy/default.nix rename to modules/rock5b-proxy/default.nix index c6c1a7b..3a324ef 100644 --- a/modules/sisko-proxy/default.nix +++ b/modules/rock5b-proxy/default.nix @@ -47,16 +47,13 @@ proxyWebsockets = true; }; }; - "paper.aciceri.dev" = { - forceSSL = true; - enableACME = true; - locations."/" = { - proxyPass = "http://localhost:${builtins.toString config.services.paperless.port}"; - }; - }; - # "${config.services.nextcloud.hostName}" = { + + # "jellyfin.aciceri.dev" = { # forceSSL = true; # enableACME = true; + # locations."/" = { + # proxyPass = "http://localhost:8096"; + # }; # }; # "sevenofnix.aciceri.dev" = { # forceSSL = true; diff --git a/modules/sisko-samba/default.nix b/modules/rock5b-samba/default.nix similarity index 100% rename from modules/sisko-samba/default.nix rename to modules/rock5b-samba/default.nix diff --git a/modules/sisko-nfs/default.nix b/modules/sisko-nfs/default.nix deleted file mode 100644 index 7e9b82b..0000000 --- a/modules/sisko-nfs/default.nix +++ /dev/null @@ -1,20 +0,0 @@ -{ - systemd.tmpfiles.rules = [ - "d /export 770 nobody nogroup" - ]; - - fileSystems."/export/hd" = { - device = "/mnt/hd"; - options = [ "bind" ]; - }; - - services.nfs.server = { - enable = true; - exports = '' - /export 10.100.0.1/24(rw,fsid=0,no_subtree_check) - /export/hd 10.100.0.1/24(rw,nohide,insecure,no_subtree_check,no_root_squash) - ''; - }; - - networking.firewall.allowedTCPPorts = [ 2049 ]; -} diff --git a/modules/syncthing/default.nix b/modules/syncthing/default.nix index eb25947..b857df4 100644 --- a/modules/syncthing/default.nix +++ b/modules/syncthing/default.nix @@ -4,13 +4,12 @@ syncthing = { enable = true; guiAddress = "${config.networking.hostName}.fleet:8434"; - # TODO Use the home-manager module instead of the following conditions - user = if config.networking.hostName == "sisko" then "syncthing" else "ccr"; - dataDir = if config.networking.hostName == "sisko" then "/mnt/hd/syncthing" else "/home/ccr"; + user = config.ccr.username; + dataDir = "/home/${config.ccr.username}"; settings = { options = { urAccepted = 1; # anonymous usage data report - globalAnnounceEnabled = false; # Only sync when connected to the VPN + globalAnnounceEnabled = false; # Only sync on the VPN }; devices = { picard = { @@ -20,7 +19,7 @@ ]; }; sisko = { - id = "5JYQLMP-KNBMSOE-I452UDU-UTKPXJI-K27X2DI-MSCSRCG-6V54Q6U-NVGXPQA"; + id = "L5RAQXR-6U3ANNK-UJJ5AVN-37VKQRB-UK6HXSU-NN3V6HF-JNZEVA5-NI6UEAP"; addresses = [ "tcp://sisko.fleet" ]; @@ -32,7 +31,7 @@ ]; }; oneplus8t = { - id = "KMB2YRF-DGTWU24-SLITU23-5TN7BMQ-6PFAQQZ-CZ7J2QL-PIGVBTU-VRFRMQV"; + id = "76BJ2ZE-FPFDWUZ-3UZIENZ-TS6YBGG-EZSF6UE-GLHRBQ2-KTHTRMI-3JWNRAT"; addresses = [ "tcp://oneplus8t.fleet" ]; @@ -42,9 +41,9 @@ org = { path = { - picard = "/home/ccr/org"; - sisko = "/mnt/hd/syncthing/org"; - kirk = "/home/ccr/org"; + picard = "/home/${config.ccr.username}/org"; + sisko = "/home/${config.ccr.username}/org"; + kirk = "/home/${config.ccr.username}/org"; } .${config.networking.hostName}; devices = [ @@ -57,9 +56,9 @@ sync = { path = { - picard = "/home/ccr/sync"; - sisko = "/mnt/hd/syncthing/sync"; - kirk = "/home/ccr/sync"; + picard = "/home/${config.ccr.username}/sync"; + sisko = "/home/${config.ccr.username}/sync"; + kirk = "/home/${config.ccr.username}/sync"; } .${config.networking.hostName}; devices = [ diff --git a/packages/default.nix b/packages/default.nix index 258985d..ace7ede 100644 --- a/packages/default.nix +++ b/packages/default.nix @@ -54,10 +54,10 @@ (name: value: { inherit name; value = pkgs.callPackage "${self}/packages/${name}" { + pkgsStable = inputs.nixpkgsStable.legacyPackages.${system}; dream2nix = inputs.dream2nix; projectRoot = self.outPath; packagePath = "packages/${name}"; - inherit inputs; }; }) (lib.filterAttrs (_: type: type == "directory") (builtins.readDir "${self}/packages")) diff --git a/packages/emacs/default.nix b/packages/emacs/default.nix deleted file mode 100644 index fe77b46..0000000 --- a/packages/emacs/default.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ - lib, - inputs, - pkgs, - ... -}: -let - pkgs' = pkgs.extend ( - lib.composeManyExtensions [ - inputs.emacs-overlay.overlays.package - inputs.emacs-overlay.overlays.emacs - ] - ); - all-grammars = pkgs'.tree-sitter.withPlugins builtins.attrValues; - treesitGrammars = pkgs'.runCommand "treesit-grammars" { } '' - mkdir $out - for f in ${all-grammars}/* - do - cp $f $out/"libtree-sitter-$(basename $f)" - done - ''; - emacsWithoutPackages = pkgs'.emacs-git.override { - withSQLite3 = true; - withWebP = true; - withPgtk = true; - }; - emacs = (pkgs'.emacsPackagesFor emacsWithoutPackages).emacsWithPackages ( - import ./packages.nix pkgs' - ); -in -emacs.overrideAttrs { - passthru = { - inherit treesitGrammars; - }; -} diff --git a/packages/emacs/packages.nix b/packages/emacs/packages.nix deleted file mode 100644 index 7baa25f..0000000 --- a/packages/emacs/packages.nix +++ /dev/null @@ -1,108 +0,0 @@ -pkgs: epkgs: -let - inherit (epkgs) melpaPackages nongnuPackages elpaPackages; - - # *Attrset* containig extra emacs packages from flake inputs - - # *List* containing emacs packages from (M)ELPA - mainPackages = - # builtins.filter - # if an extra package has the same name then give precedence to it - # (package: ! builtins.elem package.pname (builtins.attrNames extraPackages)) - (with melpaPackages; [ - meow - meow-tree-sitter - dracula-theme - nord-theme - catppuccin-theme - modus-themes - # solaire-mode - nerd-icons - nerd-icons-completion - nerd-icons-ibuffer - nerd-icons-dired - ligature - treemacs-nerd-icons - eshell-syntax-highlighting - fish-completion # fish completion for eshell - eshell-prompt-extras - eshell-atuin - eshell-command-not-found - clipetty - sideline - consult-eglot - # sideline-flymake - rainbow-delimiters - vertico - marginalia - consult - orderless - embark - embark-consult - magit - magit-delta - magit-todos - difftastic - with-editor - diff-hl - corfu - cape - which-key - nix-mode - nix-ts-mode - agenix - zig-mode - unisonlang-mode - purescript-mode - dhall-mode - envrc - inheritenv - popper - paredit - yaml-mode - hl-todo - markdown-mode - haskell-mode - terraform-mode - diredfl - org-modern - org-roam - org-roam-ql - visual-fill-column - consult-org-roam - pass - password-store-otp - eldoc-box - go-translate - notmuch - consult-notmuch - poly-org - casual-calc - gptel - agenix - solidity-mode - # org-re-reveal # FIXME very not nice hash mismatch when building - # gptel # TODO uncomment when there will be a new release including GPT-4o - ]) - ++ (with elpaPackages; [ - delight - kind-icon - ef-themes - indent-bars - ]) - ++ (with nongnuPackages; [ - eat - corfu-terminal - haskell-ts-mode - ]); -in -mainPackages -# ++ (builtins.attrValues extraPackages) -# Playing with EAF -++ [ - # Disabled because pymupdf was broken - # (pkgs.callPackage ./eaf.nix { - # inherit (epkgs) melpaBuild; - # inherit (melpaPackages) ctable deferred epc s; - # }) -]