nixos-rebuild Modes
nixos-rebuild is the main command you use after editing your config. The mode you pass determines what happens after the build:
switch builds and activates the new config immediately, and sets it as the default boot entry. This is what you use for normal deployments.
boot builds and sets the boot entry but doesn't activate until next reboot. Good for kernel updates or config changes that require a restart to take effect properly.
test builds and activates immediately but doesn't update the boot entry. The previous config is still what boots on restart. Use this when you're testing a change and want to be able to reboot back to a known-good state if something goes wrong.
build just builds the system derivation without activating anything. Useful for checking that your config evaluates and builds cleanly before you commit.
# normal deploy
sudo nixos-rebuild switch --flake .#homeserver
# test a risky change without committing it to boot
sudo nixos-rebuild test --flake .#homeserver
# build only, check for errors
nixos-rebuild build --flake .#homeserver
Remote Builds with --target-host
If you're managing the server from a workstation, you can push builds remotely without SSHing in manually:
nixos-rebuild switch \
--flake .#homeserver \
--target-host eli@homeserver.local \
--use-remote-sudo
This builds the config on your local machine (or a build host), copies the closure to the target over SSH, and activates it there. Your workstation needs Nix installed and the target needs to be reachable via SSH with sudo access.
The --build-host flag lets you offload the build to a separate machine if your server is low-powered:
nixos-rebuild switch \
--flake .#homeserver \
--build-host builder@build-box.local \
--target-host eli@homeserver.local \
--use-remote-sudo
This is useful for ARM boards where compilation is painfully slow, or for keeping the server's Nix daemon from doing heavy builds during normal operation.
PowerShell Deploy Script
Since I manage this from a Windows workstation, I've got a small PowerShell script that wraps the common operations. It runs through WSL where Nix is installed:
# deploy.ps1
param(
[string]$Host = "homeserver",
[ValidateSet("switch","boot","test","build")]
[string]$Mode = "switch",
[switch]$UpdateFlake
)
$flakeDir = "$PSScriptRoot"
if ($UpdateFlake) {
Write-Host "Updating flake.lock..." -ForegroundColor Cyan
wsl --cd $flakeDir -- nix flake update
wsl --cd $flakeDir -- git diff flake.lock
$confirm = Read-Host "Commit updated flake.lock? (y/n)"
if ($confirm -eq 'y') {
wsl --cd $flakeDir -- git add flake.lock
wsl --cd $flakeDir -- git commit -m "flake: update inputs $(Get-Date -Format yyyy-MM-dd)"
}
}
Write-Host "Deploying to $Host ($Mode)..." -ForegroundColor Cyan
wsl --cd $flakeDir -- `
nixos-rebuild $Mode `
--flake ".#$Host" `
--target-host "eli@$Host" `
--use-remote-sudo
Run it with .\deploy.ps1 for a normal switch, .\deploy.ps1 -Mode test to test, or .\deploy.ps1 -UpdateFlake to pull new nixpkgs before deploying.
Rollbacks
If a deployment breaks something, rollback is fast. On the server:
# roll back to the previous generation
sudo nixos-rebuild switch --rollback
# or list generations and switch to a specific one
nix-env --list-generations --profile /nix/var/nix/profiles/system
sudo nix-env --switch-generation 42 --profile /nix/var/nix/profiles/system
sudo /nix/var/nix/profiles/system/bin/switch-to-configuration switch
If the system isn't booting at all, pick an older generation from the systemd-boot menu on the console. Every successful build gets an entry there up to the configurationLimit you set.
deploy-rs
For multi-host setups or more structured deployments, use deploy-rs. It adds health checks after deployment, automatic rollback if the activation fails, and a cleaner multi-host config. The tradeoff is another tool to manage in your flake inputs.
For a single home server, nixos-rebuild --target-host is usually enough and has zero extra dependencies.
Keeping flake.lock Updated
flake.lock pins everything, which means you don't get security updates automatically. Build a habit around updates: run nix flake update on a schedule (I do it monthly or when something specific needs a newer version), review the diff to understand what changed, then deploy and test before committing.
# see what changed in nixpkgs since your last update
nix flake update
git diff flake.lock
The diff is a JSON blob of commit SHAs, not very human-readable. For a clearer picture:
# compare nixpkgs commits before and after update
nix flake metadata --json | jq '.locks.nodes.nixpkgs.locked.rev'
You can also subscribe to the NixOS security mailing list or watch the nixpkgs GitHub for CVEs that affect packages you run. The pinned model means you're in control of when updates land, not at the mercy of an automatic background process, which is exactly where you want to be for a home server.
That wraps up the series. The config repo this is based on lives at github.com/eli2k/homeserver-nix if you want to poke around the actual code.