Skip to content
/ nixos Public

NixOS for all my devices. All. Of. Theeeeeeeeeem.

License

Notifications You must be signed in to change notification settings

miXwui/nixos

Repository files navigation

NixOS Configurations

To be stored in $XDG_NIXOS_DIR/.

Useful references (thanks!)

Modularize NixOS and Home Manager | Great Practices

Building

Garnix

We're using Garnix to build and cache remotely, in the ~C L O U D~.

Cachix is also used. In flake.nix:

# Caches
nixConfig = {
  extra-substituters = [
    "https://cache.garnix.io"
    "https://nix-community.cachix.org"
  ];
  extra-trusted-public-keys = [
    # https://garnix.io/docs/caching
    "cache.garnix.io:CTFPyKSLcx5RMJKfLo5EEPUObbA78b0YQ2DTCJXqr9g="
    # https://app.cachix.org/cache/nix-community
    "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
  ];
};

So builds can pull from the Garnix/Cachix caches.

Note that it stores a single nix store and cache among users:/ https://discourse.nixos.org/t/a-common-public-nix-cache/26998/ Unless on a paid plan, and requested to be made private.

Testing, maybe switch over to GitHub Actions to Cachix.

Rebuild

sudo nixos-rebuild switch --flake .#framework_13_amd_7840u

Hosts/devices

  • framework_13_amd_7840u
  • framework_13_intel_i7-1165g7
  • dell_xps_15_9550_intel_i7-6700hq_and_nvidia_gtx-960m
  • qemu

Remove old boot entries

https://nixos.wiki/wiki/Storage_optimization

Remove all but the current generation with sudo nix-collect-garbage --delete-older-than.

Also should run without sudo, as:

nix-collect-garbage is per user, so you need to execute it per each user that might have store paths that need cleaning up

https://discourse.nixos.org/t/no-free-disk-space-and-a-lot-of-duplicates-in-nix-store/47515/4

Remove old entries and rebuild boot options:

sudo nix-collect-garbage --delete-older-than 30d && nix-collect-garbage --delete-older-than 30d && sudo nixos-rebuild boot --flake $XDG_NIXOS_DIR/.#framework_13_amd_7840u

or

sudo nix-collect-garbage --delete-older-than 30d && nix-collect-garbage --delete-older-than 30d && sudo /run/current-system/bin/switch-to-configuration boot

Running with sudo deletes system profiles, and without deletes only current user's.

Pass --delete-old/-d instead of --delete-older-than to delete all old generations.

https://nix.dev/manual/nix/2.18/command-ref/nix-env/delete-generations#generations-time

nix-env --delete-generations +5 --dry-run

Also (sudo) nix store gc and nix store optimise.

Rebuild/regenerate systemd-boot from another partition

The relevant boot files are in /boot/EFI/nixos and /boot/loader/entries.

NixOS rebuilding will wipe/regenerate the files in those folders. So if two NixOS partitions are on the same drive that use the same EFI partition, then they will overwrite each other.

One can back up those folders and manually copy the relevant files back after each build. There should be a better solution...

To build from another NixOS partition to regenerate the boot files for that installation:

  1. Mount your root and EFI partition:

    sudo mount /dev/<root-partition> /mnt
    sudo mount /dev/<efi-partition> /mnt/boot
  2. Chroot into your system:

    sudo nixos-enter
  3. Copy resolv.conf to ensure DNS hostnames can be resolved:

    sudo cp /etc/resolv.conf /mnt/etc/resolv.conf

    NixOS/nixpkgs#39665 (comment)

  4. Rebuild your system, which will regenerate the files in /boot/EFI/nixos`:

    cd /home/mwu
    nixos-rebuild boot --flake nixos/.#framework_13_amd_7840u

Remove a directory in Nix store

nix store delete /nix/store/path

Build ISO

flake.nix is set up to use nixos-generators:

nix build $XDG_NIXOS_DIR/.#iso

This also works if added to flake.nix:

{
  nixosConfigurations = {
    live-image = nixpkgs.lib.nixosSystem {
      specialArgs = { inherit inputs; };
      modules = [
        (nixpkgs + "/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix")
        ./hosts/live-image/configuration.nix
        inputs.home-manager.nixosModules.default
        { nixpkgs.overlays = overlays; }
      ];
    };
};
}
nix build $XDG_NIXOS_DIR/.#nixosConfigurations.live-image.config.system.build.isoImage

XDG user directories

Set in xdg.userDirs in home.nix. See for full list.

The values can be accessed within nix flakes like so:
"${config.xdg.userDirs.extraConfig.XDG_WALLPAPERS_DIR}".

The environment variables can be used in scripts, e.g. $XDG_WALLPAPERS_DIR.

Packages

Install a specific version of a package

Find details from https://lazamar.co.uk/nix-versions/ or search the Git repo for the PR/commit.

Then modify hosts/home.nix like so:

let
  old = import (builtins.fetchGit {
    name = "waybar-old";
    url = "https://github.com/NixOS/nixpkgs/";
    ref = "refs/heads/nixpkgs-unstable";
    rev = "db92283eff575ac2a78d7b2d65d2dad4f7acf14a";
  }) { system = "x86_64-linux"; };
in
{
  home.packages = with pkgs; [
    old.waybar
  ]
}

Search packages

nix-search <package name>

Launch a Nix shell with package

nix-shell -p git

Keyboard

The internal keyboard is disabled by default, and keyd intercepts the internal keyboard presses remapped to a more ergonomic "split" layout with thumb modifiers.

Since I use an external split keyboard for ergonomics, I can place it on top of the laptop and systemctl stop keyd to stop the service, completely disabling the internal keyboard altogether. systemctl start keyd to re-enable.

A nixos rebuild switch or reboot will re-enable it, since the keyd service starts at boot.

Disable internal laptop keyboard when another keyboard is connected

This is taken care of in hardware_input-laptop.nix.

Here is a breakdown of the manual steps:

  1. Install libinput (services.libinput.enable = true).
  2. Find the input device paths from libinput list-devices.

or

1 Install evtest 2. sudo evtest 3. Find input event number 4. Get ATTRS{id/vendor} and ATTRS{id/product} from udevadm info --attribute-walk --path=$(udevadm info --query=path --name=/dev/input/event<N>) | grep 'vendor\|product'

Then,

  1. Add to udev rule file, e.g.: /etc/udev/rules.d/99-disable-internal-keyboard.rules or on Nix in services.udev.extraRules:

    # Disable internal keyboard when Bluetooth keyboard (Lily58) is connected
    ACTION=="add", SUBSYSTEM=="input", ENV{ID_INPUT_KEYBOARD}=="1", KERNELS=="<bluetooth_keyboard_path>", RUN+="/usr/bin/libinput disable-device /dev/input/event14"
    # Enable internal keyboard when Bluetooth keyboard (Lily58) is disconnected
    ACTION=="remove", SUBSYSTEM=="input", ENV{ID_INPUT_KEYBOARD}=="1", KERNELS=="<bluetooth_keyboard_path>", RUN+="/usr/bin/libinput enable-device /dev/input/event0"
    
  2. Reload udev rules: sudo udevadm control --reload-rules.

For more info: https://unix.stackexchange.com/questions/381944/how-to-disable-internal-keyboard-on-fedora-26-wayland/702857#702857

Fingerprint

User files are stored under /var/lib/fprint/<user> which can be migrated to another installation (ref).
The actual fingerprints for Framework 13 apparently are stored directly on the sensor.

Firmware

fwupdmgr refresh
fwupdmgr get-updates
fwupdmgr update

Power management/battery life

Show charge limit

sudo ectool fwchargelimit

Set charge limit

sudo ectool fwchargelimit 80

s2idle checks

Debugging higher idle power consumption after resume from s2idle

https://community.frame.work/t/responded-higher-idle-power-consumption-after-resume-from-s2idle/50537

Compare /sys/kernel/debug/amd_pmf/current_power_limits before and after.

Check brightness value from sysfs:

cat /sys/class/backlight/amdgpu_bl1/brightness
cat /sys/class/backlight/amdgpu_bl1/actual_brightness

Can you compare lspci -vv output before and after suspend? Does L1SS change for any device? If so; it’s pointing at a kernel driver or firmware bug for that device.

Useful to compare with (thanks to OP!): https://gist.github.com/ZachLiu519/5d932675be4997f811c73870a745d6a4

AMD

The https://gitlab.freedesktop.org/drm/amd repo is cloned to $XDG_PROJECTS_DIR/git-clones/drm/amd.

Run amd/scripts/amd_s2idle.py.

These Python packages are required:

distro
gi
packaging
pyudev
systemd

These packages are required:

acpica-tools

"msr" needs to be added to kernel modules:

boot.kernelModules = [ "msr" ];

Check if anything is inhibiting idle

There is a yidle alias/command that runs .config/sway/scripts/get-idle-inhibitors.

Its foundation:

swaymsg -t get_tree -r | jq -C '..|select(objects) | select(.inhibit_idle == true) | {pid, app_id, inhibit_idle, name}'

Adaptive Backlight Management (ABM)

Specifically for AMD.

https://community.frame.work/t/adaptive-backlight-management-abm/41055/ https://docs.kernel.org/gpu/amdgpu/module-parameters.html?highlight=abmlevel

0 is off, 1 is least reduction, 4 is max.

echo [0-4] | sudo tee /sys/class/drm/card1-eDP-1/amdgpu/panel_power_savings

Currently automatically set by TLP or power-profiles-daemon.

Restart touchpad if clicking/moving doesn't work

sudo modprobe -r i2c_hid_acpi && sudo modprobe i2c_hid_acpi

Keyring

We use Gnome Keyring for pkcs11 and secrets. We use gcr for SSH since that functionality has been moved there.

Seahorse (Passwords and Keys) is also installed.

Secrets

Managed using sops-nix.

Generating using ssh-to-age

  1. Generate new ssh age key:

    nix shell nixpkgs#age -c age-keygen -o secrets/.config/sops/age/keys.txt
  2. Or generate age key from existing ssh key:

    nix run nixpkgs#ssh-to-age -- -private-key -i ~/.ssh/id_ed25519 > secrets/.config/sops/age/keys.txt

    If the ssh key has a passphrase, run this before:

    read -s SSH_TO_AGE_PASSPHRASE; export SSH_TO_AGE_PASSPHRASE
  3. Get the public key:

    nix shell nixpkgs#age -c age-keygen -y secrets/.config/sops/age/keys.txt

Creating SOPS secrets file

mkdir secrets
cd secrets
sops secrets.yaml

Files needed

Instead of using the default SOPS path ~/.config/sops/age/keys.txt, we set the SOPS_AGE_KEY_FILE environment variable in hosts/base.nix to: $XDG_NIXOS_DIR/secrets/.config/sops/age/keys.txt.

So be sure these required files are added (the secrets/ dir is gitignored):

  • $XDG_NIXOS_DIR/secrets/.config/sops/age/keys.txt
  • $XDG_NIXOS_DIR/secrets/secrets.yaml

SSH keys

Systemd ssh-config.service defined in hosts/base.nix will automatically set up and write files to ~/.ssh using sops-nix.

See modules/home-manager/ssh.nix.

Adding new secrets

sops $XDG_NIXOS_DIR/secrets/secrets.yaml which will decrypt and open the file for editing.

Passing secrets to other processes

https://github.com/getsops/sops?tab=readme-ov-file#passing-secrets-to-other-processes

sops exec-env secrets.yaml 'echo secret: $some_secret; ./some-script

VPN

Packaged PIA manual-connections in packages/pia_manual-connections.

Installed via modules/nixos/vpn.nix.

It uses sops to decrypt the username/password and pass as variables into the startup script.

pia-connect/pia-disconnect to, well, connect and disconnect.

There are a few useful args that can be changed for pia-connect.

IPv6 will be disabled (since apparently it's not supported by PIA). The disconnect script will re-enable it.

Notable programs

  • Sway (with SwayFX toggle)
  • Power management
  • KDE Connect
  • Geoclue
    • Uses Google geolocation API.
    • Systemd geoclue-config.service write url with API key (from sops-nix) to /etc/geoclue/conf.d/90-custom-wifi.conf.
  • Gammastep for automatic color temperature adjustment based on location. disabled for now since I think it's causing higher power consumption.
    • Currently set up to use Geoclue.
  • amd_s2idle check/verify s2idle and power draw. sudo amd_s2idle.

Nix cookbook

https://nixos.wiki/wiki/Nix_Cookbook

Getting SRI hash

$ bass nix hash to-sri --type sha256 $(nix-prefetch-url "https://git.kernel.org/pub/scm/linux/kernel/git/superm1/linux.git/patch/?id=23fddba4039916caa6a96052732044ddcf514886")
path is '/nix/store/ssa6aqvdfpsgdpd2yb6rs2n0vmr3hk1d-?id=23fddba4039916caa6a96052732044ddcf514886'
sha256-q57T2Ko79DmJEfgKC3d+x/dY2D34wQCSieVrfWKsF5E=

https://www.reddit.com/r/Nix/comments/171ijju/comment/k3rbx44/

nix-shell

E.g. for https://gitlab.freedesktop.org/drm/amd/:

 nix-shell --pure -p gobject-introspection fw
upd json-glib 'python3.withPackages(ps: with ps; [ pyg
object3 ])'

Clone a Git repo to home directory

This example clones a repo, then runs a command on the repo.

Note that builtins.fetchGit saves to a read-only Nix store for users, and the directory is symlinked to it.

# For `amd_s2idle.py` script, etc.
"projects/git-clones/drm/amd" = {
  source = pkgs.runCommand "modified-amd-repo" {
    src = builtins.fetchGit {
      url = "https://gitlab.freedesktop.org/drm/amd.git";
      rev = "449cf64fdd71ac14893e8e9fd2eeb65ac65cdd84";
    };
  } ''
    cp -r $src $out
    chmod -R u+w $out
    find $out -type f -exec sed -i \
    -e 's|#!/usr/bin/python3|#!/usr/bin/env python|g' \
    -e 's|#!/usr/bin/python|#!/usr/bin/env python|g' \
    {} +
  '';      
};

Though this is packaged up in a flake here and here.

Kernel

Adding kernel patches

This adds a named specialisation with kernel patches that will appear as a separate boot entry.

  specialisation.drm-amdgpu-vcn = { inheritParentConfig = true; configuration =
    {
      boot.kernelPatches = [
        # https://gitlab.freedesktop.org/drm/amd/-/issues/3195#note_2485525
        {
          name = "1-identify-unified-queue";
          patch = (builtins.fetchurl {
            url = "https://git.kernel.org/pub/scm/linux/kernel/git/superm1/linux.git/patch/?id=23fddba4039916caa6a96052732044ddcf514886";
            sha256 = "sha256-q57T2Ko79DmJEfgKC3d+x/dY2D34wQCSieVrfWKsF5E=";
          });
        }
        {
          name = "2-not-pause-dpg";
          patch = (builtins.fetchurl {
            url = "https://git.kernel.org/pub/scm/linux/kernel/git/superm1/linux.git/patch/?id=3941fd6be7cf050225db4b699757969f8950e2ce";
            sha256 = "sha256-JYOLF5ZUxDx9T9jaZCvSQtowUq38qiGPsmAMlaCi5qg=";
          });
        }
      ];
    };
  };

One can also switch to a specialized configuration with sudo /run/current-system/specialisation/fewJobsManyCores/bin/switch-to-configuration test.
https://search.nixos.org/options?&show=specialisation

Or extract boot.kernelPatches to apply it to the config without being under a separate specialisation.

List available kernels

https://nixos.wiki/wiki/Linux_kernel#List_available_kernels

Tab complete pkgs.linuxPackages.

$ nix repl

nix-repl> :l <nixpkgs>
Added 12607 variables.

nix-repl> pkgs.linuxPackages

See current patch version

nix-search linux-manual seems to show the current version.

This seems to as well: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/os-specific/linux/kernel/kernels-org.json

Pinning a kernel version

https://nixos.wiki/wiki/Linux_kernel#Pinning_a_kernel_version

Warning: This will compile the kernel and take a while.

Example (add to base.nix under ### KERNEL ###):

boot.kernelPackages = pkgs.linuxPackagesFor (
  pkgs.linux_6_11.override {
    argsOverride = rec {
      src = pkgs.fetchurl {
        url = "mirror://kernel/linux/kernel/v6.x/linux-${version}.tar.xz";
        sha256 = "sha256-BXJj0K/BfVJTeUr9PSObpNpKpzSyL6NsFmX0G5VEm3M=";
      };
      version = "6.11.3";
      modDirVersion = "6.11.3";
    };
  }
);

Build Fedora kernel

https://nixos.org/manual/nixos/stable/#sec-linux-config-customizing https://nixos.org/manual/nixpkgs/stable/#sec-linux-kernel https://nixos.wiki/wiki/Linux_kernel

Useful for testing/diffing, e.g. in the case that the Fedora kernel has a lower idle power draw than the NixOS default kernel.

let
  fedoraKernel = (pkgs.linuxKernel.manualConfig rec {
    version = "6.9.11";
    modDirVersion = version;
    configfile = ./kernel-x86_64-fedora.noquotes.config;
    allowImportFromDerivation = true;
    src = pkgs.fetchurl {
      # https://github.com/NixOS/nixpkgs/blob/28b3994c14c4b3e36aa8b6c0145e467250c8fbb8/pkgs/os-specific/linux/kernel/mainline.nix#L19
      url = "https://cdn.kernel.org/pub/linux/kernel/v${lib.versions.major version}.x/linux-${version}.tar.gz";
      sha256 = "0f69315a144b24a72ebd346b1ca571acef10e9609356eb9aa4c70ef3574eff62";
    };
  # https://github.com/NixOS/nixpkgs/issues/216529
  # https://github.com/NixOS/nixpkgs/pull/288154#pullrequestreview-1901852446
  }).overrideAttrs(old: {
    passthru = old.passthru // {
      features = {
        ia32Emulation = true;
        efiBootStub = true;
      };
    };
  });
in
{
  boot.kernelPackages = pkgs.linuxPackagesFor fedoraKernel;
}

.config

https://src.fedoraproject.org/rpms/kernel https://src.fedoraproject.org/rpms/kernel/raw/f40/f/kernel-x86_64-fedora.config

You can see the configuration of your current kernel with the following command:

zcat /proc/config.gz

Kernel source

https://cdn.kernel.org/pub/linux/kernel/v6.x/ https://cdn.kernel.org/pub/linux/kernel/v6.x/sha256sums.asc

Misc

root module: pcips2
modprobe: FATAL: Module pcips2 not found in directory /nix/store/9ngpgsnvky7fqbc28hvdi3ccpn5p3h0n-linux-6.9.11-modules/lib/modules/6.9.11

Apparently copying some options from config fixed the issue, but I didn't record it, so shrugs.

Helix

Overall, really, really enjoying Helix now as my primary editor. Switched from about 10 years of VSCode, with a short but deep sting in Emacs-land.

It's really amazing on power efficiency and also the quickest (from testing). And I love it's style of modal editing, with tweaks of course.

Nagit is really something special and thankfully there's a standalone Rust implementation, Gitu. Works well for my usecase, so far.

Emacs

NOTE: I came out of the rabbit hole frustrated with the slowness/power efficiency of Emacs relative to Helix. So I switched to Helix.

I was using Meow in Emacs so the Kakoune inspired modal editing workflow is similar.

I do miss some things with Emacs, but they should mostly be reproducible in Helix at some point and with the long-awaited plugin system.

I've switched to Emacs after about 10 years of VSCode after some careful consideration among other options. Lot of effort, so many tweaks, but it's something that should hopefully last forever and I won't need to migrate. Briefly, out of the box, Emacs is horrible IMO. But everything's configurable, and even though it takes a lot of time and effort to learn and setup, tradeoffs so far seem to be worth it. A lot of things are overly complicated, but things remain possible to do and easily fixable due to its inherent configurability vs. other platforms.

The reduced energy (battery) usage and entirely keyboard driven workflow, among some other features (and there are a lot, a metric-yacht-load!) make usage incredible, despite the initial setup pains. If anyone else is reading this as a beginner, I'd recommend using an out of the box setup like Doom Emacs to see what's possible, and continue grinding through it and figuring out how to get that thing you want. It may take writing a custom function, but there's probably a simple and clean solution that allows you to do even more than you thought possible since Emacs has a ton of widgets.

Zed editor needs this to install dev extensions

rustc
rustup
gcc

Run 'rustup default stable' to download the latest stable release of Rust and set it as your default toolchain.

Zellij

https://zellij.dev/screencasts/

  1. cd into project dir.
  2. hx .
  3. C-p for pane mode.
  4. d to split down.
  5. A-n opens new pane.
  6. C-p-e for floating pane (Ctrl-pane-eject).
  7. C-p-w to toggle it on/off.
  8. Prepend zellij run --floating (aliased to zrf) to a command to run it in it's own window. Pressing enter on the window can re-run it (although it doesn't keep sudo context since it seems to run a new instance each time).
  9. C-s-e (Ctrl-scrollback-edit) to edit the scrollback in your default editor.

A-[/] to change pane layout. It's also useful for floating panes.

A-+/- to increase/decrease pane size.

See this repo's Zellij default-layout.kdl.
More examples: https://zellij.dev/documentation/layout-examples.

Easiest way I've found so far is to manually create the layout, then run:

zellij action dump-layout

New Zellij session:

zellij -l /path/to/layout.kdl

Inside an existing session:

zellij action new-tab -l /path/to/layout.kdl

zjw is aliased for zellij -l welcome.

keybinds {
  shared_except "locked" {
  // ...
    bind "Alt f" {
      LaunchPlugin "filepicker" {
        // floating true // uncomment this to have the filepicker opened in a floating window
        close_on_selection true // comment this out to have the filepicker remain open even after selecting a file
      };
    }
  }
}

C-e to toggle hidden files/folders.

zellij plugin -- filepicker from command line.

zellij -l strider layout for "IDE-like" experience.

zellij action new-tab -l strider in an existing session.

zpipe alias for zellij pipe -p.

zpipe filepicker or zpf for zellij pipe -p filepicker to pipe its output to STDOUT.

E.g. to open the filepicker to select a file to copy to path/some-file:

zpf | xargs -i cp {} path/some-file

Run multiple commands with sudo

pane command="sudo" {
  start_suspended true
  cwd "$XDG_NIXOS_DIR"
  args "sh" "-c" "nix-collect-garbage --delete-older-than 30d && nixos-rebuild boot --flake .#framework_13_amd_7840u"
}

Also see: zellij-org/zellij#3459

compact-bar pane

To add, run this in a floating window in a layout that has the compact-bar:

zellij setup --dump-layout compact

Which has this relevant part:

pane size=1 borderless=true {
  plugin location="compact-bar"
}

Paste that into your layout.

Command pane repetition

Example:

pane split_direction="horizontal" {
  cargo { args "run"; }
  cargo { args "test"; }
  cargo { args "check"; }
}
pane_template_name name="cargo" {
  command "cargo"
  start_suspended true
}

Rust

Build older version from crate

zellij_0-38 = pkgs.zellij.overrideAttrs (old: rec {
  version = "0.38.2";
  src = pkgs.fetchFromGitHub {
   owner = "zellij-org";
   repo = "zellij";
   rev = "eb18af029e6ddc692baacf49666354694e416d53";
   hash = "sha256-rq7M4g+s44j9jh5GzOjOCBr7VK3m/EQej/Qcnp67NhY=";
  };
  cargoDeps = pkgs.rustPlatform.fetchCargoTarball {
    inherit src;
    name = "${old.pname}-${version}";
    hash = "sha256-xK7lLgjVFUISo4stF6MgfgI4mT5qHuph70cyYaLYZ30=";
  };
});

Music

Using mpd with ncmpcpp

mpc is also installed.

Has a lot of useful commands like mpc stats, update.

ncmpcpp cheatsheet

https://pkgbuild.com/~jelle/ncmpcpp/

Issues

Not applying GID change during boot

I was getting this warning during boot in NixOS Stage 2 after running activation script:

warning: not applying GID change of group uinput (990 -> 327) in /etc/group/

See this: NixOS/nixpkgs#19599 (comment)

To manually fix: Read this answer and this comment.

  1. groupmod -g NEWGID GROUPNAME
    1. sudo groupmod -g 327 uinput
  2. sudo find / -gid OLDGID ! -type l -exec chgrp NEWGID {} \;\
    1. Suggest using chgrp -h ... instead of chgrp .... Without -h, the target of any relevant symlink will have its group changed.

    2. sudo find / -gid 990 ! -type l -exec chgrp 327 {} \;
    3. Or, manually find and change.

ls -n to see the numeric UID/GID of file.

Diagnosing long boot times

  • systemd-analyze critical-chain
  • systemd-analyze blame
  • systemd-analyze plot > boot-analysis.svg
  • journalctl -b -k
  • systemctl status --lines 1000 home-manager-mwu.service

I also have flags in base.nix in boot_debug for:

  • .enable: Enabling verbose boot logs
  • .network_no_wait_online: Not waiting for network to be online during boot
  • .network_no_wait_startup: Not waiting for network startup during boot
  • .home_manager_verbose: Enabling verbose Home Manager logs

Remove/delete files/folders

If a file/folder gets stuck and you can't remove it even as root, you can create a script in home.activation like so:

home.activation = {
  # Scripts to run during the activation phase.
  removeFolder = ''
    rm -rf /home/mwu/projects/scripts
  '';
};

3-2-1 Backup

Modules are in hosts/common/backup.nix and modules/home-manager/backup.nix.

Requires a rebuild since secrets are pulled from sops-nix and files need to be updated/regenerated.

Since NixOS 23.11, the restic service creates wrapper scripts for each job. The script is name restic-$job: https://www.arthurkoziel.com/restic-backups-b2-nixos/ — thanks!

Check current snapshots on remote:

sudo restic-hetzner-storage-box snapshots

Or run other restic commands:

sudo restic-hetzner-storage-box <command>

E.g. updating the password:

https://restic.readthedocs.io/en/stable/070_encryption.html

sudo restic-hetzner-storage-box key <list|add|remove|passwd>

Connect with SFTP

sftp -P <22 or 23> <username>@<username>.<server>
  1. Setup storage box with main account and save credentials.
  2. SFTP into box and create a folder.
  3. Create a sub-account
  4. Enable these options in sub-account:
  • Allow SSH
  • External reachability

https://docs.hetzner.com/storage/storage-box/backup-space-ssh-keys/

Use port 23 for better performance, apparently.

Copy public key over to storage box:

cat ~/.ssh/id_rsa.pub | ssh -p23 <account>@<account>.<server> install-ssh-key

Preparing a new repo - SFTP

restic -r sftp:user@host:/path/to/restic-repo init
Backing up

Use port 23 which is apparently faster on Hetzner.

https://restic.readthedocs.io/en/stable/030_preparing_a_new_repo.html

restic -r sftp://user@host:23/path/to/restic-repo --verbose backup ~/work

Using Rclone

On Hetzner Storage Box:

  • If using a sub-account, ensure the sub-account URL is used.
  • Below is for WebDAV. If using, ensure that WebDAV is enabled on the box.
Example Rclone config file
rclone config create hetzner_webdav \
        webdav \
        url https://<sub-account>.<server> \
        user <sub-account> \
        vendor other \
        pass $(rclone obscure <repo password>)
Init repo

Will init if it doesn't exist, else no-op.

restic -r rclone:hetzner_webdav:/srv/restic-repo init
Backup a directory
restic -r rclone:hetzner_webdav:/srv/restic-repo --verbose backup ~/
Connect with bare config

Where Rclone config is just:

[hetzner_storage_box]
type = webdav

Command:

RESTIC_PASSWORD="REPO-PASSWORD" restic --password-command "cat /path/to/password/file" -o rclone.args="serve restic --stdio --webdav-url=https://<sub-account>.<server> --webdav-user=<sub-account> --webdav-vendor=other --webdav-pass=<sub-account password with `rclone obscure`> --verbose" -r rclone:hetzner_storage_box:/path/to/restic-repo backup ~/

restic --password-command "cat /path/to/password/file" -o rclone.args="serve restic --stdio --webdav-url=https://$(cat /path/to/sub-account/file).$(cat /path/to/server/file) --webdav-user=$(cat /path/to/sub-account/file) --webdav-vendor=other --webdav-pass="$(rclone obscure $(cat /path/to/sub-account/password))" --verbose" -r rclone:hetzner_storage_box:/path/to/restic-repo backup ~/

Restoring

Restic mount
mkdir /mnt/restic
Mount using NixOS generated wrapper script

Use --allow-other to be able to let other users and GUI apps like Nautilus to access the FUSE mount.

sudo restic-hetzner-storage-box mount --allow-other /mnt/restic
Over SFTP
restic -r sftp:user@host:/path/to/restic-repo mount /mnt/restic
Restore entire repo/backup

Restore the latest snapshot to root /, which restores directories such as /var/lib and /home/<main-user>.

sudo restic-hetzner-storage-box restore --target / latest
Restore something specific to a folder
sudo restic-hetzner-storage-box restore <snapshot-id> --target /tmp/restore-work --include /work/foo

See: https://forum.restic.net/t/performance-differences-between-restic-dump-mount-restore/3878

restore seems way faster than mount (with rsync) and dump.

Removing files from snapshots

sudo restic-hetzner-storage-box rewrite --exclude=file1 --exclude=file2 --dry-run

This will save new snapshots marked with rewrite and keep old snapshots. To also remove old snapshots, Use the --forget flag. And to remove unreferenced data, run restic prune (advisable to run restic check afterwards).

See for more details: https://restic.readthedocs.io/en/stable/045_working_with_repos.html#removing-files-from-snapshots

Rsync

Copy from source to destination:

rsync -av --info=progress2 /src/ /dest/

About

NixOS for all my devices. All. Of. Theeeeeeeeeem.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published