My NixOS and Nix-Darwin configurations.
Note
in all commands flake location can be one of the following:
# github repo
github:konradmalik/dotfiles#<target>
# local current dir
.#<target>
# absolute local git repo
git+file://$HOME/Code/github.com/konradmalik/dotfiles#<target>
I'll use the local version for brevity.
$ sudo nixos-rebuild --flake . switch
To just build (for example for a test):
$ nix build .#nixosConfigurations.$(hostname -s).config.system.build.toplevel
Note
This will fail because of this bug. Workaround is to use root ssh access, but I don't want to do that
$ TARGET=rpi4-1 nixos-rebuild --flake .#$TARGET --target-host $TARGET --build-host $TARGET --use-remote-sudo boot
Instead, this will work for now. I may create a wrapper for that:
$ TARGET=rpi4-1 ssh $TARGET -- sudo nixos-rebuild --flake github:konradmalik/dotfiles#$TARGET boot
$ nix build .#rpi4-2-sd-image
Copy it somewhere and unpack:
$ unzstd -d rpi4-2.img.zst
Flash directly to the card:
$ sudo dd if=rpi4-2.img of=/dev/sdX bs=4096 conv=fsync status=progress
Note
The filesystem won't be complete, it will miss etc
and more. NixOS will populate those dirs on first boot.
So if you need to modify something on the card (like read host keys or add wpa_supplicant.conf
) then the steps are:
- boot rpi with the newly flashed card once
- wait a minute or two
- poweroff rpi and mount the card on your PC
- filesystem will be complete
In my case, Wi-Fi (wpa_supplicant.conf
) is symlinked from sops
, but you may still need to add appropriate host key to .sops.yaml
.
Useful for installing any nixos-config through ssh.
$ nix build .#installer-iso
Flash iso to a pendrive
$ sudo dd if=installer.iso of=/dev/sdX bs=4096 conv=fsync status=progress
Boot, find the ip and ssh connect as root.
Consider using nmap for discovery:
$ sudo nmap -p 22 --open -sV 192.168.178.0/24
Format, partition the drive etc.
Then you can install the system from flake directly:
$ sudo nixos-install --flake github:konradmalik/dotfiles#m3800 --root /mnt --no-bootloader
Tip: nixos-enter
is also very handy if you have a working system but need to fix something, e.g. change your password.
Tip2: I use --no-bootloader
because I don't want grub (either way it will fail if there is systemd already defined I think,
it will say something like '/boot/efi is not at the root'). My flake has already all the needed hardware and booloader configs for the machines I use.
In order to install on a new machine, just generate hardware-configuration.nix on that machine and add a new entry in this flake.
Disable gatekeeper or however it's called:
$ sudo spctl --master-disable
Go to Settings → Security and Privacy and allow apps from "Anywhere".
Then install nix following the official guidelines and installer.
Then build and enable config locally:
$ darwin-rebuild switch --flake .#$(hostname -s)
To just build (for example for a test):
$ nix build .#darwinConfigurations.$(hostname -s).config.system.build.toplevel
# or shortened by nix-darwin
$ nix build .#darwinConfigurations.$(hostname -s).system
It is useful to have a Linux builder on a macOS machine to build linux-specific stuff.
NixOS has a great support for this. We need to:
- set up a remote builder
- configure nix.buildMachines to use it
We can have either a truly remote machine (local PC, cloud VM etc. etc.) or a 'local remote builder' which is just a qemu virtual machine with NixOS inside. This 'local remote builder' is very handy to have either way, very easy to deploy and very lightweight (it mounts your existing /nix/store for example for absolutely minimal disk usage).
nix-darwin
support a Linux builder as an option:
nix.linux-builder.enable = true;
Use darwin-docker
module.
Build and enable config locally:
$ home-manager switch --flake .
To just build (for example for a test):
$ nix build .#homeConfigurations.$(whoami)@$(hostname -s).activationPackage
We use age
, it's way easier and more straightforward than gpg
.
Strategy with keys:
age
derived from host ssh key for host-wide secretsage
derived from personal ssh key for personal secrets- one global
age
key per person that is kept secret and not directly on any machine. Serves as a backup to decrypt in case of 'tragedy'
Create age
directory for sops:
$ mkdir -p "$XDG_CONFIG_HOME/sops/age" \
$ && touch "$XDG_CONFIG_HOME/sops/age/keys.txt" \
$ && chmod 700 "$XDG_CONFIG_HOME/sops/age" \
$ && chmod 600 "$XDG_CONFIG_HOME/sops/age/keys.txt"
Create age
key from your personal ssh key:
Why do this when decryption keys are also derived from host ssh keys?
- Redundancy, 2. Personal (user-specific) secrets, 3. Keys generated here can also be used in the home-manager module below
$ ssh-to-age -private-key -i ~/.ssh/personal > "$XDG_CONFIG_HOME/sops/age/keys.txt"
Add this key to .sops.yaml
and propagate re-encryption to all secrets:
# adjust this command, glob may not work!
$ sops updatekeys secrets/*.yaml
For user-specific secrets, a home-manager modules of sops-nix is used.
We similarly use age
. The key is reused from system-wide config (the one derived from personal ssh).
See how sops
is configured in the home-manager (it just points at the keys.txt
file).
Misterio77 - big inspiration for hyprland and nix files structure.