diff --git a/hosts/idols-ai/default.nix b/hosts/idols-ai/default.nix index 2abdd882..3f806bb8 100644 --- a/hosts/idols-ai/default.nix +++ b/hosts/idols-ai/default.nix @@ -62,6 +62,13 @@ in modules.btrbk.enable = true; + # systemd-journal - cap disk usage + # https://www.freedesktop.org/software/systemd/man/latest/journald.conf.html + services.journald.settings.Journal = { + SystemMaxUse = "10G"; + RuntimeMaxUse = "256M"; + }; + # QEMU/KVM(HostCpuOnly) for local VMs. environment.systemPackages = [ pkgs.qemu_kvm ]; diff --git a/hosts/idols-ai/disko-fs.nix b/hosts/idols-ai/disko-fs.nix index a0698564..50514bc2 100644 --- a/hosts/idols-ai/disko-fs.nix +++ b/hosts/idols-ai/disko-fs.nix @@ -17,6 +17,8 @@ nodev."/" = { fsType = "tmpfs"; mountOptions = [ + "nosuid" # Ignore setuid bit; no suid binaries live on the root tmpfs + "nodev" # Ignore device files; nothing here needs to be a device node "size=4G" "relatime" # Update inode access times relative to modify/change time "mode=755" @@ -96,12 +98,17 @@ "@snapshots" = { mountpoint = "/snapshots"; mountOptions = [ + "nosuid" + "nodev" "compress-force=zstd:1" ]; }; "@tmp" = { mountpoint = "/tmp"; mountOptions = [ + "nosuid" + "nodev" + "noatime" # Temp files don't need access times; saves btrfs metadata writes "compress-force=zstd:1" ]; }; diff --git a/hosts/idols-ai/preservation.nix b/hosts/idols-ai/preservation.nix index 9361611c..d68fa279 100644 --- a/hosts/idols-ai/preservation.nix +++ b/hosts/idols-ai/preservation.nix @@ -51,10 +51,36 @@ in "/var/log" # system caches (e.g. restic, plocate; slow to rebuild) "/var/cache" + # General scratch space. It is re-creatable and can grow large, so keep it + # off the root tmpfs and on the persistent volume. Contents only + # accumulate between reboots: the tmpfiles rule below wipes it at boot. + # World-writable scratch, so harden the bind mount like /tmp; the mode + # must stay 1777 to match that `D!` rule. + { + directory = "/var/tmp"; + mode = "1777"; + mountOptions = [ + "nosuid" + "nodev" + ]; + } + # btrbk state/home (SSH keys, cache). The owner must match the btrbk + # module's `d /var/lib/btrbk 0750 btrbk btrbk` rule, which preservation + # would otherwise override with the default root:root. + { + directory = "/var/lib/btrbk"; + user = "btrbk"; + group = "btrbk"; + mode = "0750"; + } + # CUPS state (the print spool lives in /var/spool/cups, not here) + "/var/lib/cups" # system-core "/var/lib/nixos" "/var/lib/systemd" + # upower device battery history (e.g. Magic Trackpad) + "/var/lib/upower" { directory = "/var/lib/private"; mode = "0700"; @@ -82,6 +108,10 @@ in file = "/etc/machine-id"; inInitrd = true; } + # logrotate's state file (a regular file, not a directory). It records the + # last rotation per log; a missing entry makes logrotate treat the log as + # freshly rotated, so the state must survive reboots. + { file = "/var/lib/logrotate.status"; } ]; # the following directories will be passed to /persistent/home/$USER @@ -127,6 +157,7 @@ in ".local/state/home-manager" ".local/state/nix/profiles" + ".local/state/noctalia" # shell settings, notification/clipboard history ".local/share/nix" # ====================================== @@ -372,6 +403,18 @@ in "/home/${username}/.terraform.d".d = permission; }; + # /var/tmp is re-creatable scratch, but it must not consume RAM, so it is + # bind-mounted onto the persistent volume above. Wipe it at boot (mirrors + # nixpkgs `boot.tmp.cleanOnBoot` for /tmp) so contents only accumulate + # between reboots. + # + # Crash dumps live in the persisted /var/lib/systemd and can contain secrets + # copied out of process memory, so don't keep them across reboots either. + systemd.tmpfiles.rules = [ + "D! /var/tmp 1777 root root" + "D! /var/lib/systemd/coredump 0755 root root" + ]; + # systemd-machine-id-commit.service would fail but it is not relevant # in this specific setup for a persistent machine-id so we disable it #