Here are my NixOS machines:
- carokann: personal computer (Framework laptop).
- najdorf: server where I deploy my self-hosted apps.
- ginko: RaspberryPi used as tailscale exit node.
The hosts communicate through Tailscale.
This repo is structured with flake-parts and haumea for automatic module/profile discovery, preserving all the convenience features from the original digga setup.
nixfiles/
├── hosts/ → Host configurations
├── profiles/ → Reusable configuration profiles
├── modules/ → Custom NixOS modules
├── hm-modules/ → Custom home-manager modules
├── pkgs/ → Custom packages
├── overlays/ → Additional overlays
├── lib.nix → Custom lib functions
└── shell.nix → Development shell
- Wayland compositor: hyprland
- Desktop shell: DankMaterialShell
- Editor: kakoune and Zed
- Terminal: wezterm
- Shell: fish
- Browser: zen
Here's the list of the main services deployed through their NixOS modules:
I deploy some service as Docker containers through Arion:
Important data is backed up with Restic.
Create a bootstrap ISO and put it on your usb key:
nixos-generate --flake '.#bootstrap' --format iso
sudo dd if=your.iso of=/dev/sda bs=4M status=progress oflag=directThen, from that key, install NixOS:
cd nixfiles
sudo disko --mode destroy,format,mount -f '.#carokann'
sudo mount /dev/mapper/cryptroot /mnt
sudo mkdir /mnt/boot
sudo mount /dev/nvme0n1p1 /mnt/boot
# Generate the hardware config for reference, change what you need before install
sudo nixos-generate-config --root /mnt --dir /home/sweenu
sudo nixos-install --flake '.#carokann' --root /mnt
# Optional:
# Enroll your fingerprint
sudo fprintd-enroll sweenu
# Enroll TPM2 for dm-crypt (if enabled in config)
sudo systemd-cryptenroll --tpm2-device=auto /dev/nvme0n1p2After logging in with tailscale and enabling SSH connections (sudo tailscale set --ssh), you can backup the important files:
- ~/.ssh
- ~/.local/share/fish/fish_history
- /etc/NetworkManager/system-connections (replace interface names:
sed -i 's/wlp166s0f0/wlp192s0/' *) - All documents from ~ that you want to keep
Create a ready-to-boot SD card for a RaspberryPi, do the following:
nixos-generate --flake '.#ginko' --format sd-aarch64 --system aarch64-linux
unzstd -d {the output path from the command above} -o nixos-sd-image.img
sudo dd if=nixos-sd-image.img of=/dev/sda bs=4M status=progress oflag=directDeploy the server config to a new machine:
# 0) Preperation
# Uncomment all services in hosts/najdorf/default.nix to have a minimal deployment at first.
# Generate a tailscale auth key for unattended login here: https://login.tailscale.com/admin/settings/keys, and add it through `services.tailscale.authKeyFile`. This way, your old and new server have direct access to each other.
# 1) Provision
# We use --copy-host-keys to temporarily allow agenix to decrypt the secrets.
nixos-anywhere --copy-host-keys --flake '.#najdorf' root@<ip-address>
# 2) Preserve SSH host identity
scp -p root@najdorf:/etc/ssh/ssh_host_* root@najdorf-1:/etc/ssh/
# 2b) (Optional) Generate an initrd SSH host key (only needed for remote LUKS unlock)
# See https://nixos.org/manual/nixos/unstable/options#opt-boot.initrd.network.ssh.hostKeys
ssh root@najdorf-1 'sudo ssh-keygen -t ed25519 -N "" -f /etc/ssh/initrd_ssh_host_ed25519_key'
# 3) Pre-populate known_hosts
ssh root@najdorf 'ssh-keyscan -H najdorf-1 >> ~/.ssh/known_hosts'
# 4) Freeze writes (stop apps that write into /opt + Postgres)
ssh root@najdorf 'systemctl stop docker || true; systemctl stop postgresql || true' # adapt to your services
# 5) Copy /opt to new server
# Start a detached tmux session that runs the rsync
ssh root@najdorf 'tmux new-session -d -s migration "rsync -aAXH --numeric-ids --partial --info=progress2 --log-file=/root/rsync-opt.log /opt/ root@najdorf-1:/opt/"'
# Later: check progress by reattaching
ssh root@najdorf 'tmux attach-session -t migration'
# (Ctrl+B then D to detach again without stopping it)
# 6) Postgres migration
ssh root@najdorf 'sudo -u postgres pg_dumpall --clean --if-exists --no-role-passwords' \
| ssh root@najdorf-1 'sudo -u postgres psql -X -v ON_ERROR_STOP=1 -d postgres'
# 7) Deploy all services
# Remove najdorf from tailscale and change the tailscale name from najdorf-1 to najdorf.
# Change DNS records to point to the new server (on Cloudflare, change the IP scope of the API token to the new IP).
# Uncomment the services in hosts/najdorf/default.nix
deploy '.#najdorf'- Thanks to the digga people for making my life easier when I first started to use NixOS and from which the current structure of the repo is still heavily inspired.
