Skip to content

Latest commit

Β 

History

554 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🏠 Nix Configuration

NixOS nix-darwin License CI

Personal NixOS & nix-darwin configuration with a modular, hierarchical architecture.

Why Nix?

"Works on my machine" β†’ "Works on every machine"

Nix is a purely functional package manager that treats system configuration as code. The same configuration always produces the same system β€” whether you're setting up a fresh laptop or rebuilding after a disaster. Made a mistake? Just boot into a previous generation and you're back to a working state in seconds.

Everything is declarative: packages, services, dotfiles, even your desktop environment. No more scattered configs or forgotten setup steps. Your entire system lives in version-controlled .nix files that work across all your machines β€” Linux desktops, macOS laptops, headless servers.

Updates are atomic (they fully apply or don't touch anything), and different package versions coexist peacefully. No dependency hell, no "I updated X and now Y is broken". Just reproducible, reliable systems.


✨ Features

  • πŸ–₯️ Multi-platform β€” Same structure for NixOS and macOS (nix-darwin)
  • πŸ‘₯ Multi-user ready β€” Each user can have different modules enabled
  • 🎯 Hierarchical enables β€” Enable at any path level: home.browsers.enable or home.browsers.vivaldi.enable
  • ✏️ Live-editable dotfiles β€” Config files are symlinked to this repo, edit in place without rebuild
  • πŸ” Auto-discovery β€” Drop a .nix file in any module directory, it's automatically imported

πŸ“‘ Table of Contents


πŸš€ Quick Start

# Clone the repository
git clone https://github.com/gdr/dot.git ~/Workspaces/gdr/dot
cd ~/Workspaces/gdr/dot

# Apply configuration
# NixOS:
sudo nixos-rebuild switch --flake .#<hostname>

# macOS:
darwin-rebuild switch --flake .#<hostname>

πŸ— Architecture

Architecture Diagram

graph TD
    subgraph Inputs["Flake Inputs & Outputs"]
        FI["flake.nix Inputs<br/>(nixpkgs, nix-darwin, home-manager, sops-nix, vantage)"]
        FO["flakeOutputs<br/>(nixosConfigurations, darwinConfigurations, packages, devShells, checks, formatter)"]
        FI --> FO
    end

    subgraph Hosts["Host Configurations"]
        NG["nix-goldstar<br/>(NixOS Desktop)"]
        NO["nix-oldstar<br/>(NixOS Server)"]
        MB["mac-brightstar<br/>(Darwin Laptop)"]
        FO --> NG
        FO --> NO
        FO --> MB
    end

    subgraph Profiles["Profiles & Users"]
        U["User Defaults<br/>(hosts/users/dgarifullin.nix)"]
        P["Profiles & Enables<br/>(developer, desktop, server, gaming)"]
        NG --> U
        NO --> U
        MB --> U
        U --> P
    end

    subgraph Modules["Module System"]
        HM["User Modules (mkModuleV2)<br/>modules/home/*"]
        SM["System Modules (mkSystemModuleV2)<br/>modules/systems/{all,linux,darwin}/*"]
        P --> HM
        P --> SM
    end

    subgraph Targets["System State & Config"]
        DOT["Live-Editable Dotfiles<br/>(mkDotfilesSymlink β†’ ~/.config/*)"]
        SECR["SOPS Secrets<br/>(sops-nix / age / Bitwarden integration)"]
        HM --> DOT
        SM --> SECR
    end
Loading

Directory Structure

.
β”œβ”€β”€ flake.nix                 # Entry point - defines hosts and imports
β”œβ”€β”€ hosts/
β”‚   β”œβ”€β”€ users/                # User defaults (imported by machines)
β”‚   β”‚   └── dgarifullin.nix
β”‚   └── machines/             # Machine configurations
β”‚       β”œβ”€β”€ nix-goldstar/     # NixOS host
β”‚       β”‚   β”œβ”€β”€ default.nix
β”‚       β”‚   └── hardware-configuration.nix
β”‚       └── mac-brightstar/   # Darwin host
β”‚           └── default.nix
β”œβ”€β”€ lib/
β”‚   └── default.nix           # Helper functions (mkModule, mkDotfilesSymlink)
β”œβ”€β”€ modules/
β”‚   β”œβ”€β”€ _core/                # Core module infrastructure
β”‚   β”‚   β”œβ”€β”€ registry.nix      # Module registry builder
β”‚   β”‚   └── user.nix          # hostUsers options & home-manager setup
β”‚   β”œβ”€β”€ systems/
β”‚   β”‚   β”œβ”€β”€ all/              # Cross-platform system modules
β”‚   β”‚   β”‚   β”œβ”€β”€ fonts.nix
β”‚   β”‚   β”‚   β”œβ”€β”€ nix/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ gc.nix
β”‚   β”‚   β”‚   β”‚   └── settings.nix
β”‚   β”‚   β”‚   └── shell/
β”‚   β”‚   β”‚       β”œβ”€β”€ git.nix
β”‚   β”‚   β”‚       └── ssh.nix
β”‚   β”‚   β”œβ”€β”€ linux/            # Linux-only system modules
β”‚   β”‚   β”‚   β”œβ”€β”€ desktop/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ awesomewm/
β”‚   β”‚   β”‚   β”‚   └── hyprland/
β”‚   β”‚   β”‚   β”œβ”€β”€ graphics/
β”‚   β”‚   β”‚   β”œβ”€β”€ keyboards/
β”‚   β”‚   β”‚   β”œβ”€β”€ networking/
β”‚   β”‚   β”‚   └── sound.nix
β”‚   β”‚   └── darwin/           # macOS-only system modules
β”‚   └── home/                 # User-level modules (enabled hierarchically)
β”‚       β”œβ”€β”€ browsers/
β”‚       β”œβ”€β”€ cli/
β”‚       β”œβ”€β”€ desktop/
β”‚       β”‚   β”œβ”€β”€ appearance/
β”‚       β”‚   β”œβ”€β”€ services/
β”‚       β”‚   β”œβ”€β”€ utils/
β”‚       β”‚   └── widgets/
β”‚       β”œβ”€β”€ editors/
β”‚       β”œβ”€β”€ games/
β”‚       β”œβ”€β”€ media/
β”‚       β”œβ”€β”€ messengers/
β”‚       β”œβ”€β”€ security/
β”‚       β”œβ”€β”€ shell/
β”‚       └── terminal/
└── pkgs/                     # Custom packages

Module Types

Type Location Enabled via Scope
System (All) systems/all/ modules.system.all.<name>.enable System-wide, cross-platform
System (Linux) systems/linux/ modules.system.linux.<name>.enable System-wide, Linux only
System (Darwin) systems/darwin/ modules.system.darwin.<name>.enable System-wide, macOS only
User home/ hostUsers.<user>.modules.<path>.enable Per-user, hierarchical enables

πŸ“– Guides

Create a New Host

  1. Create host directory:
mkdir -p hosts/machines/my-new-host
  1. Create default.nix:
# hosts/machines/my-new-host/default.nix
{ config, lib, pkgs, ... }:
let
  importUser = name: import ../../users/${name}.nix { inherit lib; };
in
{
  imports = [ ./hardware-configuration.nix ];

  # User configuration
  hostUsers.dgarifullin = importUser "dgarifullin" // {
    enable = true;
    keys = [{
      name = "my-new-host";
      type = "rsa";
      purpose = [ "git" "ssh" ];
      isDefault = true;
    }];
    # Hierarchical module enables
    modules = {
      home.cli.enable = true;
      home.shell.enable = true;
      home.editors.enable = true;
      # Or enable specific modules:
      # home.browsers.vivaldi.enable = true;
    };
  };

  networking.hostName = "my-new-host";

  # System modules
  modules.system.all = {
    fonts.enable = true;
    nix.settings.enable = true;
    nix.gc.enable = true;
    shell.ssh.enable = true;
    shell.git.enable = true;
  };

  # Linux-specific (remove for Darwin)
  modules.system.linux = {
    desktop.hyprland.enable = true;
    networking.networkmanager.enable = true;
    sound.enable = true;
  };

  time.timeZone = "Europe/Moscow";
}
  1. Generate hardware config (NixOS):
nixos-generate-config --show-hardware-config > hosts/machines/my-new-host/hardware-configuration.nix
  1. Add to flake.nix:
nixosConfigurations.my-new-host = mkNixosConfiguration ./hosts/machines/my-new-host;
# or for Darwin:
darwinConfigurations.my-new-host = mkDarwinConfiguration ./hosts/machines/my-new-host;

Create a New User

  1. Create user defaults:
# hosts/users/newuser.nix
{ lib, ... }:
{
  enable = lib.mkDefault false;
  fullName = lib.mkDefault "New User";
  email = lib.mkDefault "newuser@example.com";
  github = lib.mkDefault "newuser";
  extraGroups = lib.mkDefault [ "wheel" "audio" "video" ];
}
  1. Enable in host config:
# hosts/machines/my-host/default.nix
hostUsers.newuser = importUser "newuser" // {
  enable = true;
  keys = [{
    name = "my-host";
    type = "rsa";
    purpose = [ "git" "ssh" ];
    isDefault = true;
  }];
  # Hierarchical module enables
  modules = {
    home.core.enable = true;
    home.shell.enable = true;
    home.media.vlc.enable = true;  # specific module
  };
};

Per-User Module Configuration

Configure modules per-user using hierarchical enables:

hostUsers.dgarifullin = importUser "dgarifullin" // {
  enable = true;

  modules = {
    # Enable entire categories
    home.browsers.enable = true;     # enables vivaldi, chromium, etc.
    home.editors.enable = true;      # enables neovim, cursor, etc.

    # Or enable specific modules
    home.media.vlc.enable = true;    # just vlc
    home.media.spotify.enable = true;
  };
};

Hierarchical enables:

  • home.enable = true β†’ enables ALL home modules
  • home.browsers.enable = true β†’ enables all browsers
  • home.browsers.vivaldi.enable = true β†’ enables just vivaldi

Module paths follow the directory structure: home.<category>.<module-name>


Create a New Module

User Module

# modules/home/tools/my-tool.nix
{ lib, pkgs, ... }@args:

lib.my.mkModuleV2 args {
  description = "My awesome tool";
  platforms = [ "linux" "darwin" ];  # optional, defaults to both

  module = {
    # Cross-platform config (goes to home-manager.users.*)
    allSystems.home.packages = [ pkgs.my-tool ];

    # Or platform-specific
    nixosSystems.programs.my-tool.enable = true;
    darwinSystems.homebrew.casks = [ "my-tool" ];
  };
}

System Module (Linux)

# modules/systems/linux/services/my-service.nix
{ lib, pkgs, config, ... }@args:

let
  enabledUsers = lib.filterAttrs (_: u: u.enable) config.hostUsers;
in
lib.my.mkSystemModuleV2 args {
  namespace = "linux";
  description = "My service";

  module = _: {
    # System-level NixOS options
    services.my-service.enable = true;

    # User packages via home-manager
    home-manager.users = lib.mapAttrs (name: _: {
      home.packages = [ pkgs.my-tool-client ];
    }) enabledUsers;
  };
}

Auto-discovery

Modules are auto-discovered recursively! Just create your .nix file in the right directory and it's automatically imported. No manual import lists needed.


Dotfile Symlink Modes (Nix Store vs. Live Edit)

Dotfiles support two modes on a per-module basis:

  1. πŸ“¦ Settled / Store Mode (live = false, default): Copies dotfiles into /nix/store. Store paths are captured in NixOS / Home Manager generations, allowing NixOS & GRUB generation rollbacks (nixos-rebuild switch --rollback or GRUB boot menu) to restore historical dotfile revisions cleanly.
  2. πŸ› οΈ Live Mode (live = true): Symlinks point out-of-store directly to $DOTFILES_DIR. Edit files directly during active development and changes apply immediately without nixos-rebuild switch.

How to Configure

  • In Module Definition:
dotfiles = {
  path = "ghostty/config";
  source = "modules/home/terminal/ghostty/dotfiles/config";
  live = true; # Set to true during active development
};
  • Per-Module Override in Host Config:
# hosts/machines/nix-goldstar/default.nix
modules.home.terminal.ghostty.dotfilesLive = true;  # Enable live edit for active dev
modules.home.editors.neovim.dotfilesLive = false;   # Store mode for settled neovim config

πŸ” Secrets Management (SOPS)

Secrets across the repository are managed using sops-nix with age encryption.

Key Derivation (ssh-to-age)

Host age keys are derived directly from SSH host keys (/etc/ssh/ssh_host_ed25519_key.pub), eliminating the need to store secondary key files on machine hosts:

# Derive host age key from SSH host key
nix-shell -p ssh-to-age --run 'ssh-to-age < /etc/ssh/ssh_host_ed25519_key.pub'

Age Key Locations

  • Linux / NixOS: ~/.config/sops/age/keys.txt (XDG standard compliant).
  • macOS / Darwin: ~/Library/Application Support/sops/age/keys.txt (Environment variable SOPS_AGE_KEY_FILE is automatically set by modules.system.all.sops.enable).

Shell Wrapper & Bitwarden Integration

A shell wrapper (sops) is provided in Zsh (common.zsh). If SOPS_AGE_KEY is not present, it dynamically fetches the per-machine SOPS key from Bitwarden CLI (bw get notes "SOPS Age Key <hostname>") and caches it in RAM (/tmp/.sops-age-key-<hostname>-<uid>) for 15 minutes.

Managing Secrets

Secrets are specified in .sops.yaml with creation rules targeting host secrets paths (e.g., hosts/machines/<host>/secrets/*). Edit or create secrets using:

sops hosts/machines/<host>/secrets/<secret-name>

πŸ”Œ Vantage Infrastructure Stub

vantage is an optional infrastructure flake input containing private service modules (Consul, Nomad, Vault, Vault Agent sidecar, remote builder configuration, Consul DNS).

Public Stub Mechanism

To ensure the repository remains fully open-source, evaluation-ready, and buildable on public CI without needing private SSH keys:

  • By default, flake.nix points vantage to a public stub repository: github:GDR/dot-stubs?dir=vantage
  • The stub exposes no-op modules and default options, allowing all host configurations (nix-goldstar, nix-oldstar, mac-brightstar) to evaluate cleanly without private repo access.

Override Workflow for Infra Hosts

When deploying to active infrastructure nodes (nix-oldstar or mac-brightstar), override the vantage input to point to the private repository:

# Manual override during rebuild:
nixos-rebuild switch --flake .#nix-oldstar --override-input vantage git+ssh://git@github.com/GDR/vantage

# Or using Makefile helper targets:
make nix-oldstar
make mac-brightstar

πŸ–₯ Host Configuration

Host Platform Description
nix-goldstar NixOS (x86_64-linux) Desktop workstation with Hyprland & NVIDIA
nix-oldstar NixOS (x86_64-linux) Server & remote builder (ThinkPad T480 homelab)
mac-brightstar Darwin (aarch64-darwin) MacBook Pro workstation

πŸ“‚ Module Reference

Enable modules hierarchically per-user:

hostUsers.myuser.modules = {
  home.browsers.enable = true;    # enables all browsers
  home.core.enable = true;        # enables htop, shell-utils
  home.shell.enable = true;       # enables zsh, tmux
  home.editors.neovim.enable = true;  # specific module
};
Path Modules
home.core htop, shell-utils (bat, fzf, wget, direnv)
home.shell zsh with oh-my-zsh, zplug, tmux
home.terminal ghostty
home.browsers chromium, vivaldi
home.editors cursor, neovim (nixvim)
home.desktop rofi, dunst, brightnessctl, pamixer, wayland-utils
home.media vlc, spotify
home.messengers telegram
home.games steam
home.security keepassxc, bitwarden
home.downloads qbittorrent
home.virtualisation docker
home.utils raycast (darwin), macfuse (darwin)

πŸ“„ License

MIT License - see LICENSE for details.

About

My personal config repo for my NixOS configurations. I use Nix flakes to manage dependencies and reproducibility.

Topics

Resources

Stars

8 stars

Watchers

1 watching

Forks

Used by

Contributors

Languages