Skip to content

About

Public/Sanitized version of my NixOS config

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

⚠️ NOTICE: This is a sanitized public version of a private NixOS configuration.

Personal information, secrets, network configurations, and other sensitive data have been removed or replaced with generic placeholders. This configuration will not build as-is without customization.

Use this repository as a template and reference - you will need to:

  • Replace all placeholder values with your own (usernames, hostnames, emails, etc.)
  • Create your own network.nix from the provided network.nix.example
  • Set up your own secrets management with sops-nix
  • Adjust hardware configurations for your specific system

For questions about specific configurations, please open an issue.

NixOS Configuration - nixos-framework

Personal NixOS configuration for Framework 13 (Intel Core Ultra Series 3) with secure boot, LUKS encryption, Btrfs with impermanence, and Stylix theming.

System Overview

Hardware: Framework 13 (Intel Core Ultra Series 3) Desktop: GNOME (Plasma and COSMIC also available) Theme System: Stylix with Kanagawa color scheme Bootloader: Lanzaboote (systemd-boot for initial install, switched via post-install.sh) Boot Splash: Plymouth with the custom framework-penguin theme, recolored from the active Stylix scheme Filesystem: Btrfs with LUKS encryption Partition Layout: Disko-managed with impermanence

Key Features

  • Security: Secure Boot with Lanzaboote, LUKS full-disk encryption unlocked automatically by the TPM (systemd-pcrlock, PCRs 0/4/7), sops-nix secrets management
  • Impermanence: Root and home wiped on cold boot, hibernation-safe (systemd HibernateLocation EFI variable; the wipe is skipped on resume)
  • Hybrid Swap: zram (50% RAM) for active compression + swapfile for hibernation
  • Hardware Support: Framework-specific optimizations, fan control (fw-fanctrl), QMK/VIA keyboard support, Thunderbolt, fingerprint reader
  • External Monitor Control: DDC/CI brightness control via ddcutil and a GNOME quick-settings extension
  • Cloud Storage: Google Drive (multiple accounts) mounted via rclone and surfaced in the Nautilus sidebar
  • Development: VSCode, Claude Code, Git, Docker, Virt-Manager, Ghostty, Distrobox, Direnv
  • Unified Theming: Stylix manages colors across system, browser extensions, and applications
  • Automation: GitHub Actions for automated flake.lock and package updates

Repository Structure

nixos/
├── flake.nix              # Main flake with inputs/outputs
├── configuration.nix      # System-level NixOS configuration
├── home.nix               # Home Manager user configuration
├── hardware-configuration.nix
├── stylix.nix             # Unified theming (Kanagawa)
├── de/
│   ├── default.nix        # DE selector (gearhead.desktop option)
│   ├── gnome.nix          # GNOME desktop environment (active)
│   ├── kde.nix            # KDE Plasma desktop (selectable)
│   ├── cosmic.nix         # COSMIC DE (selectable)
│   ├── dconf.nix          # GNOME dconf settings
│   └── plasma.nix         # plasma-manager home config (used with kde)
├── firefox.nix            # Firefox browser config
├── disko.nix              # Disk partitioning
├── impermanence.nix       # Impermanence/stateless config
├── archived/flatpak.nix   # Flatpak support (not currently imported)
├── network.nix            # NetworkManager profiles (sops-nix)
├── overlays/
│   └── gnome-extensions/  # Temporary overlay pinning newer extension versions
├── packages/
│   ├── duplicacy-web.nix  # Duplicacy service
│   ├── package-duplicacy.nix
│   ├── package-copyous.nix # Copyous GNOME extension
│   └── package-framework-penguin.nix # Plymouth boot theme (Stylix-recolored)
├── scripts/
│   ├── install.sh              # Initial installation script
│   ├── post-install.sh         # Post-install setup (Secure Boot)
│   ├── root-diff.sh            # Debug impermanence changes
│   ├── boot-loader-helper.sh   # Marker-based helper to toggle systemd-boot/lanzaboote config blocks
│   └── sync-pr-cleanup.sh      # Interactive tool to merge newest sync PR and close/delete stale ones
├── secrets/
│   └── secrets.yaml       # Encrypted secrets (sops)
├── dots/                  # Dotfiles and configs
├── templates/
│   └── python-direnv/     # Python dev environment template
└── .github/workflows/     # Automated update workflows

Installation

Prerequisites

  • NixOS ISO booted with networking configured
  • USB drive (or other accessible media) with the sops-nix keys.txt — install.sh prompts interactively for its path

Install Steps

  1. Clone and run installer:

    git clone https://github.com/0x6a64/NixOS-Public.git
    cd nixos
    ./scripts/install.sh
  2. The script will:

    • Configure git and authenticate with GitHub
    • Partition and format disks using Disko
    • Generate hardware configuration
    • Copy sops-nix keys from USB
    • Install NixOS with the nixos-framework flake configuration
    • Prompt for reboot
  3. After installation:

    • Reboot into new system
    • Run /home/user/Nixos/scripts/post-install.sh to complete setup

Post-Installation

The post-install.sh script completes the following:

  1. Configuration Migration:

    • Copies /etc/nixos into ~/Nixos, fixes ownership, then clears /etc/nixos (the directory itself is kept — it is a persisted bind mount)
  2. Secure Boot Setup:

    • Uncomments lanzaboote configuration in configuration.nix if needed
    • Rebuilds the system
    • Checks Secure Boot setup mode status
    • Enrolls Secure Boot keys with sbctl enroll-keys -m -f
  3. Manual Steps After Script:

    • Enable Secure Boot in BIOS/UEFI
    • Reboot to verify Secure Boot is active

Configuration Highlights

Filesystem Layout

/boot           2GB FAT32 (ESP)
/dev/nvme0n1p2  LUKS encrypted, Btrfs subvolumes:
  root          Ephemeral / + home (rotated into persist/old_roots on cold boot)
  nix           Nix store
  persist       Persistent state (bind-mounted to ephemeral paths)
  log           /var/log
  lib           /var/lib (docker, systemd, bluetooth, sbctl, etc.)
  swap          /persist/swap swapfile (48GB, nocow)

Impermanence

On each cold boot an initrd systemd service (root-explode) runs when the kernel command line does not contain resume= (i.e. not a hibernate resume). It moves the current root Btrfs subvolume to persist/old_roots/<timestamp> and creates a fresh root subvolume, giving a clean slate. Old roots older than 30 days are pruned, keeping at least the latest one.

What's ephemeral (wiped on cold boot):

  • / root filesystem
  • /home/* (except persisted directories)
  • Random dotfiles, app caches, temp files

What's persisted:

  • XDG directories: Desktop, Documents, Downloads, Music, Pictures, Videos, etc.
  • Security: .ssh, .gnupg, .local/share/keyrings, rclone OAuth tokens
  • App configs: ghostty, VSCode, OBS, Discord, etc.
  • Desktop state: monitor layout/VRR (monitors.xml), Nautilus bookmarks, Mesa GPU shader cache
  • System: /etc/nixos, NetworkManager connections, machine-id

Swap Configuration

  • zram: 50% of RAM, priority 100 (used first)
  • Swapfile: 48GB at /persist/swap/swapfile, priority 10 (fallback + hibernation)

Secure Boot & TPM Unlock

Lanzaboote signs the kernel/initrd and boot.loader.systemd-boot.enable is forced off. LUKS unlocks automatically from the TPM via boot.lanzaboote.measuredBoot against PCRs 0, 4 and 7, using systemd-pcrlock rather than raw PCR value-matching — PCR 11 is deliberately excluded because systemd-pcrphase rolls it on every boot, so it can never be value-matched.

Because lanzaboote re-signs the pcrlock policy in place on every rebuild, kernel and initrd updates do not require re-enrolling. The tradeoff is configurationLimit = 8: systemd-pcrlock cannot build a policy covering more generations than that.

The original LUKS passphrase keyslot is kept as a fallback and should stay that way — systemd-pcrlock is still labelled experimental upstream.

Enrollment was done without --tpm2-with-pin. Instead, GDM autologin is disabled so a real password still gates the session; this also fixes gnome-keyring auto-unlock, since pam_gnome_keyring needs pam_unix to actually authenticate before it can be handed the key.

Boot failures are self-healing: bootCounting.initialTries = 3 rolls back to the last known-good generation, and systemd-bless-boot (wired to multi-user.target) marks a boot good so the counter resets.

Power Management

  • Lid close: suspend-then-hibernate (hibernates after 1h)
  • Power button: hibernate
  • Power button long press: poweroff

Key Software

  • Shell: Zsh with Home Manager configuration
  • Editor: VSCode with Nix extensions
  • Terminal: Ghostty, Ptyxis
  • Browser: Firefox with Stylix integration
  • Communication: Discord, Signal
  • Productivity: Obsidian, LibreOffice, OBS Studio
  • Cloud Storage: rclone (Google Drive, multiple accounts)
  • Virtualization: Docker (Btrfs storage), libvirtd/QEMU, Virt-Manager

Secrets Management

Secrets stored in secrets/secrets.yaml encrypted with sops-nix:

  • User password
  • Wallhaven API key
  • SSH keys
  • GitHub token

Age key stored at /persist/sops-nix/keys.txt

Maintenance

Day-to-day rebuilds go through nh, configured via programs.nh (flake = "/home/user/Nixos", exported as NH_FLAKE). nh self-elevates, so these are run without sudo:

Alias Runs Purpose
rebuild nh os switch Build and activate now
rebuildst nh os switch --show-trace Same, with a full trace when evaluation fails
update nh os boot --update Update flake inputs, activate on next boot

nh bundles nix-output-monitor for build progress and prints a closure diff on completion.

Validate a change without activating it (no sudo required):

nixos-rebuild build --flake /home/user/Nixos     # produces ./result
nix store diff-closures /run/current-system ./result
alejandra -c .                                   # formatting check

Garbage Collection & Store Maintenance:

  • Weekly automatic GC via programs.nh.clean (nh-clean.service/timer, --keep 5 --keep-since 3d). This replaces nix.gc.automatic — the two conflict, so do not re-enable it.
  • Daily scheduled store deduplication (nix.optimise)
  • Boot menu capped at the last 8 generations (lanzaboote inherits configurationLimit); 8 is the ceiling systemd-pcrlock can build a TPM policy for

GitHub Actions (Automated Updates)

This repository includes GitHub Actions workflows for automated maintenance:

Flake Lock Updates

  • File: .github/workflows/update-flake-lock.yml
  • Schedule: Weekly (Sundays at midnight UTC)
  • Action: Updates flake.lock and creates a PR for review

Duplicacy Web Updates

  • File: .github/workflows/update-duplicacy-web.yml
  • Schedule: Weekly (Mondays at midnight UTC)
  • Action: Checks for new versions, updates hash, creates PR

Copyous GNOME Extension Updates

  • File: .github/workflows/update-copyous.yml
  • Schedule: Weekly (Mondays at midnight UTC)
  • Action: Checks GitHub releases for new versions, uses Nix tooling to compute hash, creates PR

Manual Trigger: Go to Actions tab → Select workflow → "Run workflow"

Cost: Free for public repos. Private repos get 2,000+ free minutes/month (these workflows use ~30 min/month total).

Development Environment (Direnv)

Direnv is enabled for automatic environment loading. Templates are provided in templates/.

Python Development Setup

  1. Copy the template to your project:

    cp -r ~/Nixos/templates/python-direnv/* /path/to/project/
  2. Allow direnv:

    cd /path/to/project
    direnv allow
  3. Customize flake.nix with your required packages

The environment auto-loads when you enter the directory and creates a .venv/ for pip packages.

Alternative Desktop Environments

DEs are switched with a single option in configuration.nix — all de/*.nix modules are always imported and gate themselves on it (home-manager modules follow automatically via osConfig):

gearhead.desktop = "gnome"; # or "kde" or "cosmic"

Then rebuild with the rebuild alias.

NetworkManager Declarative Profiles

The network.nix module provides templates for declarative network configuration with sops-nix secrets.

Supported profiles:

  • WiFi (WPA-PSK)
  • VLAN tagging
  • WireGuard VPN

Setup:

  1. Add secrets to secrets/secrets.yaml:
    wifi-home: "your-password"
    wg-private-key: "your-wireguard-key"
  2. Import ./network.nix in configuration.nix
  3. Uncomment and customize desired profiles

Stylix Color API Reference

Stylix exposes colors via config.lib.stylix.colors, an attribute set generated by mkSchemeAttrs from base16.nix.

Base16 Color Names (base00–base0F)

Attribute Example Value Description
base08 "ff0000" Raw hex (no #)
base08-hex "ff0000" Same as above
base08-hex-r "ff" Red component (hex)
base08-hex-g "00" Green component (hex)
base08-hex-b "00" Blue component (hex)
base08-rgb-r "255" Red component (decimal string)
base08-rgb-g "0" Green component (decimal string)
base08-rgb-b "0" Blue component (decimal string)
base08-dec-r "0.996094" Red component (0–1 float string)
base08-dec-g "0.0" Green component (0–1 float)
base08-dec-b "0.0" Blue component (0–1 float)

Named Color Aliases

Standard color names that map to base16 values:

  • red, green, yellow, blue, magenta, cyan, orange, brown
  • bright-red, bright-green, bright-yellow, bright-blue, bright-magenta, bright-cyan

With Hashtag

Access hex colors with # prefix:

config.lib.stylix.colors.withHashtag.base08  # => "#ff0000"
config.lib.stylix.colors.withHashtag.red     # => "#ff0000"

Helper Functions

From stylix/colors.nix:

# Convert hex color to 0x format
config.lib.stylix.mkHexColor "#ff0000"           # => "0xff0000"

# Convert hex color with opacity (0-1) to 0xRRGGBBAA format
config.lib.stylix.mkOpacityHexColor "#ff0000" 0.5  # => "0x7fff0000"

Base16 Color Meanings

Color Typical Usage
base00 Default Background
base01 Lighter Background (status bars, line numbers)
base02 Selection Background
base03 Comments, Invisibles
base04 Dark Foreground (status bars)
base05 Default Foreground
base06 Light Foreground
base07 Lightest Foreground
base08 Red (Variables, Errors)
base09 Orange (Integers, Constants)
base0A Yellow (Classes, Search)
base0B Green (Strings)
base0C Cyan (Support, Regex)
base0D Blue (Functions, Methods)
base0E Magenta (Keywords)
base0F Brown (Deprecated, Embedded)

Usage Examples

Integer RGB values

theme.colors = [{
  red = lib.strings.toInt config.lib.stylix.colors.base0E-rgb-r;
  green = lib.strings.toInt config.lib.stylix.colors.base0E-rgb-g;
  blue = lib.strings.toInt config.lib.stylix.colors.base0E-rgb-b;
}];

Hex colors with hashtag (for CSS/extensions)

uiAccentCustom0 = "${config.lib.stylix.colors.withHashtag.base0D}";

Raw hex (no hashtag)

background = colors.base00;  # => "1a1b26"

References

About

Public/Sanitized version of my NixOS config

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages