Skip to content
Nikola-MilovicPublic

About

My Nix flake that contains all of my system configurations

Resources

Stars

3 stars

Watchers

2 watching

Forks

Repository files navigation

.dotfiles

Personal NixOS and macOS configuration flake. Built on snowfall-lib, with home-manager, nix-darwin, NixOS impermanence, and sops-nix.

Ported from my previous Ubuntu setup at .dotfiles-old.

What's In Here

  • NixOS workstation with Sway / Wayland
  • Impermanent NixOS root: only /nix, /boot, and /persist survive reboots
  • Apple Silicon MacBook managed with nix-darwin and Home Manager
  • SOPS + age for secrets, scoped per host
  • Custom xkb layouts on Linux, plumbed through to Sway keybindings
  • Darwin keyboard defaults for Dvorak, Caps Lock, and non-US tilde behavior
  • Homebrew-managed macOS apps through the Darwin layer

Repository Layout

Everything defined by this repo uses the custom. namespace.

Path Purpose
flake.nix Flake entry point and inputs
systems/ Per-host NixOS / nix-darwin configurations
homes/ Per-user Home Manager configurations
modules/nixos/ NixOS system modules
modules/darwin/ nix-darwin system and app modules
modules/home/ Home Manager modules
modules/shared/ Modules shared between system and home
lib/ Snowfall library extensions exposed under lib.custom.*
packages/ Custom packages surfaced as flake outputs
overlays/ nixpkgs overlays
shells/ Per-language nix develop shells
secrets/ SOPS-encrypted secrets
docs/ Operational notes and recovery runbooks

Hosts

  • systems/x86_64-linux/workstation - main NixOS desktop
  • systems/x86_64-linux/vm - virtualized test target
  • systems/aarch64-darwin/macbook - Apple Silicon MacBook

Common Commands

Use just as the normal entry point:

just switch          # Darwin: HM then sudo darwin-rebuild; Linux: sudo nixos-rebuild
just hm-switch       # standalone Home Manager switch
just darwin-switch   # sudo darwin-rebuild for macbook
just nixos-switch    # sudo nixos-rebuild for workstation

Development shells:

nix develop .#nix
nix develop .#go
nix develop .#lua

Run custom packages:

nix run .#backup
nix run .#monitor-control
nix run .#gammastep-helper
nix run .#waybar-vpn-status
nix run .#networkmon

Format the tree:

nix fmt

Operational Documentation

  • Workstation failsafes: memory-pressure prevention, earlyoom behavior, Magic SysRq commands, recovery order, and post-incident diagnostics.
  • Pins and patches: every version pin, overlay, and source patch that only works around an upstream bug, with its removal condition.
  • RustDesk: private relay and macOS/NixOS client setup.

macOS Package Policy

The rule for Darwin is:

  • CLI tools: use nixpkgs, Home Manager, flake inputs, overlays, or local packages.
  • GUI apps and macOS app bundles: use nix-darwin-managed Homebrew, with nix-homebrew as the preferred bootstrap layer if Homebrew ownership needs to be made fully declarative.

This keeps the Mac simple and reliable. Even if a nixpkgs package exposes a .app, pinning that app into the Dock can leave a missing question mark after rebuilds because the Dock points at an old store path. Use Homebrew casks for apps that live in /Applications.

Current examples:

  • ghostty and wezterm are Homebrew casks in modules/darwin/apps/terminals/default.nix
  • worktrunk is a Homebrew formula on macOS
  • worktrunk is installed from its upstream Nix flake on Linux

Darwin MacBook

Install Nix on a clean macOS machine:

curl -L https://nixos.org/nix/install | sh -s -- --daemon

Restart the terminal, then enable flakes for bootstrap:

mkdir -p ~/.config/nix
printf 'experimental-features = nix-command flakes\n' >> ~/.config/nix/nix.conf

Clone this repo:

mkdir -p ~/Desktop
cd ~/Desktop
git clone https://github.com/Nikola-Milovic/.dotfiles.git dotfiles
cd dotfiles

Install the MacBook age key before activating SOPS-backed Home Manager:

mkdir -p ~/.config/sops/age
install -m 600 ~/Downloads/macbook-keys.txt ~/.config/sops/age/keys.txt

Bootstrap with just through Nix:

nix run nixpkgs#just -- switch

After the first successful activation:

just switch

darwin-rebuild switch must run as root. The just recipes already do that with sudo.

Impermanence

The NixOS root filesystem is meant to be reset on every boot. It currently is not: boot.initrd.systemd.services.rollback in modules/nixos/system/impermanence/default.nix has wantedBy = [ ], so the wipe never runs (see the TODO below). Everything therefore survives whether or not it is opted in, which means the persist list is untested -- re-enabling the rollback would be the moment you discover which paths were never really persisted.

A files = [...] entry also fails loudly if a real file already sits at the target: the bind-mount helper refuses rather than clobbering it, the unit fails during just switch, and the two copies silently diverge. Fix it by moving the authoritative copy under /persist/... and starting the unit.

To keep state across reboots, opt in explicitly:

  • System state: modules/nixos/system/impermanence/default.nix
  • User state: modules/home/impermanence/default.nix
  • App-specific state: the relevant module's own impermanence block

Persistent data lives under /persist/... and is mounted back to where apps expect it. Before major changes, snapshot it:

nix run .#backup

Darwin does not use impermanence.

Codex

codex on the workstation talks to the self-hosted CodexLB in the prod Kubernetes cluster, reached only over the tailnet at https://codex-lb-prod.tail469983.ts.net. Runbook: docs/codex-lb.md in the frmlabz/infra repo.

The provider is configured in ~/.codex/config.toml, which is not managed by Nix. It authenticates with CODEX_LB_API_KEY, one key per machine. Codex has no dotenv support, so env_key needs a genuinely exported variable:

  • the key lives in a mode-0600 ~/.codex/env, never in the Nix store, which is world-readable;
  • modules/home/programs/terminal/common/default.nix sources that file from programs.bash.initExtra;
  • ~/.codex is persisted, so the key survives reboots.

A custom.services.codex-lb module used to run CodexLB locally as a Docker oci-containers unit. It was removed on 2026-08-18 when prod became authoritative: the unit had autoStart = true, so any rebuild would have started a second writer against a by-then-stale SQLite database.

Credits

Heavy inspiration and borrowed patterns from:

TODO

  • Security enhancements
  • Evaluate Looking Glass as an alternative to dual-booting
  • YubiKey setup
  • Fix sway brightness hotkeys
  • Wrong audio device picked as default
  • BTRFS rollback not working

About

My Nix flake that contains all of my system configurations

Resources

Stars

3 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages