KISS NixOS configuration based on Flakes & flake-parts (supports macOS too)
Find a file
Sridhar Ratnakumar 776c4425b0 incus-pet: shared /nix/store, restart-to-deploy, drop anywhen flake input
The incus-pet CLI gains three big changes that together cut per-container
disk usage by ~5GB, drop nix-rebuild + nix-copy from the deploy path, and
make `deploy` actually pull latest on every invocation. anywhen migrates
from a host-installed service to an incus-pet container in the process.

* Shared /nix/store mount. Each container gets host's /nix/store
  bind-mounted read-only (with shift=true for idmapped unprivileged
  containers). Zero per-container duplication of nixpkgs closures. The
  CLI builds toplevels on the host; the container sees them via the
  shared mount, no `nix copy` needed.

* Restart-to-deploy. switch-to-configuration is removed entirely (it
  was stalling on dbus-broker reload and hitting the same lock-
  contention bug across redeploys). New activation: update
  /nix/var/nix/profiles/system, repoint /sbin/init through the profile
  symlink, `incus restart`. The new toplevel's own init script handles
  /etc setup on boot. Trade-off: ~5s of container reboot per deploy.

* Marshaling flake exposes only nixosModules.default. No nixpkgs
  input, no nixosConfigurations entry. The CLI picks nixpkgs at build
  time (pinned to nixos-25.11 — matches the LXC image baseline, dodges
  unstable regressions) and assembles the full nixosSystem via
  `nix build --impure --expr`. Lets us bump nixpkgs without touching
  per-deploy state.

* `nix flake update --refresh` on every deploy. Was `nix flake lock`,
  which only locks first-seen inputs — re-deploying `github:srid/anywhen`
  stayed pinned at the first commit ever resolved. Now every deploy
  bumps the target input to the current tip of its ref and bypasses
  nix's fetcher cache.

* /sbin/init repoint. The NixOS LXC image hard-links /sbin/init to its
  own toplevel's init path. Without switch-to-configuration, `incus
  restart` re-execs that old init, which sets up /etc from the old
  toplevel — running services keep using the OLD anywhen binary even
  though the profile pointer moved. CLI now also does
  `ln -sfn /nix/var/nix/profiles/system/init /sbin/init` so the profile
  actually drives boot. Idempotent.

* Host gcroot via `nix-store --add-root --indirect`. Container's nix DB
  doesn't know about the path (it lives behind the shared mount), so
  without a host-side gcroot the host could nix-collect-garbage the
  running system out from under the container. Symlink at
  ~/.local/state/incus-pet/<name>/system. Only the LATEST toplevel is
  pinned per app — no rollback today (file a 5-line ring buffer when
  rollback matters).

* anywhen flake input removed. `modules/nixos/linux/anywhen.nix` is
  gone; the host config no longer imports anywhen as a flake input.
  The deploy command takes the flake ref as an argument, so locking it
  here was just bloat. `just pureintent anywhen-deploy` runs the
  current invocation.

* pureintent ops recipes. New `configurations/nixos/pureintent/mod.just`
  with anywhen-{deploy,rm,backup,restore,status,shell}. Namespaced via
  `mod pureintent` so each host's recipes live behind their own prefix.

* Drop ssh from deploy path. Bootstrap still pushes the operator's
  pubkey (for interactive debugging), but activation goes through
  `incus exec` exclusively. No NIX_SSHOPTS, no nix-copy-via-ssh,
  no host-key TOFU dance during deploys.

Tested end-to-end on pureintent: anywhen migrated from host-installed
(21-task SQLite DB at /var/lib/anywhen) to an incus-pet container with
the DB intact; hello-web deployed fresh with shared /nix/store; both
serve over the tailscale proxy at 100.122.32.106:{6111,8081}; lock
bumps + new toplevels confirmed after master advances.
2026-05-23 18:50:10 -04:00
.vscode vscode: nushell 2025-07-22 10:27:01 -04:00
AI Upstreamed 2026-04-09 17:49:46 -04:00
configurations incus-pet: shared /nix/store, restart-to-deploy, drop anywhen flake input 2026-05-23 18:50:10 -04:00
docs i 2026-05-23 10:27:31 -04:00
doom.d doom: disable 2024-11-18 12:04:59 -05:00
modules incus-pet: shared /nix/store, restart-to-deploy, drop anywhen flake input 2026-05-23 18:50:10 -04:00
overlays opencode: use upstream juspay/oc home module (#105) 2026-03-12 18:18:51 -04:00
packages twitter-convert, restore minimally 2026-05-20 08:06:44 -04:00
secrets Update juspay llm key 2026-03-02 10:26:58 -05:00
.envrc envrc: Fix devshell path 2025-06-25 18:06:30 +10:00
.gitattributes chore: Redundant entry 2024-06-21 19:46:58 -04:00
.gitignore Ignore .codex 2026-04-23 12:32:31 -04:00
.gitmodules Remove submodules entirely 2026-03-14 09:22:23 -04:00
CLAUDE.md Add hackage-publish.nix, to be tested 2025-08-28 05:31:50 +05:30
config.nix Remove unused 2024-09-28 22:51:12 -04:00
flake.lock incus-pet: shared /nix/store, restart-to-deploy, drop anywhen flake input 2026-05-23 18:50:10 -04:00
flake.nix incus-pet: shared /nix/store, restart-to-deploy, drop anywhen flake input 2026-05-23 18:50:10 -04:00
justfile incus-pet: shared /nix/store, restart-to-deploy, drop anywhen flake input 2026-05-23 18:50:10 -04:00
README.md Remove submodules entirely 2026-03-14 09:22:23 -04:00
vira.hs ci: Add vira 2025-10-21 08:31:21 -04:00

AGPL

This is my Nix / NixOS configuration for all of my systems. See nixos-unified—specifically nixos-unified-template—if you wish to create your own configuration from scratch.

Setup

If you are using this repository as a starting template for your own configuration, perform these initial steps:

  1. Edit config.nix in the repository root to set your primary user information (username, fullname, email, sshKey).
  2. Replace the SSH keys in secrets/secrets.nix with your own, or delete the file if you do not use agenix.
  3. Delete any files in configurations/ that you do not need, and create/rename files to match your hostnames.

After preparing your template, to install on a new machine running:

NixOS Linux

Tip

For a general tutorial, see https://nixos.asia/en/nixos-install-flake

macOS

  • Install Nix
  • Clone this repo anywhere
  • Run nix run.1 That's it. Re-open your terminal.

Architecture

Start from flake.nix (see Flakes). flake-parts is used as the module system.

Directory layout

Tip

See flake-module.nix for autowiring of flake outputs based on this directory structure.

Path Corresponding flake output
./configurations/{nixos,darwin,home}/foo.nix {nixos,darwin,home}Configurations.foo
./mdules/{nixos,darwin,home,flake-parts}/foo.nix {nixos,darwin,home,flake}Modules.foo
./overlays/foo.nix overlays.foo
./packages N/A (Nix packages)
./secrets N/A (agenix data)

Tips

  • To update NixOS (and other inputs) run nix flake update
    • You may also update only primary inputs:
      # nix run .#update
      
  • To free up disk space,
    sudo nix-env -p /nix/var/nix/profiles/system --delete-generations +2
    sudo nixos-rebuild boot
    
  • To autoformat the project tree using nixpkgs-fmt, run just lint in Nix devShell.
  • To build all flake outputs (locally or in CI), run nix run nixpkgs#omnix ci
  • For secrets management, I use agenix, because it works with SSH keys, and functions well on macOS and NixOS.

Discussion

https://github.com/srid/nixos-config/discussions


  1. You might have to rm -rf /etc/nix/nix.conf, so our flake.nix can do its thing. ↩︎