# nix-config A single Nix flake for provisioning both NixOS hosts and non-NixOS systems (any Linux now; macOS via nix-darwin later) from one shared set of modules. ## Layout - `flake.nix` — inputs (`nixpkgs`, `home-manager`) and outputs (`nixosConfigurations`, `homeConfigurations`, `formatter`, `devShells`) - `lib/` — `mkNixos` and `mkHome` helper functions that build `nixosConfigurations` / `homeConfigurations` entries - `modules/nixos/common.nix` — shared NixOS-only system settings applied to every NixOS host: flakes enabled, `tom` user (bash as the login shell), locale/timezone defaults, gc policy, sshd (key-only auth) with a firewall allowing port 22, and a GNOME desktop (GDM login, NetworkManager, PipeWire audio, CUPS+Avahi printing) — see below - `modules/home/` — the shared, cross-platform home-manager profile (shell, editor, CLI tools, dev tools, dotfiles). The same modules are consumed whether activated via a NixOS host's home-manager module or standalone `home-manager switch` - `users/tom.nix` — identity/profile file consumed by both `mkNixos` and `mkHome` - `hosts/template/` — a copy-source-only NixOS host skeleton; **never** wired into `flake.nix` outputs directly (excluded from discovery by name — see below). Copy it via `scripts/bootstrap-host.sh` (or `nix run .#bootstrap-host`) when provisioning a real machine - `scripts/bootstrap-host.sh` — scaffolds a new `hosts//` from the template; exposed as `apps..bootstrap-host` - `modules/home/dotfiles.nix` — opt-in personal dotfiles automation (see below) - `modules/home/bash-profile.nix` — always-on `~/.bash_profile` bootstrap (see below) - `modules/home/editor.nix` — Neovim provisioning; deliberately never writes to `~/.config/nvim` (see below) Any directory under `hosts/` other than `hosts/template` that contains a `system` file automatically becomes a real `nixosConfigurations.` output — adding a host means dropping in a directory, not editing `flake.nix`. ## Installing NixOS on a new machine This flake does not partition disks for you — do that first, with the standard NixOS installer or manually. 1. Partition and format disks; mount the target filesystems under `/mnt` (including `/mnt/boot` for the ESP if UEFI). 2. Get this repo onto the installer: `nix-shell -p git && git clone ~/nix-config` (requires the repo already pushed to a remote — see Follow-ups below). 3. From `~/nix-config`, scaffold the host: ``` nix run .#bootstrap-host -- --root /mnt --state-version ``` `--root /mnt` tells the script to read (or generate, via `nixos-generate-config --root /mnt` if needed) `hardware-configuration.nix` from the freshly mounted install target — it never reads the live installer's own `/etc/nixos`, since `--root` has no default and must always be given explicitly. `--state-version` should match the installer's NixOS release (e.g. `24.05`) and should never be changed after the fact. 4. Review `hosts//configuration.nix` (boot loader choice, etc.) — the script prints this reminder along with the exact next commands. 5. `cd ~/nix-config && git add hosts/` (flakes only see git-tracked files). 6. If needed: `export NIX_CONFIG="experimental-features = nix-command flakes"`. 7. `nixos-install --root /mnt --flake ~/nix-config#`. 8. Reboot and remove the install media. 9. Afterwards, clone the flake to a stable path (e.g. `/etc/nix-config`) so future updates are just `sudo nixos-rebuild switch --flake /etc/nix-config#`. ## Desktop environment Every NixOS host built from this flake boots into a GNOME desktop by default (GDM as the login manager), applied unconditionally in `modules/nixos/common.nix` rather than as a per-host opt-in. Necessary companions are enabled alongside it: `networking.networkmanager` (GNOME's own network settings UI), `services.pipewire` + `security.rtkit` (audio, including PulseAudio-compatible clients), and `services.printing` (CUPS) + `services.avahi` (`nssmdns4`, `openFirewall`) for printing and network/AirPrint printer discovery — `openFirewall` is required so mDNS discovery traffic isn't blocked by the port-22-only firewall this repo already enables. This is a system-level toggle only; per-user GNOME customization (dconf, Shell extensions) is out of scope. ## Installing on a non-NixOS system (any Linux, or macOS once supported) Non-NixOS hosts are unaffected by `bootstrap-host` — there's nothing per-host to scaffold. `homeConfigurations` has one generic entry per platform (`tom@linux` for x86_64-linux, `tom@darwin` for aarch64-darwin), shared by every standalone machine of that platform. 1. Install Nix. Recommended: the [Determinate Systems installer](https://github.com/DeterminateSystems/nix-installer) (flakes enabled by default). The official installer also works, but you'll need to add `experimental-features = nix-command flakes` to `nix.conf` yourself. 2. `git clone ~/nix-config`. 3. First run: `nix run home-manager/master -- switch --flake ~/nix-config#tom@linux` (or `#tom@darwin` on macOS). After that, `home-manager switch --flake ~/nix-config#tom@linux` (or `#tom@darwin`) works directly. This only touches your home directory — no sudo required. ## Personal dotfiles (opt-in) `modules/home/dotfiles.nix` can automatically clone a separate personal dotfiles repo to `~/dotfiles` and symlink its top-level package directories into `$HOME`, GNU-Stow style (each package directory's contents mirror their target path — e.g. a package's `.gitconfig` links to `~/.gitconfig`). It's opt-in and controlled by a single option: ```nix home.dotfiles.repoUrl = "https://example.com/your/dotfiles.git"; ``` `users/tom.nix` sets this to `https://git.tomvanderlee.com/dotfiles` — the feature is active as soon as this flake is activated with `home-manager switch`. Behavior notes: an existing `~/dotfiles` checkout is never re-cloned or modified; every non-hidden top-level directory is treated as a stow package; one package's conflict with an existing file only skips that package (a warning is printed) rather than blocking the rest. Because `~/dotfiles/git/.gitconfig` and `~/dotfiles/bash/.bashrc` are expected to be the sole sources of git and bash configuration once stowed, this repo's own `programs.git`/`programs.bash` home-manager management has been removed — `git` itself is still installed via `modules/home/cli-tools.nix`, and `bash` ships with both macOS and NixOS regardless of whether `repoUrl` is set. ## Editor (Neovim) `modules/home/editor.nix` installs Neovim as the default editor (`$EDITOR`/`$VISUAL`, plus a `vim` alias), and provisions a C compiler (`pkgs.stdenv.cc`) and the `tree-sitter` CLI so natively-built plugins can compile. It deliberately sets `programs.neovim.sideloadInitLua = true`, which stops home-manager from writing anything to `~/.config/nvim/init.lua` — that path is owned exclusively by the personal dotfiles repo's `neovim` Stow package (lazy.nvim + plugins). Without `sideloadInitLua`, home-manager's own generated `init.lua` permanently conflicts with that Stow package and it gets silently skipped (per the dotfiles automation's skip-on-conflict behavior above), so plugins never load. **Don't add `programs.neovim.extraConfig`/`plugins`/anything else that writes into `~/.config/nvim` here** — it would reintroduce the same conflict. ## Login shell bootstrap NixOS and most other Linux distros don't ship a `~/.bash_profile` that sources `~/.bashrc`, so login shells never pick up your bash config. `modules/home/bash-profile.nix` creates one for you — but only if `~/.bash_profile` doesn't already exist. If it's already there (any file or symlink), it's left completely untouched; home-manager never edits or removes it. This is always on, on every platform (Linux and macOS), and isn't gated by `home.dotfiles.repoUrl` — it works whether or not you use the personal dotfiles automation above. ## Developer tooling `modules/home/dev-tools.nix` provisions the developer's most-used CLI tools: `gh`, `tmux`, `htop`, `yq-go`, `tree-sitter`, `docker`, `docker-compose`, `kubectl`, `awscli2`. The container/cloud entries (`docker`, `docker-compose`, `kubectl`, `awscli2`) are client/CLI tools only — the actual container runtime (OrbStack/Docker Desktop on macOS) and any cloud account configuration stay outside Nix's control; these just give you a consistent CLI version to talk to whatever runtime/account is already set up. `terraform` was considered but deliberately left out: recent versions are unfree-licensed (HashiCorp's BSL), which would require either `nixpkgs.config.allowUnfree = true` (flake-wide, not just for terraform) or substituting `opentofu`. Neither was wanted for now. **Shell and prompt**: bash is the primary managed shell (matching where the real shell config already lives — `~/dotfiles/bash/.bashrc`). `modules/home/shell.nix` only provisions the `liquidprompt` package; its configuration and activation are entirely owned by `~/dotfiles/liquidprompt/`, same as git and bash. There is no Nix-managed `starship` or `direnv` — both were removed; per-project environments are left entirely to your existing pyenv/nvm/rustup setup rather than a Nix-managed alternative. ## Development - `nix fmt` — format all `.nix` files with `nixfmt-rfc-style`. - `nix develop` — a shell with `statix` and `deadnix` for linting. - `nix flake check` — validates `homeConfigurations."tom@linux"`, `apps.bootstrap-host`, and the other outputs defined here (there are no real `nixosConfigurations` until a host is scaffolded — see Follow-ups). ## Follow-ups (not covered by this change) - Push this repo to a remote — required before `nixos-install` can `git clone` it during a real install. - Add a real NixOS host once hardware has been partitioned (see workflow above). - Add nix-darwin once a real Mac host is being configured. - Add secrets management (e.g. sops-nix) — none is set up yet.