NixOS + home-manager flake

A flake-based NixOS and home-manager configuration: a set of reusable modules plus a ready-to-run example host that assembles them. Use it either way:

  • as a starting template — clone, swap in your hardware, rebuild; or
  • as modules — import them into your own (private) flake.

Quick start (template)

nix flake init -t github:<owner>/<repo>        # or: git clone …
# generate hardware config for THIS machine (the one file you must replace):
sudo nixos-generate-config --show-hardware-config > hosts/example/hardware-configuration.nix
# set your hostName + username in hosts/example/default.nix, then:
sudo nixos-rebuild switch --flake .#example

nixosConfigurations.example is a real, buildable machine assembled from the modules in modules/. It doubles as living documentation: it shows exactly how the modules wire together, so there's nothing to reverse-engineer. The only genuinely machine-specific file is hardware-configuration.nix (NixOS generates it); everything else works from defaults you can tweak.

Import the modules into your own flake

Add this repo as an input and assemble your machines in a private flake. Below is a realistic example layout. Structurally only flake.nix is required — every other path is just one way to organize your config; rename, merge, inline, or drop them freely. The one bit of content a bootable machine can't skip is its hardware-configuration.nix (nixos-generate-config output); the hosts/<host>/ directory is only where this example keeps it.

your-inventory/
├── flake.nix                        # inputs (baseline + your nixpkgs) + nixosConfigurations.<host>
├── flake.lock
├── system/                          # system-level modules
│   ├── regional.nix                 # time zone / keymap / locale (see Overriding)
│   ├── packages.nix                 # extra system packages
│   └── tailscale.nix                # VPN / network topology
├── home/                            # home-manager modules, one file per concern
│   ├── identity.nix                 # git identity, name/email
│   ├── ssh.nix                      # SSH hosts (topology — stays private)
│   ├── syncthing.nix                # Syncthing peers
│   └── …                            # personal apps: browser, editor, chat, …
└── hosts/
    └── myhost/
        ├── default.nix              # hostname, user account, host-specific system bits
        └── hardware-configuration.nix   # `nixos-generate-config` output

The flake.nix that wires it together:

{
  inputs = {
    # You own nixpkgs, so your update cadence is yours — the baseline modules
    # build against the versions you pin here.
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    home-manager.url = "github:nix-community/home-manager";
    home-manager.inputs.nixpkgs.follows = "nixpkgs";

    baseline.url = "github:<owner>/<repo>";
    baseline.inputs.nixpkgs.follows = "nixpkgs";        # baseline builds against YOUR nixpkgs
    baseline.inputs.home-manager.follows = "home-manager";
  };

  outputs = inputs@{ self, nixpkgs, baseline, home-manager, ... }: {
    nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [
        baseline.nixosModules.default     # generic system baseline
        ./system/regional.nix             # your regional values (see below)
        ./hosts/myhost                    # hardware + hostname
        home-manager.nixosModules.home-manager
        {
          home-manager.useGlobalPkgs = true;
          home-manager.useUserPackages = true;
          # Inject your own inputs into your home modules; the public ones ignore them.
          home-manager.extraSpecialArgs = { inherit inputs; };
          home-manager.users.me.imports = [
            baseline.homeModules.default    # generic home baseline
            ./home/identity.nix             # your git identity, name/email, …
            ./home/ssh.nix                  # your SSH hosts (topology stays private)
            # … more personal home modules
          ];
        }
      ];
    };
  };
}

This repo ships modules, not pinned packages: they build against the nixpkgs you declare above, so you decide when packages move. Quickstart alternative: drop your own nixpkgs and write nixpkgs.follows = "baseline/nixpkgs" to pin to this repo's tested versions instead — one less thing to think about, but then your update cadence is whatever this repo pins, not the reverse.

Your machine list, hostnames, and any private specifics stay in your flake — you pull only the generic modules from here.

Overriding the baseline

The public modules are a baseline you extend without forking. Three ways to shape them from your private flake, in rough order of how often you reach for them:

  1. Neutral default → your real value. Region-agnostic settings ship as mkDefault placeholders (console.keyMap = "us", time.timeZone = "UTC", en_US locale). Set the real ones in a private module — no mkForce needed:

    # system/regional.nix
    { time.timeZone = "Europe/Berlin"; console.keyMap = "de"; }
    
  2. local.* options. A module that exposes a knob puts it under the local.* namespace with a default. Override in one line, e.g. a fuller TeX Live:

    local.texlive.package = pkgs.texlive.withPackages (ps: [ ps.scheme-full ]);
    

    A few local.* options exist precisely because a module pins a package to a nixpkgs other than the one you declare (a deliberate freeze that would otherwise reach you regardless of your own pin); the option is how you pull it back onto your nixpkgs.

  3. Extra modules. Anything with no public counterpart is just another module in the import lists above — personal apps, SSH/Syncthing topology, secrets wiring.

Architecture: three layers

Kept apart on purpose. When adding config, decide which layer it belongs to:

  1. Modules — generic, public (this repo). Reusable building blocks under modules/, exposed as nixosModules.* / homeModules.*. Anything machine- or user-specific is a module option with a sane default — never hard-code personal values into a module.
  2. Inventory — topology, private (your flake). The actual machines: nixosConfigurations.<host>, per-host hosts/<host>/ (hardware, hostname), and topology-revealing config (SSH hosts, Syncthing peers, internal IPs). This is what you deploy from; it imports the modules above. Publish the modules, keep the inventory in a private repo. The example host here is a placeholder-filled stand-in for it.
  3. Secrets — neither repo. Private keys, tokens, passwords never enter any repo. Provide them as runtime files (0600, out-of-band) or via a secrets manager that decrypts to a runtime path; nix references only the path.

Layout

flake.nix            # inputs + outputs (nixosModules, homeModules, example host, devShells)
modules/             # the reusable library
hosts/example/       # the template host (placeholder hardware-configuration.nix)

Shared *.nix / *.lock live at the top level; per-host files under hosts/<host>/.

Chasing a shutdown/boot hang? modules/shutdown-debug.nix exposes local.shutdownDebug.* (verbose systemd logging to kmsg, a tty9 debug shell, a shortened stop-timeout) — see its header comment for how to read the evidence.

S
Description
No description provided
Readme
893 KiB
Languages
Nix 99.4%
Python 0.6%