The Coding Adventure
  • About
  • Blog
  • Mobile Dev Adventure

Categories

  • Books
  • Case studies
  • Monthly reports
  • Programming
  • Self-development
  • Yearly reports
30 Feliratkozó
The Coding Adventure
  • About
  • Blog
  • Mobile Dev Adventure
  • Magyar
  • Home Programming NixOS: Stop Configuring Servers Like It’s 2009

    NixOS: Stop Configuring Servers Like It’s 2009

    Table of Contents
    1. The Problem with Traditional Server Configuration
    2. There Has to Be a Better Way
    3. The NixOS Approach
    4. Core Concepts of Nix & NixOS
    5. Powerful Tools in the Nix Ecosystem
      1. Nix Flakes
      2. Home Manager
      3. Secrets with agenix
      4. Package Customization (Overlays)
      5. Containers and Partitions
    6. Where to learn more about Nix and NixOS?
    7. How I like my configuration?
    8. Real Example: Deploying to Hetzner
    9. Conclusion

    If you’ve ever inherited a server that nobody understands, fought with outdated scripts, or tried to document a setup only to forget what half of it meant a week later — you’re not alone.

    I got tired of all that.

    So I started using NixOS. It’s a weird Linux distro where everything is defined in config files, but once it clicks, it’s a total game-changer. You write your system like code, commit it to Git, and suddenly your servers are predictable, reproducible, and way less stressful.

    Of course, this can be used on your daily device as well, you will get the same benefits, and the great thing is, macos also supports it. 😊

    In this guide we will mainly focus on servers, because it has the biggest benefits on them for most of us. Also, this guide is focused on teaching and describing the core motivators towards this approach. Do not expect advanced stuff, but a clear example is being shown later.

    Let me show you why I think it’s the best approach — and how you can get started.

    The Problem with Traditional Server Configuration

    You know the story.

    There’s a guy who sets up the server. He installs packages, tweaks configs, maybe writes a bash script or two… and then disappears. No one knows what he did, or how to recreate it. Maybe there’s a README. Maybe.

    Even if you do have documentation, there’s no guarantee it’s actually correct or up to date. People forget to update it or just says “install Docker” and calls it a job done. Even worse, people think they updated it, but the system drifts over time — someone tweaks a setting directly on the machine, forgets to tell anyone, and now you’re in config hell.

    Now it’s your problem.

    There Has to Be a Better Way

    What if the system’s configuration wasn’t a mystery?

    What if you could just look at a file and know exactly how a server is supposed to be built — from user accounts, to services, to file systems, to installed packages?

    Even better: what if you could build that same exact system again, on any machine, with zero guesswork?

    That’s where Nix and NixOS come in.

    The NixOS Approach

    Nix is a powerful package manager. NixOS is a full Linux distribution built around it.

    With NixOS, you write a configuration file (literally just a .nix file) that describes exactly how your system should look. Users, packages, services, partitions, networking — everything is declared.

    Then, NixOS builds the system from that config. No magic. No surprises.

    It is:

    • Declarative: Define what you want, not how to get there.
    • Reproducible: Build the same system on any machine.
    • Rollback-able: Every change creates a new “generation” you can roll back to if something breaks.

    Core Concepts of Nix & NixOS

    With NixOS, you don’t “configure” a system by manually running commands or editing files on the server.

    Instead, you write a configuration file (or several) that declares what the system should look like.

    Example defining a service and a user:

    services.nginx.enable = true;
    users.users.alice = {
      isNormalUser = true;
      extraGroups = [ "wheel" ];
    };

    This tells NixOS:

    • “This machine should have Nginx running.”
    • “There should be a user named Alice, and she should have admin rights.”

    You define the desired end state, and NixOS figures out how to get there. It’s infrastructure as code, built into the OS.

    Every package, service, and configuration in Nix is stored in a content-addressed store. That means:

    • The system you build today can be rebuilt exactly the same way tomorrow.
    • You can build the same system on your laptop, your server, your Raspberry Pi, etc.

    No “it works on my machine” issues. No “depends on version X.Y of a package.” Everything is pinned and controlled.

    This also means you can:

    • Share configs across machines
    • Roll out updates with confidence
    • Archive known-good states forever

    It’s like Docker, but for your whole operating system.

    Every time you apply a new configuration (nixos-rebuild switch), NixOS creates a new generation. Think of it like a snapshot of the system state at that moment.

    If something breaks? Just roll back:

    sudo nixos-rebuild switch --rollback

    Or even pick a previous generation at boot time from the GRUB menu.

    This makes experimentation safe:

    • Try new services without fear
    • Break your system and undo it with one command
    • Update without worrying about “what if this goes wrong”

    It’s like git, but for your system state.

    Powerful Tools in the Nix Ecosystem

    Nix isn’t just a package manager or an OS — it’s a whole ecosystem of tools that make configuring and managing systems way more powerful (and less painful). Here’s a breakdown of some of the most useful ones.

    Nix Flakes

    Flakes are like modules or blueprints. They help you structure your config in a reusable, versioned way.

    With flakes, you can:

    • Define multiple systems (e.g. laptop, server, container) in one place
    • Pin dependencies to exact versions
    • Share your config with others (or your future self)

    Home Manager

    Want to manage per-user configs like dotfiles, shells, themes, and secrets?

    Home Manager lets you:

    • Set up ZSH/Bash configs, themes, aliases
    • Define per-user packages and environment variables
    • Manage dotfiles and editor settings in a clean, consistent way

    Instead of manually editing your .bashrc, .vimrc, .zshrc, etc., you can define everything in a Nix config and rebuild your user environment just like your system.

    programs.zsh.enable = true;
    programs.zsh.ohMyZsh.enable = true;
    home.file.".vimrc".text = "set number";

    Each user can have their own config — no more “one size fits none” setups.

    Secrets with agenix

    Handling secrets is tricky in any config system. agenix makes it sane with Nix.

    How it works:

    • Secrets are encrypted using age, and stored safely in your git repo
    • Only specific machines (based on their SSH keys) can decrypt them at build time
    • No more plain-text secrets in config files or env variables

    Use case:

    • API keys, passwords, tokens, DB creds
    • Split secrets per host or per user
    • Store and share encrypted secrets with confidence

    Package Customization (Overlays)

    Overlays let you override or extend existing Nix packages. Want to patch a package? Add your own version of something? Build from a Git repo instead of a release tarball? Use overlays.

    Use case:

    • Replace neovim with a custom fork
    • Apply patches to broken dependencies
    • Add local packages without modifying the upstream repo

    Super useful for fine-tuning your stack or testing bleeding-edge features.

    You can write your own packages in Nix as well. The learning curve is real, but once you get the hang of it, it’s ridiculously powerful.

    Use case:

    • Package your in-house software with pinned dependencies
    • Share CLI tools across your team without weird install instructions
    • Deploy custom software in servers/containers exactly how you want

    Containers and Partitions

    Managing containers and partitions should not be hard if you use the right tool for it.

    You can define full-blown containers in Nix, with the same declarative power as the rest of the system.

    Use case:

    • Define containers just like you’d define a service
    • Control the base image, packages, users, and behavior
    • Replace or complement Docker/Podman for full reproducibility

    On the other hand, need to manage disk layouts in code too? Use disko.

    Disko lets you:

    • Define partitions, formats, mount points, and RAID/LVM layouts in Nix
    • Use the same layout across multiple machines
    • Automate the boring and error-prone setup step during installs

    No more manually typing fdisk and hoping you didn’t mess it up.

    Where to learn more about Nix and NixOS?

    Getting into Nix can feel overwhelming at first — but there’s a solid community and a growing number of resources that make the learning curve way more manageable.

    Before you dive into flakes, overlays, or secret management, it’s important to get a grip on the basics:

    • Zero to Nix — A fantastic beginner-friendly guide that walks through Nix fundamentals, package management, and basic system configuration.
    • The Official NixOS Manual — Covers everything from installation to advanced modules. A bit dense, but incredibly valuable once you’re familiar with the basics.

    One of the best ways to learn Nix is by studying real-world setups. Many developers share their full configs publicly — and they’re full of useful patterns, tricks, and module structures.

    One of the bests: https://github.com/ryan4yin/nix-config

    How I like my configuration?

    Now let’s see how I would setup a completely new server.

    Real Example: Deploying to Hetzner

    To deploy a configuration to a remote server, you typically use tools like nixos-rebuild with the --target-host flag, or more advanced tools like NixOps, Morph, or Colmena. These tools manage the process of transferring configuration files and building or switching the system remotely.

    You have two main strategies: build locally and send the result to the server, or send the configuration and build remotely. The choice between these depends on available compute power, bandwidth, and the desired trust model.

    Building locally is often faster if your development machine is more powerful or has cached dependencies, and it avoids needing a full Nix build environment on the target. This can be done using nix copy to transfer closures or with nixos-rebuild --build-host to build locally.

    Remote builds, on the other hand, are useful when the server has unique hardware, kernel modules, or system-specific dependencies. They also reduce the amount of data transferred over the network, since only the configuration needs to be sent, not the full derivation result.

    I prefer remote building, but you can decide.

    If you clone my configuration make sure you replace my SSH keys in the configuration, especially in the init-server.sh and in the user related settings.

    My config: https://github.com/TheVitya/nix

    Commands used in the video:

    curl -sL https://raw.githubusercontent.com/TheVitya/nix/main/init-server.sh | bash

    power off


    ssh HOST_NAME

    copy the hardware config

    rsync -av –exclude-from=’rsync-exclude.txt’ . HOST_NAME:/etc/nixos/

    ssh HOST_NAME

    cd /etc/nixos

    nixos-rebuild switch –flake .#HOST_NAME

    Conclusion

    Nix and NixOS is a tool that makes my workflows reliable. For a long time I was just playing around and trying to make things happen, but I had to realize that would not go long. Thankfully, this approach works now.

    Previous Article

    Copywriting – The “secret” skill everybody speaks about, but says nothing

    Read
    Next Article

    Idea Validation: Why It’s Essential Before Starting a Business

    Read
    Ezek is értékesek lehetnek
    Read
    • Programming

    Introduction to programming languages

    • viktor
    • December 13, 2023
    • About
    • Blog
    • Mobile Dev Adventure

    Input your search keywords and press Enter.