This repository contains modularized NixOS configurations, carefully compiled and in often places inspired by other similar configurations. The setup is flake-based and fully reproducible. Feel free to explore and use any part that inspires you.
- Modular flake setup based on flake-parts
- Secret management based on Agenix
- Single flake setup for NixOS and Home Manager
- Modules for servers, workstation, and mailserver
- Encrypted BTRFS setup
.
├── hosts
│  ├── bicboye
│  ├── smolboye
│  ├── thonkpad
│  └── zippyrus
├── modules
│  ├── home
│  │  ├── desktop
│  │  │  ├── firefox
│  │  │  ├── ghostty
│  │  │  ├── gnome
│  │  │  └── wezterm
│  │  ├── development
│  │  │  ├── git
│  │  │  ├── helix
│  │  │  └── tmux
│  │  └── shell
│  │  ├── direnv
│  │  └── fish
│  └── nixos
│  ├── core
│  │  ├── docker
│  │  ├── fish
│  │  ├── gnupg
│  │  ├── lanzaboote
│  │  ├── meta
│  │  ├── nix
│  │  ├── security
│  │  └── sshd
│  ├── desktop
│  │  ├── fonts
│  │  ├── gnome
│  │  ├── hyprland
│  │  ├── kde
│  │  ├── pipewire
│  │  └── plymouth
│  ├── gaming
│  │  ├── proton
│  │  └── steam
│  ├── hardware
│  │  ├── bluetooth
│  │  ├── graphics
│  │  │  ├── amd
│  │  │  ├── intel
│  │  │  └── nvidia
│  │  ├── initrd-luks
│  │  ├── usbguard
│  │  └── yubico
│  ├── monitoring
│  │  ├── exporter
│  │  ├── grafana
│  │  └── victoriametrics
│  ├── networking
│  │  ├── mullvad
│  │  └── netbird
│  ├── services
│  │  ├── actual-budget
│  │  ├── arr
│  │  │  ├── bazarr
│  │  │  ├── jellyfin
│  │  │  ├── jellyseerr
│  │  │  ├── prowlarr
│  │  │  ├── qbittorrent
│  │  │  ├── radarr
│  │  │  ├── sabnzbd
│  │  │  └── sonarr
│  │  ├── asus
│  │  ├── backup
│  │  ├── bluesky-pds
│  │  ├── fail2ban
│  │  ├── forgejo
│  │  ├── homebridge
│  │  ├── immich
│  │  ├── mailserver
│  │  ├── miniflux
│  │  ├── navidrome
│  │  ├── nginx
│  │  ├── ntfy-sh
│  │  ├── paperless
│  │  ├── postgresql
│  │  ├── static-site
│  │  ├── technitium
│  │  ├── tools
│  │  │  └── duperemove
│  │  ├── unifi-controller
│  │  ├── vaultwarden
│  │  └── wildcard-ssl
│  └── user
├── overlays
│  ├── jellyfin-web
│  └── netbird
├── packages
│  └── vuetorrent
├── secrets
│  ├── machines
│  │  ├── bicboye
│  │  ├── smolboye
│  │  ├── thonkpad
│  │  └── zippyrus
│  ├── monitoring
│  │  └── grafana
│  ├── network-manager
│  └── services
│  ├── backups
│  ├── bluesky-pds
│  ├── forgejo
│  │  └── actions-runner
│  ├── maddy
│  ├── mailserver
│  ├── miniflux
│  ├── paperless
│  ├── unifi-unpoller
│  └── vaultwarden
├── templates
│  ├── desktop
│  ├── module
│  └── server
└── users
├── chnmy
│  ├── thonkpad
│  └── zippyrus
└── server
├── bicboye
└── smolboye
flake.nix: Entrypoint for the NixOS configurationsdata.nix: Mappings for Agenix secrets, passed asspecialArgsinflake.nixand referenced inside the configurations.users: Home user configuration for the flakes, structured as<username>/<system>modules: Platform-based opinionated NixOS modules, containinghomeandnixoshome: Home Manager configuration options programs and servicesnixos: NixOS configuration options for services, programs, and system setup
overlays: Customized nix package builds for existing packagespackages: Custom packages for NixOStemplates: Flake templates for generating Nix configurationssecrets: Agenix deployment secrets, referenced indata.nixoptions.md: Auto-generated documentation for all available module optionstreefmt.nix: Configuration for code formatting
All modules are available under the modules/ directory, for both Home manager and NixOS, with the options listed under snowflake.*. These modules makes deploying complex configurations quite simple. For example: A full-fledged, minimal, KDE Plasma desktop can be enabled by adding snowflake.desktop.kde.enable = true to your system configuration.
The modular configuration also allows for efficient reusability and config de-duplication between machines. Most of the configuration is tailored to my needs, but is still highly-customizable except for the security defaults.
As an example, to deploy a new workstation with a desktop environment:
{lib, pkgs, userdata, ...}:
{
imports = [./hardware.nix];
hardware.cpu.intel.updateMicrocode = true;
hardware.enableRedistributableFirmware = true;
networking.hostName = "workstation";
# Power management, enable powertop and thermald.
powerManagement.powertop.enable = true;
services.thermald.enable = true;
snowflake = {
stateVersion = "24.05";
core.lanzaboote.enable = true;
core.docker.enable = true;
core.docker.storageDriver = "btrfs";
desktop.enable = true;
desktop.fingerprint.enable = true;
desktop.kde.enable = true;
hardware.bluetooth.enable = true;
hardware.yubico.enable = true;
networking.firewall.enable = true;
networking.networkManager.enable = true;
networking.iwd.enable = true;
networking.resolved.enable = true;
networking.netbird.enable = true;
user.enable = true;
user.username = "user";
user.description = "User McUsername";
user.extraGroups = ["video"];
# NOTE: this requires adding an agenix secret to `secrets/secrets.nix`
# and an entry in `data.nix` to work. Refer those files for more details.
user.userPasswordAgeModule = userdata.secrets.machines.workstation.password;
user.rootPasswordAgeModule = userdata.secrets.machines.workstation.root-password;
}
};zippyrus: Primary workstation on ASUS Zephyrus GA403UI - AMD Ryzen 9 8945HS, 32GB RAM, Nvidia 4070thonkpad: Work provisioned Lenovo X1 Carbon 12th Gen - Intel Core Ultra 7 155H, 32GB RAMbicboye: A custom-built Homelab running Intel Core i5 12600K, 32GB RAM, 16TB storagesmolboye: Hetzner Cloud VPS Running a dual-core Intel Xeon, 4GB RAM
For all deployment secrets, I am using agenix. All secrets are stored in the secrets/ directory and are encrypted with host SSH keys.
To add new deployment secrets:
- Create the relevant directory structure under
secrets/and add an entry tosecrets.nix - Create/Edit the secret with agenix. This command needs to be run in the same directory as
secrets.nix. You do not require agenix to be installed, and instead can usenix run, for example:
$ nix run github:ryantm/agenix#agenix -- -e services/service-name/password.age- Add an entry for the secret to
data.nix. The added secret can then be used asuserdata.secrets.services.service-name.passwordin the configuration. Refer todata.nixfor more details.
This repository does not walk you through the entire installation process, but instead lists down steps to get an encrypted BTRFS partition setup for NixOS, mostly for future reference. So prepare a NixOS installation disk your preferred way, either by downloading the ISO, or using scripts like nixos-anywhere to bootstrap your system.
You may setup NixOS through either the traditional way, by manual partitioning, or through disko.
Wipe the partition table with wipefs -a /dev/nvme0n1. Edit the partition table to create two partitions:
/dev/nvme0n1p1- 512MiB EFI partition. This won't be encrypted./dev/nvmen01p2- root partition, will use LUKS+BTRFS for root.
An encrypted swap partition can optionally be set up using BTRFS later.
All commands prefixed with # are expected to be run as the root user. Make sure to enter a strong encryption password during luksFormat (and then remember it!).
# cryptsetup luksFormat --type=luks2 /dev/nvme0n1p2
# cryptsetup open /dev/nvme0n1p2 cryptroot- Format the EFI and the root partition:
# mkfs.fat -F32 /dev/nvme0n1p1
# mkfs.btrfs /dev/mapper/cryptroot- Create BTRFS subvolumes:
# mount /dev/mapper/cryptroot /mnt
# btrfs subvolume create /mnt/@
# btrfs subvolume create /mnt/@home
# btrfs subvolume create /mnt/@snapshots
# btrfs subvolume create /mnt/@log
# btrfs subvolume create /mnt/@cache
# btrfs subvolume create /mnt/@nix-config
# btrfs subvolume create /mnt/@nix-store- Create directories for the subvolumes:
# mkdir /mnt/@/home
# mkdir /mnt/@/.snapshots
# mkdir /mnt/@/boot
# mkdir /mnt/@/nix
# mkdir -p /mnt/@/var/log
# mkdir -p /mnt/@/var/cache
# mkdir -p /mnt/@/etc/nixos
# mkdir -p /mnt/@/nix
# umount -R /mnt- Mount all the file systems
# mount -o ssd,noatime,compress=zstd,space_cache=v2,autodefrag,subvol=@ /dev/mapper/cryptroot /mnt
# mount -o ssd,noatime,compress=zstd,space_cache=v2,autodefrag,subvol=@home,nodev /dev/mapper/cryptroot /mnt/home
# mount -o ssd,noatime,compress=zstd,space_cache=v2,autodefrag,subvol=@snapshots,nodev,nosuid,noexec /dev/mapper/cryptroot /mnt/.snapshots
# mount -o ssd,noatime,compress=zstd,space_cache=v2,autodefrag,subvol=@log,nodev,nosuid,noexec /dev/mapper/cryptroot /mnt/var/log
# mount -o ssd,noatime,compress=zstd,space_cache=v2,autodefrag,subvol=@cache,nodev,nosuid,noexec /dev/mapper/cryptroot /mnt/var/cache
# mount -o ssd,noatime,compress=zstd,space_cache=v2,autodefrag,subvol=@nix-config,nodev /dev/mapper/cryptroot /mnt/etc/nixos
# mount -o ssd,noatime,compress=zstd,space_cache=v2,autodefrag,subvol=@nix-store,nodev /dev/mapper/cryptroot /mnt/nix
# mount /dev/nvme0n1p1 /mnt/bootDisko is a helper tool that lets you declaratively specify disk partitions for your system. This can be used as a replacement for the fileSystems.* option in NixOS. Check out the disko repository to set it up in flakes, or refer flake.nix for the setup.
A sample disko configuration for a VPS set up using nixos-anywhere:
# hosts/smolboye/disk-config.nix
{
disko.devices = {
disk = {
sda = {
type = "disk";
device = "/dev/sda";
content = {
type = "gpt";
partitions = {
boot = {
priority = 1;
name = "ESP";
start = "1M";
end = "128M";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
root = {
size = "100%";
content = {
type = "btrfs";
extraArgs = ["-f"];
subvolumes = {
"/root" = {
mountpoint = "/";
mountOptions = ["compress=zstd" "noatime"];
};
"/home" = {
mountpoint = "/home";
mountOptions = ["compress=zstd" "noatime"];
};
"/nix" = {
mountpoint = "/nix";
mountOptions = ["compress=zstd" "noatime"];
};
"/swap" = {
mountpoint = "/.swapvol";
mountOptions = ["nodatacow" "noatime"];
swap.swapfile.size = "20M";
};
"/log" = {
mountpoint = "/var/log";
mountOptions = ["compress=zstd" "noatime"];
};
};
};
};
};
};
};
};
};
}To partition the disks in live USB:
# nix --experimental-features "nix-command flakes" run github:nix-community/disko -- --mode disko ./hosts/smolboye/disk-config.nixAlternatively, running nixos-install should take care of the partitioning for you.
- Clone the git repository
# git clone https://git.deku.moe/thunderbottom/flakes.git /mnt/etc/nixos- Get the UUID for the disks and edit
hardware.nixto match theblkidoutput. This step can be skipped if you are usingdisko:
# blkid
/dev/nvme0n1p1: UUID="7FBB-9E80" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="b4e5f895-cd2d-4cc9-9878-03dc8fca178c"
/dev/nvme0n1p2: UUID="9de352ea-128f-4d56-a720-36d81dfd9b92" TYPE="crypto_LUKS" PARTUUID="95574dc5-5f5d-465d-b01c-f76918f7a125"
/dev/mapper/cryptroot: UUID="870fde90-a91a-4554-8b1c-d5702c789f4d" UUID_SUB="ccc90835-8b61-4d8e-8293-e1323a02fb3b" BLOCK_SIZE="4096" TYPE="btrfs"If you are not using disko for partition setup, make sure to set the following values in hardware.nix:
luks.devices."cryptroot".deviceto/dev/nvme0n1p2output, in this case:/dev/disk/by-uuid/9de352ea-128f-4d56-a720-36d81dfd9b92- All the values in
fileSystems.*, except/bootto/dev/mapper/cryptrootoutput,/dev/disk/by-uuid/870fde90-a91a-4554-8b1c-d5702c789f4d fileSystems."/boot"to/dev/nvme0n1p1output,/dev/disk/by-uuid/7FBB-9E80
Check any of the hardware.nix files in the repository for more details.
- Install NixOS with
nixos-installand thenreboot.
To deploy all hosts using deploy-rs:
$ deployTo deploy a specific host:
$ deploy .#hostnameTo deploy the traditional way using nix:
# nixos-rebuild switch --flake '.#hostname'It is also possible to rebuild and deploy NixOS to a remote host. This can be used in cases where the remote host is incapable of building packages, or while running a VPS. To run remote deployments:
# nixos-rebuild switch --flake '.#hostname' --target-host user@ip --use-remote-sudo