NixOS for a Homelab: Declarative Server Management
Homelab operators who want to treat a server’s operating-system setup as code often consider NixOS: its configuration can describe packages, users, services, and network rules, then build a system generation from those declarations. That model can make a machine easier to reinstall or an update easier to review, but it does not make all server state reproducible. This guide explains how NixOS rebuilds work, where data and secrets remain separate, and when a conventional distribution may be simpler.
What Is NixOS?
NixOS is a Linux distribution whose operating-system configuration is expressed with the Nix language and evaluated by the Nix package manager. Instead of treating a server as a collection of undocumented shell commands, an administrator declares settings such as its hostname, installed packages, users, firewall rules, and system services. The NixOS project describes the distribution and its ecosystem; the NixOS manual documents installation, configuration, and system management.
When the configuration changes, NixOS evaluates it and builds a system closure: the selected packages, configuration files, and activation logic needed for that operating-system version. The Nix store lets different package versions coexist. A rebuild can then activate the new configuration as a system generation. The bootloader generally retains earlier generations, so a host can often start from a previous system after a faulty operating-system change.
That model is useful for a personal server because the operating-system setup can be reviewed as text, tracked in version control, and applied again after reinstalling. It is not the same as making every part of the machine immutable or automatically reproducible: hardware, external inputs, mutable service data, and secrets still need separate treatment.
The Problem NixOS Solves
On a conventional Linux server, configuration can accumulate through several channels: package-manager commands, edits under /etc, service installers, and hand-written scripts. These changes may be perfectly reasonable at the time, but they are difficult to reconstruct if the disk fails or the administrator forgets exactly what was changed. Two servers that were installed from the same image can gradually behave differently.
Configuration-management tools can address some of this drift by applying a playbook to already-installed machines. NixOS moves more of the base operating system into the system configuration itself. A declared service can install its package, generate its configuration, and enable its systemd unit together, rather than requiring the operator to remember a sequence of setup steps.
This is most valuable when a homelab host is rebuilt, when several machines should share a common baseline, or when an update needs a clear review and recovery path. The trade-off is that NixOS introduces its own language, module system, package conventions, and debugging workflow. It makes configuration explicit; it does not make every operational decision simple.
How NixOS Works
The main configuration describes the desired operating-system state. NixOS combines options from modules, evaluates dependencies between those options, and builds the resulting system. Modules connect high-level settings to lower-level files and services. For example, enabling a service can arrange its package and systemd unit, while firewall and user settings can be declared alongside it.
The nixos-rebuild command evaluates and activates that configuration. A dry-build checks whether the system can be built without switching the running host. switch builds and activates a new generation now; boot selects a generation for a later restart. Generations help with operating-system rollback, but they are not snapshots of the entire disk. Application databases, uploaded files, and other mutable data under locations such as /var/lib do not become recoverable merely because an older system generation remains.
NixOS can be configured with the traditional channel-based setup or with flakes. A flake declares its inputs and can record exact input revisions in flake.lock, making the package set easier to reproduce across machines. Flakes are an optional workflow rather than a prerequisite for understanding the NixOS configuration model; check the current Nix documentation before depending on a particular flake command or feature.
| Approach | Main source of configuration | Rebuilding and repeatability | Best fit |
|---|---|---|---|
| Conventional Linux with manual setup | Package manager, service files, and administrator notes | Reinstallation depends on restoring notes and repeating changes | A simple server where familiarity and ecosystem support matter most |
| Conventional Linux with Ansible | The installed OS plus playbooks applied to managed hosts | Playbooks can reapply many settings, but the base installation and playbook coverage still matter | Managing multiple existing distributions or machines |
| NixOS with a traditional configuration | NixOS modules and the host’s configuration files | Builds a system generation from the declared settings; external package inputs need their own update discipline | A single host or lab that wants a declarative operating-system baseline |
| NixOS with flakes | A flake configuration and its locked inputs | Pins declared inputs in a lock file, helping hosts use the same package revisions | A Git-managed configuration shared across hosts when the operator accepts the flake workflow |
These approaches are not mutually exclusive in every situation. For example, a NixOS machine can run application containers, while a separate tool manages services on other Linux distributions. NixOS is most compelling when the operating system itself is part of the configuration the operator wants to review and rebuild.
Components and Key Concepts
- NixOS configuration and modules: The usual starting point is the generated
configuration.nixfile. Module options define system behavior and can be divided into separate files as a configuration grows. - Hardware configuration: The installer generates hardware-specific settings, commonly in
hardware-configuration.nix. Preserve the file for that machine; a configuration copied to different hardware may need different kernel modules, filesystems, or device settings. - System generations: A successful rebuild creates a selectable system version. Keep a known-good generation until the new one has been tested, and verify that the bootloader and console access work before relying on rollback.
- Nix store and garbage collection: Store paths hold packages and build outputs used by generations. Garbage collection can remove old outputs that are no longer reachable, so do not remove generations you still need as a rollback option.
- Mutable application state: Databases, media libraries, and other service data need normal backup and restore plans. A declarative service definition does not copy or protect that data.
- Secrets and state version: Avoid committing passwords, private keys, and tokens in ordinary configuration files. Keep the generated
system.stateVersionvalue unless deliberately following the NixOS upgrade guidance; changing it is not a general-purpose way to upgrade the operating system.
Real-World Homelab Uses
NixOS can be a good base for a NAS, a media server, a small virtualization host, or a Kubernetes node when the owner values a documented and repeatable host configuration. A Git repository can hold common settings and machine-specific modules, while each host keeps its own hardware configuration and secrets workflow. Reviewing a diff before applying it also helps explain why a service or firewall rule changed.
It is less attractive when a device depends on unsupported hardware, when a vendor appliance expects a different distribution, or when the operator needs a familiar system immediately and does not want to learn the Nix language. A spare mini PC is a lower-risk place to experiment than a server holding the only copy of important files. The mini PC build guide covers hardware considerations for small home-lab machines.
Getting Started with NixOS on a Homelab Server
Start with a non-critical machine, read the current NixOS installation and configuration manual, and make an independent backup of any data on the target disk. Record the hardware, network address, storage layout, and services the host needs. Do not begin by migrating a NAS or other system whose data has not been backed up and restore-tested.
After installation, review the generated configuration rather than replacing it with an example from another machine. Keep the generated hardware configuration and existing system.stateVersion. A minimal addition for a named server with SSH access could look like this:
{ config, pkgs, ... }:
{
networking.hostName = "lab-node";
services.openssh.enable = true;
networking.firewall.allowedTCPPorts = [ 22 ];
environment.systemPackages = with pkgs; [
git
vim
];
}
This is an illustration to merge into the installed configuration, not a complete replacement for the generated file. Before applying SSH changes, configure a non-root account and an authentication method you have tested from another device, and keep local console access available. Only expose the services and ports required by the host; a firewall rule does not provide authentication or protect a service from vulnerabilities.
Save the configuration in version control so changes can be inspected and recovered. If it is stored remotely, keep credentials and secret material out of the repository. For more than one machine, factor out shared settings but leave hardware-dependent and host-specific values explicit. A configuration-management guide to Ansible explains a complementary approach for systems that are not running NixOS.
Check and activate a change from the server:
sudo nixos-rebuild dry-build
sudo nixos-rebuild switch
sudo nixos-rebuild list-generations
sudo systemctl status sshd --no-pager
dry-build catches evaluation or build problems before activation, but it does not prove that a service is reachable or that application data is intact. After switch, verify the service from a second machine and inspect its logs if it does not behave as expected:
sudo journalctl -u sshd -b --no-pager
If the new generation prevents normal startup, use the bootloader to select a previous generation or recover through local console access. Then correct the configuration and rebuild. Keep a separate backup for application state: for example, ZFS snapshots and replication can be part of a data-protection plan, but snapshots on the same failed disk are not an independent backup.
Networking deserves its own plan. Reserve addresses for servers and avoid overlapping the LAN, VPN, and container subnets. RFC 1918 specifies private IPv4 address ranges used inside private networks; it does not make those networks secure or guarantee that independently chosen address ranges will not conflict.
If the server will host Kubernetes, treat the operating system and cluster as separate layers: NixOS configures the host, while Kubernetes manages workloads. The Kubernetes homelab guide covers cluster sizing, networking, storage, and recovery decisions.
Common Misconceptions
NixOS makes the whole server immutable. The system configuration is declarative, but services can write mutable data and administrators can still make changes outside the configuration. Configuration management works best when the intended source of truth is clear.
A previous generation is a backup. Generations can help recover from a broken operating-system update. They do not restore a deleted database, protect against disk failure, or guarantee that an application can read older data after a schema change.
The same configuration always produces an identical server. Reproducibility depends on the inputs that are pinned, the hardware and boot environment, and any external services or mutable state. A lock file can control declared Nix inputs, but it is not a complete backup or disaster-recovery plan.
Related Articles
- Kubernetes Homelab: How to Build a Small Cluster
- Mini PC Build Guide for Development Environments
- Configuration Management with Ansible: A Beginner’s Complete Guide
- ZFS Snapshots and Replication
- Home Lab Network Segmentation with VLANs
Changelog
- Initial publication.

