NixOS for Reproducible Infrastructure
Context
I required an operating system that could eliminate the 'it works on my machine' paradox across my daily driver, development environment, and production servers. I needed a way to manage system configurations as code to ensure 100% parity and seamless recovery in case of hardware failure.
Decision
Adopt NixOS as the universal OS, utilizing a Flake-based architecture to manage a unified configuration for desktop (Wayland/Hyprland), dev environments, and remote server deployments.
Alternatives Considered
Arch Linux
- Bleeding-edge packages via the AUR
- Minimalist 'do-it-yourself' philosophy
- Imperative updates can lead to system breakage
- Difficult to replicate the exact state across multiple machines
Ubuntu/Debian (Standard LTS)
- Massive community support and stability
- Industry standard for server deployments
- Configuration drift over time
- PPA management becomes a 'dependency hell' at scale
Reasoning
NixOS treats the entire operating system as a pure function. By using a declarative configuration, I can guarantee that my desktop and server environments are identical where it matters. The ability to rollback instantly and manage per-project development shells via Nix-shell makes it the only choice for a truly robust, version-controlled lifestyle.
The Declarative Advantage
Switching to NixOS isn’t just a change in distribution; it’s a shift in mental model from imperative “state tinkering” to functional “state definition.”
1. Unified Desktop & Server Management
Using Nix Flakes, I maintain a single Git repository that defines my entire digital footprint.
- The Desktop: My daily driver runs a highly customized Wayland environment. If I want to change a font or a kernel parameter, I edit one
.nixfile and rebuild. - The Server: The same repository contains the configuration for my VPS. I share modules between them, such as SSH hardening, ZSH aliases, and Neovim configs, ensuring a consistent experience whether I’m local or remote.
2. Atomic Updates and Rollbacks
The fear of a system update breaking a workflow is eliminated. NixOS performs atomic upgrades:
- When I “rebuild” the system, Nix creates a new “generation” without touching the current working state.
- If a new driver causes a kernel panic, I simply select the previous generation at the bootloader and I’m back to work in seconds.
3. Isolated Development Environments
With Nix-shell (or nix develop), I no longer install compilers or language runtimes globally.
- Each project has its own
flake.nixdefining its dependencies (e.g., Python 3.11, PostgreSQL 15, and specific C libraries). - Entering the project directory automatically activates the environment. This keeps the host system “pure” and prevents version conflicts between different client projects.
Strategic Advantages of the Nix Ecosystem
Beyond the OS, the Nix package manager provides a level of control that traditional package managers cannot match:
- Immutable Store: Packages are stored in
/nix/storewith unique hashes. This allows multiple versions of the same library to coexist peacefully, solving the “DLL hell” of Linux. - Home Manager: I manage my dotfiles (VS Code settings, browser configs, terminal colors) using the same Nix language, ensuring my user environment is just as reproducible as the system kernel.
Results & Impact
- Zero Downtime Migration: When I upgraded my laptop hardware, I simply cloned my configuration repo and ran one command. My entire desktop environment was restored in 15 minutes.
- Server Parity: My staging server and production server are bit-for-bit identical, leading to zero deployment surprises.
- Efficiency: The time spent “fixing the OS” has dropped by roughly 80%, allowing more focus on actual engineering.
The Road Ahead
The next phase involves integrating Colmena or nix-darwin. This will allow me to deploy Nix configurations to my remote servers in parallel and potentially bring my macOS machines under the same declarative umbrella, creating a completely unified cross-platform ecosystem.