Config for all my nix services at home
Nix 98%
Shell 2%
<1%

README.md

nix-config #

Personal NixOS configuration for all machines and services — managed as a single flake.

Hosts #

Personal machines #

Host Description
chris-framework AMD Framework AI 300 laptop
chris-desktop AMD desktop (gaming/workstation)
chris-wsl Windows Subsystem for Linux

Servers / LXC containers (Proxmox) #

Host IP Role
caddy 192.168.1.239 Reverse proxy + TLS (Cloudflare DNS)
pihole-1 192.168.1.9 Primary DNS
pihole-2 192.168.1.10 Secondary DNS
immich 192.168.1.127 Photo management
plex 192.168.1.209 Media server
transcode 192.168.1.74 FFmpeg transcoding worker
transmission 192.168.1.136 Torrent client
sonarr 192.168.1.75 TV automation
grafana 192.168.1.122 Metrics dashboard
uptime-kuma 192.168.1.31 Uptime monitoring
paperless 192.168.1.32 Document management
tailscale 192.168.1.207 VPN exit node
claude-agent 192.168.1.33 Remote Claude Code agent

All host IPs and Caddy routing are defined in hosts.nix — the single source of truth for network topology.


Rebuilding a machine #

Local rebuild (on the machine itself) #

sudo nixos-rebuild switch --flake /home/chris/nix-config#<hostname>

For example, on the Framework laptop:

sudo nixos-rebuild switch --flake /home/chris/nix-config#chris-framework

Remote deployment with deploy-rs #

Remote deploys use deploy-rs. Deploy nodes are auto-generated from hosts.nix — any host that exists in both hosts.nix and nixosConfigurations gets a deploy node. All builds happen locally and closures are copied to the target.

Deploy all servers (shows a confirmation prompt first):

./deploy-all.sh

Deploy a single server:

deploy .#caddy

Dry run — preview what would change without activating:

./deploy-all.sh --dry-activate
deploy .#caddy --dry-activate

Rollback all servers:

./deploy-all.sh --rollback

deploy-rs includes magic rollback — if a deployment makes a machine unreachable (e.g. broken networking), it automatically rolls back after a timeout.

The deploy user has passwordless sudo configured on all servers. SSH key auth is required.

Build only (no switch) — test for errors #

nixos-rebuild build --flake /home/chris/nix-config#<hostname>

This builds the system closure without activating it. Useful for catching errors before deploying.

Dry run with nixos-rebuild #

nixos-rebuild dry-activate --flake /home/chris/nix-config#<hostname>

Shows which services would be restarted and what would change, without applying anything.


Updating flake inputs #

Update all inputs (nixpkgs, home-manager, etc.) to their latest versions:

nix flake update

Update a single input:

nix flake update nixpkgs
nix flake update nixpkgs-unstable

After updating, commit the new flake.lock before rebuilding:

git add flake.lock
git commit -m "Update flakes"

Then rebuild the relevant machines to apply the updates.


Testing changes before deploying #

Build for a different host locally #

You can build a remote host's configuration locally to catch errors without touching the target:

nixos-rebuild build --flake /home/chris/nix-config#<remote-hostname>

The build runs on your local machine but produces the configuration for the target host.

Evaluate without building #

Check that the Nix expressions parse and evaluate correctly:

nix eval .#nixosConfigurations.<hostname>.config.system.build.toplevel.drvPath

Check the diff before switching #

After a nixos-rebuild build, compare the new system with the currently running one:

nvd diff /run/current-system ./result

(nvd is the NixOS version diff tool — install with nix-shell -p nvd if not present.)


Secrets management (sops-nix) #

Secrets are encrypted with age and stored in secrets/*.yaml. Each host can only decrypt its own secrets using its SSH host key.

Edit a secret #

sops secrets/<name>.yaml

Add a new secret file #

  1. Add the host's age public key to .sops.yaml under the appropriate creation rules.
  2. Create and edit the file: sops secrets/<name>.yaml
  3. Reference it in the host config via config.sops.secrets.*

Rotate/re-encrypt secrets after adding a new host key #

sops updatekeys secrets/<name>.yaml

Repository structure #

flake.nix                  # Flake inputs, NixOS configs, deploy-rs nodes
flake.lock                 # Pinned dependency versions
hosts.nix                  # Network topology — IPs, ports, Caddy routing
deploy-all.sh              # Deploy all servers (with confirmation prompt)
.sops.yaml                 # Age encryption rules per host

<hostname>.nix             # Top-level config for each host
hardware/                  # Hardware-specific configs (Framework, desktop)
modules/                   # Reusable NixOS modules
  common.nix               # Base for desktop machines (GNOME, Tailscale, etc.)
  cloudflare-tunnel.nix    # Cloudflare tunnel service wrapper
  nfs-home-automount.nix   # Smart NFS mount (WiFi/Tailscale aware)
  keyboard-backlight-timeout.nix  # Framework keyboard backlight
  locale.nix               # Locale/timezone
home/                      # Home Manager profiles
  common.nix               # Shared: Git, zsh, GNOME extensions
  framework.nix            # Framework-specific user packages
  desktop.nix              # Desktop-specific user packages
  wsl.nix                  # WSL: Python, 1Password SSH bridge
secrets/                   # sops-nix encrypted YAML files
common.nix                 # Base for all server/LXC containers

Common workflows #

Add a new server #

  1. Create <hostname>.nix importing common.nix and any relevant modules.
  2. Add the host to flake.nix under nixosConfigurations.
  3. Add the host to hosts.nix with its IP (and caddy = true if it needs a reverse proxy entry).
  4. If it needs secrets, add its age key to .sops.yaml and create secrets/<hostname>.yaml.
  5. Boot the server with a NixOS installer, then deploy:
nixos-install --flake /home/chris/nix-config#<hostname>

Or deploy remotely after initial install:

deploy .#<hostname>

Roll back a broken deployment #

deploy-rs has magic rollback — if the machine becomes unreachable after activation, it rolls back automatically. To manually roll back:

deploy .#<hostname> --rollback
./deploy-all.sh --rollback

On the machine directly:

sudo nixos-rebuild switch --rollback

Or at boot: select a previous generation from the bootloader menu.

Garbage collect old generations #

sudo nix-collect-garbage -d

Automatic GC is configured on all hosts (weekly, removing generations older than 7–14 days).