fixes and docs

This commit is contained in:
mjallen18
2026-03-23 15:17:10 -05:00
parent 2c0b26ced0
commit 23f29b6ca1
25 changed files with 1590 additions and 795 deletions

View File

@@ -4,101 +4,178 @@ This document provides an overview of the repository architecture, explaining ho
## Overview
This NixOS configuration repository is built using [Nix Flakes](https://nixos.wiki/wiki/Flakes) and [Snowfall Lib](https://github.com/snowfallorg/lib) to provide a modular, maintainable configuration for multiple systems.
This NixOS configuration repository is built using [Nix Flakes](https://nixos.wiki/wiki/Flakes) and [Snowfall Lib](https://github.com/snowfallorg/lib) to provide a modular, maintainable configuration for multiple systems. The Snowfall namespace is `mjallen`, so all custom options are accessed as `mjallen.<domain>.<name>`.
## Directory Structure
```
.
├── checks/ # Pre-commit hooks and other checks
├── flake.nix # Main flake configuration
├── homes/ # Home-manager configurations for users
│ ├── aarch64-darwin/ # macOS home configurations
│ ├── aarch64-linux/ # ARM Linux home configurations
└── x86_64-linux/ # x86 Linux home configurations
├── flake.nix # Main flake — inputs, outputs, Snowfall config
├── flake.lock # Locked dependency versions
├── .sops.yaml # SOPS key management rules
├── treefmt.nix # Code formatter configuration
├── qemu.nix # QEMU VM testing config
├── checks/ # Pre-commit hooks and CI checks
├── docs/ # Documentation (this directory)
├── homes/ # Home Manager configurations
│ ├── aarch64-darwin/ # macOS user configs
│ ├── aarch64-linux/ # ARM Linux user configs
│ └── x86_64-linux/ # x86 Linux user configs
├── lib/ # Custom Nix library utilities
│ ├── module/ # mkModule, mkOpt, mkBoolOpt helpers
│ ├── file/ # File/path utilities
│ └── versioning/ # Package version pinning helpers
├── modules/ # Reusable configuration modules
│ ├── home/ # Home-manager modules
── nixos/ # NixOS system modules
├── boot/ # Boot configuration modules
├── desktop/ # Desktop environment modules
│ ├── hardware/ # Hardware-specific modules
│ ├── homeassistant/ # Home Assistant modules
│ ├── network/ # Network configuration modules
│ ├── services/ # Service configuration modules
│ └── ... # Other module categories
│ ├── home/ # Home Manager modules
── nixos/ # NixOS system modules
└── darwin/ # nix-darwin modules (macOS)
├── overlays/ # Nixpkgs overlays
├── packages/ # Custom package definitions
├── secrets/ # Encrypted secrets (managed with sops-nix)
── systems/ # System-specific configurations
├── aarch64-darwin/ # macOS system configurations
├── aarch64-linux/ # ARM Linux system configurations
── x86_64-linux/ # x86 Linux system configurations
├── jallen-nas/ # NAS server configuration
├── matt-nixos/ # Desktop configuration
├── nuc-nixos/ # NUC configuration
└── ... # Other system configurations
── secrets/ # SOPS-encrypted secret files
└── systems/ # Per-host system configurations
── aarch64-darwin/ # macOS (nix-darwin) hosts
├── aarch64-linux/ # ARM Linux hosts
├── x86_64-install-iso/# Install ISO configurations
└── x86_64-linux/ # x86_64 Linux hosts
```
## Flake Structure
## Flake Inputs
The `flake.nix` file defines the inputs (external dependencies) and outputs (configurations) of this repository:
| Input | Source | Purpose |
|---|---|---|
| `nixpkgs-unstable` | `github:NixOS/nixpkgs/nixos-unstable` | Primary package set |
| `nixpkgs-stable` | `github:NixOS/nixpkgs/nixos-25.11` | Stable package set |
| `nixpkgs-otbr` | `github:mrene/nixpkgs` (fork) | OpenThread Border Router packages |
| `home-manager-unstable` | `github:nix-community/home-manager` | User environment management |
| `home-manager-stable` | `github:nix-community/home-manager/release-25.11` | Stable home-manager |
| `snowfall-lib` | `github:mjallen18/snowfall-lib` | Flake structure library (personal fork) |
| `impermanence` | `github:nix-community/impermanence` | Ephemeral root filesystem support |
| `lanzaboote` | `github:nix-community/lanzaboote/v1.0.0` | Secure Boot |
| `nixos-hardware` | `github:NixOS/nixos-hardware` | Hardware-specific NixOS configs |
| `sops-nix` | `github:Mic92/sops-nix` | Secret management |
| `disko` | `github:nix-community/disko` | Declarative disk partitioning |
| `cosmic` | `github:lilyinstarlight/nixos-cosmic` | COSMIC desktop environment |
| `jovian` | `github:Jovian-Experiments/Jovian-NixOS` | Steam Deck / handheld support |
| `nixos-apple-silicon` | `github:nix-community/nixos-apple-silicon` | Asahi Linux / Apple Silicon |
| `darwin` | `github:nix-darwin/nix-darwin` | macOS system configuration |
| `nix-homebrew` | `github:zhaofengli/nix-homebrew` | Declarative Homebrew (macOS) |
| `stylix` | `github:nix-community/stylix` | System-wide theming |
| `nix-vscode-extensions` | `github:nix-community/nix-vscode-extensions` | VS Code extension packages |
| `authentik-nix` | `github:nix-community/authentik-nix` | Authentik SSO |
| `nix-cachyos-kernel` | `github:xddxdd/nix-cachyos-kernel` | CachyOS optimised kernels |
| `lsfg-vk` | `github:pabloaul/lsfg-vk-flake` | Lossless Scaling frame generation (Linux) |
| `nix-index-database` | `github:nix-community/nix-index-database` | Pre-built nix-index database |
| `steam-rom-manager` | `github:mjallen18/nix-steam-rom-manager` | Steam ROM Manager package |
| `nix-plist-manager` | `github:sushydev/nix-plist-manager` | macOS plist management |
| `nix-rosetta-builder` | `github:cpick/nix-rosetta-builder` | Rosetta build support (macOS) |
| `pre-commit-hooks-nix` | `github:cachix/pre-commit-hooks.nix` | Pre-commit hooks |
| `treefmt-nix` | `github:numtide/treefmt-nix` | Code formatting |
### Inputs
- **nixpkgs-unstable**: The unstable channel of Nixpkgs
- **nixpkgs-stable**: The stable channel of Nixpkgs (25.11)
- **home-manager**: User environment management
- **snowfall-lib**: Library for structuring flake repositories
- **impermanence**: Persistent state management
- **lanzaboote**: Secure boot implementation
- **nixos-hardware**: Hardware-specific configurations
- **sops-nix**: Secret management
- **disko**: Disk partitioning and formatting
- **And more specialized inputs**
### Outputs
The outputs are generated using Snowfall Lib's `mkFlake` function, which automatically discovers and assembles:
- **NixOS system configurations**: For each system in the `systems/` directory
- **Home Manager configurations**: For each configuration in the `homes/` directory
- **Packages**: From the `packages/` directory
- **Modules**: From the `modules/` directory
- **Overlays**: From the `overlays/` directory
`nixpkgs` and `home-manager` are aliases pointing to the unstable variants.
## Module System
The module system uses a modular approach where:
### Structure
1. **Common modules** are defined in `modules/nixos/` and `modules/home/`
2. **System-specific modules** are defined in `systems/<architecture>/<hostname>/`
All modules follow a standard Snowfall Lib pattern and are automatically discovered. Each module exposes options under the `mjallen` namespace:
Each module follows the NixOS module pattern, with:
- `default.nix`: Main module implementation
- `options.nix`: Option declarations
```nix
# Enable a module
mjallen.services.jellyfin.enable = true;
mjallen.desktop.gnome.enable = true;
mjallen.hardware.amd.enable = true;
```
## Integration with Snowfall Lib
### `mkModule` helper
Snowfall Lib provides:
1. **Automatic discovery** of modules, overlays, and packages
2. **Consistent structure** across the repository
3. **Common utilities** for working with flakes
Most service modules are built with `lib.mjallen.mkModule` (`lib/module/default.nix`), which provides a standard set of options:
| Option | Default | Description |
|---|---|---|
| `enable` | `false` | Enable/disable the module |
| `port` | `80` | Service listen port |
| `listenAddress` | `"0.0.0.0"` | Bind address |
| `openFirewall` | `true` | Open firewall ports |
| `configDir` | `/var/lib/<name>` | Config directory |
| `dataDir` | `/var/lib/<name>/data` | Data directory |
| `createUser` | `false` | Create a dedicated system user |
| `configureDb` | `false` | Create a PostgreSQL database |
| `environmentFile` | `null` | Path to an env-file |
| `reverseProxy.enable` | `false` | Add a Caddy reverse proxy block |
| `reverseProxy.subdomain` | `<name>` | Caddy subdomain |
| `redis.enable` | `false` | Create a dedicated Redis instance |
### NixOS modules (`modules/nixos/`)
| Category | Paths | Description |
|---|---|---|
| Boot | `boot/common/`, `boot/lanzaboote/`, `boot/plymouth/`, `boot/systemd-boot/` | Bootloader configurations |
| Desktop | `desktop/gnome/`, `desktop/hyprland/`, `desktop/cosmic/` | Desktop environments |
| Development | `development/` | Dev tools, language support, containers |
| Hardware | `hardware/amd/`, `hardware/nvidia/`, `hardware/battery/`, `hardware/raspberry-pi/`, `hardware/openrgb/`, ... | Hardware-specific configs |
| Headless | `headless/` | Headless server profile (watchdog, no suspend) |
| Home Assistant | `homeassistant/` | Smart home automation suite |
| Impermanence | `impermanence/` | Ephemeral root + persistent state |
| Monitoring | `monitoring/` | Prometheus/Grafana metrics |
| Network | `network/` | Hostname, firewall, NetworkManager, static IP |
| Power | `power/` | UPS support |
| Programs | `programs/` | System-wide programs (nix-index, gnupg, etc.) |
| Security | `security/common/`, `security/tpm/` | Common hardening, TPM unlock |
| Services | `services/<name>/` | ~50 self-hosted service modules (see below) |
| SOPS | `sops/` | Secret management setup |
| System | `system/` | Miscellaneous system settings |
| User | `user/` | User account management |
| Virtualization | `virtualization/` | libvirt, containers |
### Home Manager modules (`modules/home/`)
| Category | Paths | Description |
|---|---|---|
| Desktop | `desktop/gnome/`, `desktop/theme/` | GNOME and theming |
| GPG | `gpg/` | GPG agent configuration |
| Programs | `programs/btop/`, `programs/git/`, `programs/zsh/`, `programs/kitty/`, `programs/waybar/`, `programs/hyprland/`, `programs/wofi/`, `programs/mako/`, `programs/wlogout/`, `programs/librewolf/`, `programs/opencode/`, `programs/update-checker/`, ... | User applications |
| Services | `services/pass/` | Password store integration |
| Shell | `shell-aliases/` | Common shell aliases |
| SOPS | `sops/` | User-level secret integration |
| Stylix | `stylix/` | System-wide theming |
| User | `user/` | User environment defaults |
## Secrets Management
Secrets are managed using [sops-nix](https://github.com/Mic92/sops-nix), with:
- Encrypted secret files in the `secrets/` directory
- `.sops.yaml` configuration file in the root
- Key management integrated into the configuration
Secrets are encrypted with [SOPS](https://github.com/getsops/sops) using age keys derived from each machine's SSH host key (`/etc/ssh/ssh_host_ed25519_key`). The `.sops.yaml` file maps secret file path patterns to the set of age recipients that can decrypt them.
## Deployment Process
Each host has its own secrets file:
| File | Host |
|---|---|
| `secrets/secrets.yaml` | Shared (all hosts) |
| `secrets/nas-secrets.yaml` | jallen-nas |
| `secrets/pi5-secrets.yaml` | pi5 |
| `secrets/allyx-secrets.yaml` | allyx |
| `secrets/nuc-secrets.yaml` | nuc-nixos |
| `secrets/mac-secrets.yaml` | macbook-pro-nixos |
| `secrets/desktop-secrets.yaml` | matt-nixos |
See the [Secrets Management](../README.md#secrets-management) section of the root README for full details on generating keys and adding secrets.
## Deployment
Systems are built and deployed using:
```bash
nixos-rebuild switch --flake .#hostname
```
# NixOS system
sudo nixos-rebuild switch --flake .#hostname
This command:
1. Evaluates the flake for the specified hostname
2. Builds the resulting configuration
3. Activates it on the current system
# macOS (nix-darwin)
darwin-rebuild switch --flake .#hostname
# Home Manager only
home-manager switch --flake .#username@hostname
```

View File

@@ -6,167 +6,170 @@ This guide will help you get started with this NixOS configuration repository.
- Basic knowledge of NixOS and the Nix language
- Git installed on your system
- Physical access to the machine you want to configure
- Physical or SSH access to the target machine
## Initial Setup
### 1. Cloning the Repository
Clone this repository to your local machine:
## Cloning the Repository
```bash
git clone ssh://nix-apps@localhost:2222/mjallen/nix-config.git
cd nix-config
```
### 2. Setting Up a New System
## Installing on a New Machine
#### Option 1: Using an Existing Configuration
### Option 1: Using an existing system configuration
If you're setting up a new machine that should be identical to an existing configuration:
If the machine matches an existing configuration (e.g. reinstalling `jallen-nas`):
1. Boot from a NixOS installation media
2. Mount your target partitions to `/mnt`
3. Clone this repository:
1. Boot from a NixOS installation ISO
2. Partition and mount disks (or use `disko`):
```bash
nixos-enter
cd /mnt
mkdir -p /mnt/etc/nixos
git clone ssh://nix-apps@localhost:2222/mjallen/nix-config.git /mnt/etc/nixos
nix run github:nix-community/disko -- --mode disko /path/to/disko-config.nix
```
4. Install NixOS with the desired system profile:
3. Clone this repo into the target:
```bash
mkdir -p /mnt/etc/nixos
git clone <repo-url> /mnt/etc/nixos
```
4. Install:
```bash
nixos-install --flake /mnt/etc/nixos#hostname
```
Replace `hostname` with the target system name (e.g., `matt-nixos`, `jallen-nas`, etc.)
#### Option 2: Creating a New System Configuration
### Option 2: Adding a new system configuration
If you're adding a completely new system:
1. Create a new directory for your system configuration:
1. **Create the system directory** under the appropriate architecture:
```bash
mkdir -p systems/$(uname -m)-linux/new-hostname
mkdir -p systems/x86_64-linux/new-hostname
```
2. Create the basic configuration files:
```bash
cat > systems/$(uname -m)-linux/new-hostname/default.nix << EOF
{ lib, pkgs, ... }:
2. **Write the configuration** — at minimum a `default.nix`:
```nix
{ namespace, ... }:
{
imports = [
./hardware-configuration.nix
# Add other needed module imports here
];
networking.hostName = "new-hostname";
# Add your system-specific configuration here
mjallen = {
sops.enable = true;
network.hostName = "new-hostname";
user.name = "admin";
};
}
EOF
```
3. Generate the hardware configuration:
3. **Generate hardware configuration** (on the target machine):
```bash
nixos-generate-config --no-filesystems --dir systems/$(uname -m)-linux/new-hostname/
nixos-generate-config --no-filesystems --dir systems/x86_64-linux/new-hostname/
```
4. Add your new system to the flake by adding it to the `hosts` section in `flake.nix`
4. **Add SOPS secrets** for the new host — see [Secrets Management](../README.md#secrets-management).
5. Build and install the configuration:
5. **Build and switch**:
```bash
sudo nixos-rebuild switch --flake .#new-hostname
```
## Secret Management
## Day-to-Day Usage
### Setting Up Sops-Nix
1. Create a GPG key if you don't already have one:
```bash
gpg --full-generate-key
```
2. Add your key to `.sops.yaml`:
```bash
# Get your key fingerprint
gpg --list-secret-keys --keyid-format=long
# Edit the .sops.yaml file to add your key
```
3. Create a new encrypted secret:
```bash
sops secrets/newsecret.yaml
```
## Common Tasks
### Updating the Repository
### Applying configuration changes
```bash
git pull
sudo nixos-rebuild switch --flake .#hostname
# On the local machine
sudo nixos-rebuild switch --flake .#$(hostname)
# On a remote machine
nixos-rebuild switch --flake .#hostname --target-host user@host --use-remote-sudo
```
### Adding a New Package
### Updating flake inputs
1. For standard packages, add them to your system or home configuration:
```bash
# Update all inputs
nix flake update
# Update a single input
nix flake lock --update-input nixpkgs
# Apply after updating
sudo nixos-rebuild switch --flake .#$(hostname)
```
### Garbage collection
```bash
# Remove old generations and unreferenced store paths
sudo nix-collect-garbage -d
# Keep the last N generations
sudo nix-collect-garbage --delete-older-than 30d
```
## Enabling a Module
Most functionality is exposed through the `mjallen` namespace. To enable a module, set it in the system's `default.nix` (or a relevant sub-file):
```nix
mjallen = {
desktop.gnome.enable = true;
hardware.amd.enable = true;
gaming.enable = true;
services.jellyfin = {
enable = true;
port = 8096;
reverseProxy.enable = true;
};
};
```
See [Custom Modules](./modules/README.md) for the full list of available modules and options.
## Adding a New Service Module
1. **Create the module directory**:
```bash
mkdir -p modules/nixos/services/my-service
```
2. **Write `default.nix`** using the `mkModule` helper:
```nix
environment.systemPackages = with pkgs; [
new-package
];
```
2. For custom packages, add them to the `packages` directory:
```bash
mkdir -p packages/new-package
# Create the necessary Nix files
```
### Adding a New Module
1. Create a new module directory:
```bash
mkdir -p modules/nixos/new-module
```
2. Create the module files:
```bash
# Create options.nix
cat > modules/nixos/new-module/options.nix << EOF
{ lib, namespace, ... }:
with lib;
{
options.${namespace}.new-module = {
enable = mkEnableOption "Enable new module";
# Add other options here
};
}
EOF
# Create default.nix
cat > modules/nixos/new-module/default.nix << EOF
{ config, lib, namespace, ... }:
{ config, lib, namespace, pkgs, ... }:
let
cfg = config.${namespace}.new-module;
in
{
imports = [ ./options.nix ];
config = lib.mkIf cfg.enable {
# Add your configuration here
name = "my-service";
nebulaConfig = lib.${namespace}.mkModule {
inherit config name;
description = "my service description";
options = { };
moduleConfig = {
services.my-service = {
enable = true;
port = config.${namespace}.services.${name}.port;
};
};
};
}
EOF
in
{ imports = [ nebulaConfig ]; }
```
3. Import your module in your system configuration:
3. **Enable it** in a system configuration:
```nix
imports = [
# ...
../../../modules/nixos/new-module
];
${namespace}.new-module.enable = true;
```
mjallen.services.my-service = {
enable = true;
port = 1234;
};
```
## Adding a New Package
1. Create a directory under `packages/`:
```bash
mkdir packages/my-package
```
2. Write a `default.nix` that returns a derivation. The package will be available as `pkgs.mjallen.my-package` in all configurations.
## Secrets
See the [Secrets Management](../README.md#secrets-management) section of the root README for:
- How age keys are derived from SSH host keys
- Adding a new machine as a SOPS recipient
- Adding/editing secrets
- Generating Nebula VPN certificates

View File

@@ -2,115 +2,294 @@
This directory contains documentation for the custom modules used in this NixOS configuration.
## Module Types
## Overview
The repository uses two main types of modules:
Modules are split into three categories:
1. **NixOS Modules** - System-level configurations in `modules/nixos/`
2. **Home Manager Modules** - User-level configurations in `modules/home/`
- **NixOS modules** (`modules/nixos/`) — system-level configuration
- **Home Manager modules** (`modules/home/`) — user-level configuration
- **Darwin modules** (`modules/darwin/`) — macOS-specific configuration
All modules are auto-discovered by Snowfall Lib and expose options under the `mjallen` namespace.
## NixOS Modules
These modules configure the system-level aspects of NixOS:
### Boot (`modules/nixos/boot/`)
- [Boot Modules](./boot.md) - Boot loader and kernel configurations
- [Desktop Modules](./desktop.md) - Desktop environment configurations
- [Development Modules](./development.md) - Development tools and environments
- [Hardware Modules](./hardware.md) - Hardware-specific configurations
- [Home Assistant Modules](./homeassistant.md) - Home automation configuration
- [Networking Modules](./network.md) - Network configuration and services
- [Security Modules](./security.md) - Security-related configurations
- [Services Modules](./services.md) - Various service configurations
- [System Modules](./system.md) - General system configurations
- [Virtualization Modules](./virtualization.md) - Virtualization and containerization
| Module | Description |
|---|---|
| `boot/common/` | Shared boot defaults (quiet boot, Plymouth) |
| `boot/lanzaboote/` | Secure Boot via Lanzaboote |
| `boot/systemd-boot/` | systemd-boot (non-secure-boot systems) |
| `boot/plymouth/` | Plymouth splash screen |
### Desktop (`modules/nixos/desktop/`)
| Module | Description |
|---|---|
| `desktop/gnome/` | GNOME desktop environment |
| `desktop/hyprland/` | Hyprland compositor |
| `desktop/cosmic/` | COSMIC desktop environment |
### Development (`modules/nixos/development/`)
Enables development tools and language support. Options:
```nix
mjallen.development = {
enable = true;
includeLanguages = [ "python" "c" ];
includeContainers = true;
};
```
### Hardware (`modules/nixos/hardware/`)
| Module | Description |
|---|---|
| `hardware/amd/` | AMD GPU (AMDGPU driver, LACT) |
| `hardware/nvidia/` | NVIDIA GPU |
| `hardware/battery/` | Battery charge threshold management |
| `hardware/raspberry-pi/` | Raspberry Pi hardware support and DT overlays |
| `hardware/openrgb/` | OpenRGB for LED control |
| `hardware/btrfs/` | btrfs-specific settings |
| `hardware/common/` | Common hardware defaults |
### Headless (`modules/nixos/headless/`)
Server profile — disables suspend/hibernate, enables systemd watchdog, no display manager.
```nix
mjallen.headless.enable = true;
```
### Home Assistant (`modules/nixos/homeassistant/`)
Full smart home stack. See [Home Assistant docs](../home-assistant/README.md) for details.
```nix
mjallen.services.home-assistant.enable = true;
```
### Impermanence (`modules/nixos/impermanence/`)
Ephemeral root filesystem with explicit persistence declarations.
```nix
mjallen.impermanence = {
enable = true;
extraDirectories = [ { directory = "/var/lib/myapp"; user = "myapp"; } ];
};
```
### Monitoring (`modules/nixos/monitoring/`)
Prometheus metrics and Grafana dashboards.
```nix
mjallen.monitoring.enable = true;
```
### Network (`modules/nixos/network/`)
Hostname, firewall, NetworkManager profiles, static IP configuration.
```nix
mjallen.network = {
hostName = "my-host";
ipv4 = {
method = "manual";
address = "10.0.1.5/24";
gateway = "10.0.1.1";
dns = "1.1.1.1";
interface = "eth0";
};
firewall = {
enable = true;
allowedTCPPorts = [ 80 443 ];
};
};
```
### Power (`modules/nixos/power/`)
UPS (NUT) support.
```nix
mjallen.power.ups.enable = true;
```
### Security (`modules/nixos/security/`)
| Module | Description |
|---|---|
| `security/common/` | Common hardening (kernel params, etc.) |
| `security/tpm/` | TPM2 — Clevis disk unlock |
### Services (`modules/nixos/services/`)
~50 self-hosted service modules, all built with `mkModule`. Each exposes at minimum `enable`, `port`, `reverseProxy`, and `openFirewall`. Common usage pattern:
```nix
mjallen.services.jellyfin = {
enable = true;
port = 8096;
reverseProxy.enable = true;
};
```
Available services:
`actual`, `ai`, `appimage`, `arrs`, `attic`, `authentik`, `authentikRac`, `booklore`, `caddy`, `calibre`, `calibre-web`, `cockpit`, `code-server`, `collabora`, `coturn`, `crowdsec`, `dispatcharr`, `free-games-claimer`, `gitea`, `glance`, `glances`, `grafana`, `guacd`, `headscale`, `immich`, `jellyfin`, `jellyseerr`, `lubelogger`, `manyfold`, `matrix`, `minecraft`, `mongodb`, `nebula`, `netbootxyz`, `nextcloud`, `ntfy`, `onlyoffice`, `opencloud`, `orca`, `paperless`, `paperless-ai`, `protonmail-bridge`, `restic`, `samba`, `sparky-fitness`, `sparky-fitness-server`, `sunshine`, `tdarr`, `termix`, `tunarr`, `unmanic`, `uptime-kuma`, `wyoming`, `your-spotify`
#### Nebula VPN (`services/nebula/`)
Unified module for both lighthouse and node roles:
```nix
# Lighthouse
mjallen.services.nebula = {
enable = true;
isLighthouse = true;
port = 4242;
secretsPrefix = "pi5/nebula";
secretsFile = lib.snowfall.fs.get-file "secrets/pi5-secrets.yaml";
hostSecretName = "lighthouse";
};
# Node
mjallen.services.nebula = {
enable = true;
port = 4242;
lighthouses = [ "10.1.1.1" ];
staticHostMap = { "10.1.1.1" = [ "mjallen.dev:4242" ]; };
secretsPrefix = "mymachine/nebula";
secretsFile = lib.snowfall.fs.get-file "secrets/mymachine-secrets.yaml";
hostSecretName = "mymachine";
};
```
See [Secrets Management](../../README.md#generating-nebula-vpn-certificates) for how to generate the required certificates.
### SOPS (`modules/nixos/sops/`)
Configures sops-nix to decrypt secrets using the machine's SSH host key as an age key.
```nix
mjallen.sops = {
enable = true;
sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; # default
};
```
### User (`modules/nixos/user/`)
System user account management.
```nix
mjallen.user = {
name = "matt";
mutableUsers = false;
extraGroups = [ "docker" "video" ];
};
```
---
## Home Manager Modules
These modules configure user environments:
### Desktop
- [Applications](./home/applications.md) - User applications
- [Desktop](./home/desktop.md) - User desktop environments
- [Development](./home/development.md) - User development environments
- [Media](./home/media.md) - Media applications
- [Shell](./home/shell.md) - Shell configurations
| Module | Description |
|---|---|
| `desktop/gnome/` | GNOME user settings (extensions, keybindings, etc.) |
| `desktop/theme/` | Theme configuration |
## Module Structure
### Programs
Each module follows a standard structure:
| Module | Description |
|---|---|
| `programs/btop/` | btop system monitor |
| `programs/code/` | VS Code / VSCodium settings |
| `programs/git/` | Git user config |
| `programs/hyprland/` | Hyprland compositor config |
| `programs/kitty/` | Kitty terminal config |
| `programs/librewolf/` | LibreWolf browser settings |
| `programs/mako/` | Mako notification daemon |
| `programs/nwg-dock/` | nwg-dock panel |
| `programs/nwg-drawer/` | nwg-drawer app launcher |
| `programs/nwg-panel/` | nwg-panel bar |
| `programs/opencode/` | OpenCode AI coding assistant |
| `programs/update-checker/` | Automatic flake update checker |
| `programs/waybar/` | Waybar status bar |
| `programs/wlogout/` | Logout menu |
| `programs/wofi/` | Wofi launcher |
| `programs/zsh/` | Zsh shell config |
```
modules/nixos/example-module/
├── default.nix # Main implementation
├── options.nix # Option declarations
└── submodule/ # Optional submodules
└── default.nix # Submodule implementation
```
### Other
### default.nix
| Module | Description |
|---|---|
| `gpg/` | GPG agent configuration |
| `services/pass/` | Password store |
| `shell-aliases/` | Common shell aliases |
| `sops/` | User-level SOPS secrets |
| `stylix/` | System-wide theming (colours, fonts, wallpaper) |
| `user/` | User environment defaults |
The `default.nix` file contains the main implementation of the module:
---
## Module Development
### Using `mkModule`
The `lib.mjallen.mkModule` helper (`lib/module/default.nix`) creates a fully-featured NixOS module from a minimal spec:
```nix
{
config,
lib,
pkgs,
namespace,
...
}:
{ config, lib, namespace, pkgs, ... }:
let
cfg = config.${namespace}.example-module;
in
{
imports = [ ./options.nix ];
name = "my-service";
cfg = config.${namespace}.services.${name};
config = lib.mkIf cfg.enable {
# Module implementation when enabled
serviceConfig = lib.${namespace}.mkModule {
inherit config name;
description = "my service";
options = {
# extra options beyond the standard set
myOption = lib.${namespace}.mkOpt lib.types.str "default" "Description";
};
moduleConfig = {
services.my-service = {
enable = true;
port = cfg.port;
};
};
};
}
in
{ imports = [ serviceConfig ]; }
```
### options.nix
Standard options provided by `mkModule` for free: `enable`, `port`, `listenAddress`, `openFirewall`, `configDir`, `dataDir`, `createUser`, `configureDb`, `environmentFile`, `reverseProxy.*`, `redis.*`, `extraEnvironment`, `hashedPassword`, `puid`, `pgid`, `timeZone`.
The `options.nix` file declares the module's configuration options:
### Using `mkContainerService`
For Podman/OCI container services, use `mkContainerService` instead:
```nix
{ lib, namespace, ... }:
with lib;
let
inherit (lib.${namespace}) mkOpt;
in
{
options.${namespace}.example-module = {
enable = mkEnableOption "enable example module";
# Other option declarations
};
}
lib.${namespace}.mkContainerService {
inherit config name;
image = "ghcr.io/example/my-app:latest";
internalPort = 8080;
volumes = [ "${cfg.configDir}:/config" ];
};
```
## Using Modules
To use a module in your system configuration:
1. Enable the module in your system configuration:
### Option helpers
```nix
{ config, ... }:
{
mjallen.example-module = {
enable = true;
# Other options
};
}
lib.mjallen.mkOpt types.str "default" "description"
lib.mjallen.mkBoolOpt false "description"
lib.mjallen.mkOpt' types.int 80 # no description
lib.mjallen.enabled # { enable = true; }
lib.mjallen.disabled # { enable = false; }
```
## Creating New Modules
To create a new module:
1. Create a new directory in `modules/nixos/` or `modules/home/`
2. Create `default.nix` and `options.nix` files
3. Implement your module functionality
4. Import the module in your system configuration
See the [Getting Started](../getting-started.md) guide for more details on creating modules.

View File

@@ -4,19 +4,34 @@ This directory contains documentation for each system configuration in this repo
## Systems
- [Desktop (matt-nixos)](./matt-nixos.md) - Main desktop computer
- [NAS (jallen-nas)](./jallen-nas.md) - Home server and NAS
- [NUC (nuc-nixos)](./nuc-nixos.md) - Intel NUC
- [Raspberry Pi 5](./pi5.md) - Raspberry Pi 5
- [MacBook Pro (nixOS)](./macbook-pro-nixos.md) - MacBook Pro running NixOS
| Host | Architecture | OS | Role |
|---|---|---|---|
| [matt-nixos](./matt-nixos.md) | x86_64-linux | NixOS | Primary AMD desktop |
| [jallen-nas](./jallen-nas.md) | x86_64-linux | NixOS | Home server / NAS |
| [nuc-nixos](./nuc-nixos.md) | x86_64-linux | NixOS | Intel NUC — Home Assistant hub |
| [allyx](./allyx.md) | x86_64-linux | NixOS | ASUS ROG Ally X handheld |
| [pi5](./pi5.md) | aarch64-linux | NixOS | Raspberry Pi 5 — network services |
| [macbook-pro-nixos](./macbook-pro-nixos.md) | aarch64-linux | NixOS (Asahi) | Apple Silicon MacBook Pro |
| [macbook-pro](./macbook-pro.md) | aarch64-darwin | nix-darwin | macOS on the same MacBook Pro |
There are also two ISO targets (`x86_64-install-iso/graphical`, `x86_64-linux/iso-minimal`) used for installation media builds.
## Network
All hosts are on the `10.0.1.0/24` LAN with static IPs:
| Host | LAN IP | Overlay (Nebula) |
|---|---|---|
| pi5 | 10.0.1.2 | 10.1.1.1 (lighthouse) |
| jallen-nas | 10.0.1.3 | 10.1.1.x (node) |
| nuc-nixos | 10.0.1.4 | — |
## Common Configuration
All systems share certain common configurations through the modules system. These include:
All systems share:
- SOPS secret management (age keys from SSH host keys)
- Impermanence (ephemeral root, explicit persistence)
- Nix flake-based configuration via Snowfall Lib
- The `mjallen` module namespace
- Base system configuration
- User management
- Network configuration
- Security settings
Each system then adds its specific configurations on top of these common modules.
Each system then layers its own modules and hardware configuration on top.

57
docs/systems/allyx.md Normal file
View File

@@ -0,0 +1,57 @@
# ASUS ROG Ally X (allyx)
`systems/x86_64-linux/allyx/`
## Hardware
- **Device**: ASUS ROG Ally X handheld gaming PC
- **CPU/GPU**: AMD (LACT, CoolerControl)
- **Disk**: NVMe with LUKS encryption
- **Security**: Lanzaboote (Secure Boot)
## Key Features
- Jovian NixOS for Steam Deck-compatible experience
- Steam auto-starts into Game Mode on boot
- Decky Loader for Steam Deck plugins
- Handheld Daemon for power/TDP/fan control
- GNOME available as a desktop session (selectable from Steam)
- SDDM (Wayland) as display manager — GDM disabled
- Gaming enabled (Gamemode, Gamescope, etc.)
- AMD GPU management via LACT
- CoolerControl for fan curves
- iwd as the Wi-Fi backend
- Impermanence (ephemeral root)
## Jovian NixOS
The allyx uses [Jovian NixOS](https://github.com/Jovian-Experiments/Jovian-NixOS) to provide Steam Deck compatibility:
```nix
jovian.steam = {
enable = true;
autoStart = true;
desktopSession = "gnome"; # fall-through desktop session
};
jovian.decky-loader = {
enable = true;
extraPackages = [ pkgs.python3 pkgs.systemd ];
};
```
## Network
- **Hostname**: allyx
- **Wi-Fi backend**: iwd (via NetworkManager)
## Configuration Files
| File | Purpose |
|---|---|
| `default.nix` | Main config — Jovian, gaming, hardware |
| `boot.nix` | Lanzaboote, kernel |
## Secrets
Secrets are in `secrets/allyx-secrets.yaml`, encrypted for: `matt`, `desktop`, `deck`, `steamdeck`, `admin`, `jallen-nas`, `matt_allyx`, `allyx`.

View File

@@ -1,101 +1,104 @@
# NAS Server (jallen-nas)
This document describes the configuration for the NAS server system.
`systems/x86_64-linux/jallen-nas/`
## Hardware
The NAS server is built on AMD hardware:
- **CPU**: AMD (x86_64)
- **GPU**: AMD (LACT for fan/power control)
- **Disk**: NVMe system drive + bcachefs NAS pool
- **Security**: TPM2 (Clevis disk unlock), Lanzaboote (Secure Boot)
- CPU: AMD processor
- Hardware-specific modules:
- `nixos-hardware.nixosModules.common-pc`
- `nixos-hardware.nixosModules.common-cpu-amd`
- `nixos-hardware.nixosModules.common-cpu-amd-pstate`
- `nixos-hardware.nixosModules.common-hidpi`
## Key Features
## Services
- bcachefs storage pool mounted at `/media/nas/main`
- Clevis-based TPM disk unlock at boot (no passphrase required)
- Impermanence — root is ephemeral; state persists to `/media/nas/main/persist`
- Samba shares (Windows file sharing, Time Machine)
- Nebula VPN node (overlay peer, lighthouse at pi5)
- ~40 self-hosted services behind a Caddy reverse proxy
- Authentik SSO protecting most web UIs
- CrowdSec for intrusion detection
- Restic backups
The NAS hosts various services:
## Network
### Media Services
- **LAN IP**: 10.0.1.3 (static, `enp197s0`)
- **Gateway**: 10.0.1.1
- **Nebula**: overlay peer, lighthouse at `mjallen.dev:4242`
- **Jellyfin** - Media server
- **Jellyseerr** - Media request manager
- **Sonarr** - TV show management
- **Radarr** - Movie management
- **Lidarr** - Music management
- **Bazarr** - Subtitle management
- **Music Assistant** - Music streaming integration with Home Assistant
## Storage
### Download Services
| Mount | Filesystem | Description |
|---|---|---|
| `/media/nas/main` | bcachefs | Primary NAS pool (media, appdata, documents) |
| `/media/nas/test` | bcachefs | Secondary test pool |
- **Transmission** - Torrent client
- **NZBGet** - Usenet downloader
- **Prowlarr** - Indexer manager
### Samba Shares
### Document Management
| Share | Time Machine |
|---|---|
| `3d_printer` | no |
| `Backup` | no |
| `Documents` | no |
| `isos` | no |
| `app_data` | no |
| `TimeMachine` | yes (max 1 TB) |
- **Paperless-ngx** - Document management system
## Enabled Services
### File Sharing
| Service | Port | Notes |
|---|---|---|
| Caddy | 443/80 | Reverse proxy for all services |
| Authentik | 9000 | SSO / identity provider |
| Attic | 9012 | Nix binary cache (`cache.mjallen.dev`) |
| Immich | 2283 | Photo management |
| Jellyfin | 8096 | Media server |
| Jellyseerr | 5055 | Media request manager |
| Nextcloud | 9988 | Cloud storage |
| Paperless | 28981 | Document management |
| Paperless AI | 28982 | AI-assisted document tagging |
| Gitea | 3000 | Self-hosted Git |
| Matrix | 8448 | Matrix homeserver |
| Ntfy | 2586 | Push notifications |
| Glance | 5555 | Dashboard |
| Immich | 2283 | Photo library |
| Uptime Kuma | 3001 | Uptime monitoring |
| Code Server | 4444 | VS Code in the browser |
| Cockpit | 9090 | System management UI |
| Collabora | 9980 | Online office suite |
| CrowdSec | 8181 | Intrusion detection |
| Glances | 61208 | System stats |
| Coturn | 3478 | TURN/STUN server |
| Nebula | 4242 | Overlay VPN node |
| Restic | 8008 | Backup service |
| Sunshine | 47989 | Remote desktop (Moonlight) |
| Unmanic | 8265 | Media transcoding |
| Lubelogger | 6754 | Vehicle maintenance log |
| Manyfold | 3214 | 3D model library |
| Booklore | 6066 | Book library |
| Tunarr | 8000 | Virtual TV channels |
| Termix | 7777 | Web terminal |
| Sparky Fitness | 3004/3010 | Fitness tracking |
| Protonmail Bridge | 1025/1143 | SMTP/IMAP bridge |
| Arrs | various | Sonarr, Radarr, etc. |
| AI | various | Ollama, etc. |
| Wyoming | various | Voice assistant pipeline |
- **Samba** - Windows file sharing
- **Nextcloud** - Self-hosted cloud storage
## Configuration Files
### AI Services
| File | Purpose |
|---|---|
| `default.nix` | Main config — network, hardware, filesystems, packages |
| `apps.nix` | All service enable/disable declarations |
| `nas-defaults.nix` | Sets `configDir`/`dataDir` defaults for all services |
| `boot.nix` | Lanzaboote, kernel, initrd |
| `services.nix` | Home Assistant, samba, and other platform services |
| `users.nix` | User accounts (`admin`, `nix-apps`) |
| `sops.nix` | Secret declarations |
| `vpn.nix` | Nebula VPN configuration |
| `disabled.nix` | Services explicitly disabled |
- **Ollama** - Local AI model hosting
## Secrets
### Smart Home
- **Home Assistant** - Smart home controller
- **Zigbee2MQTT** - Zigbee device integration
- **MQTT** - Message broker for IoT devices
- **Thread Border Router** - Thread network for smart home devices
## Storage Configuration
The NAS uses multiple storage devices:
1. **System Drive** - For the operating system
2. **Data Drives** - Configured as a storage array for media and data
## Network Configuration
The NAS is configured with:
- Static IP address
- Firewall rules for the various services
- Tailscale for secure remote access
## Backup Strategy
The NAS implements a comprehensive backup strategy:
1. **System Backup** - Regular backups of the NixOS configuration
2. **Data Backup** - Backups of important data to secondary storage
3. **Off-site Backup** - Critical data is backed up off-site
## Usage and Management
### Accessing Services
Most services are available through a reverse proxy, which provides:
- HTTPS access
- Authentication via Authentik
- Subdomain-based routing
### Adding Storage
To add additional storage to the NAS:
1. Add the physical drive to the system
2. Update the disko configuration
3. Rebuild the system with `nixos-rebuild switch`
### Monitoring
The system can be monitored through:
- Prometheus metrics
- Grafana dashboards
- Home Assistant sensors
Secrets are in `secrets/nas-secrets.yaml`, encrypted for: `matt`, `desktop`, `admin`, `jallen-nas`.

View File

@@ -0,0 +1,69 @@
# MacBook Pro — NixOS / Asahi Linux (macbook-pro-nixos)
`systems/aarch64-linux/macbook-pro-nixos/`
## Hardware
- **Device**: Apple Silicon MacBook Pro (M-series)
- **OS**: NixOS via [Asahi Linux](https://asahilinux.org/) (`nixos-apple-silicon`)
- **Boot**: Asahi boot chain (not traditional EFI)
## Key Features
- Asahi Linux kernel with full Apple Silicon support (sound, GPU, etc.)
- GNOME as the primary desktop; Hyprland available but disabled
- x86_64 emulation via binfmt (enables running x86 binaries)
- Waydroid and libvirtd available (Waydroid disabled by default)
- Battery management — charge threshold set via `macsmc-battery`
- Omnissa Horizon client (custom package) for remote desktop
- Distrobox for containerised Linux environments
- iwd as the Wi-Fi backend
## x86_64 Emulation
```nix
nix.settings.extra-platforms = [ "x86_64-linux" ];
boot.binfmt.emulatedSystems = [ "x86_64-linux" ];
```
This allows building and running x86_64 packages on the ARM host.
## Asahi Hardware
The Asahi hardware module provides:
- Firmware loading from `./firmware/`
- Sound setup (`setupAsahiSound = true`)
- Apple-specific kernel patches and device drivers
Useful packages installed:
`asahi-bless`, `asahi-btsync`, `asahi-nvram`, `asahi-wifisync`, `apfs-fuse`, `apfsprogs`, `muvm`, `fex`
## Network
- **Hostname**: macbook-pro-nixos
- **Wi-Fi backend**: iwd (via NetworkManager)
- Firewall: extra rules for multicast (ports 1990, 2021)
## Battery Management
```nix
mjallen.hardware.battery = {
enable = true;
chargeLimitPath = "/sys/class/power_supply/macsmc-battery/charge_control_end_threshold";
};
```
## Configuration Files
| File | Purpose |
|---|---|
| `default.nix` | Main config — Asahi hardware, users, network |
| `boot.nix` | Asahi boot configuration |
| `filesystems.nix` | Disk layout |
| `hardware-configuration.nix` | Generated hardware config |
| `services.nix` | logind, GDM, GNOME, Flatpak, power settings |
| `firmware/` | Asahi firmware blobs |
## Secrets
Secrets are in `secrets/mac-secrets.yaml`, encrypted for: `matt`, `matt_pi5`, `desktop`, `pi5`, `admin`, `jallen-nas`, `matt_macbook-pro`, `macbook-pro`.

View File

@@ -0,0 +1,40 @@
# MacBook Pro — macOS / nix-darwin (macbook-pro)
`systems/aarch64-darwin/macbook-pro/`
## Overview
This is the [nix-darwin](https://github.com/nix-darwin/nix-darwin) configuration for the same MacBook Pro running macOS. It provides declarative macOS system management alongside Homebrew.
## Key Features
- Touch ID for `sudo`
- Declarative Homebrew (casks and formulae managed via `nix-homebrew`)
- `nh` for easy NixOS/darwin rebuilds
- `attic-client` for accessing the Nix binary cache
- `macpm` for Apple Silicon power monitoring
- Rosetta builder available (disabled, on-demand)
- Linux builder available (disabled)
## Configuration Files
| File | Purpose |
|---|---|
| `default.nix` | Main config — packages, users, environment |
| `homebrew.nix` | Declarative Homebrew casks and formulae |
| `programs.nix` | macOS program settings |
| `system.nix` | System defaults (dock, finder, etc.) |
## User
- **Username**: `mattjallen`
- **Home**: `/Users/mattjallen`
- **Flake path**: `/Users/mattjallen/nix-config` (set via `NH_OS_FLAKE`)
## Rebuilding
```bash
darwin-rebuild switch --flake .#macbook-pro
# or using nh:
nh darwin switch
```

View File

@@ -0,0 +1,50 @@
# Desktop (matt-nixos)
`systems/x86_64-linux/matt-nixos/`
## Hardware
- **CPU**: AMD
- **GPU**: AMD (LACT for fan/power control, OpenRGB)
- **Disk**: NVMe with LUKS encryption (disko)
- **Security**: TPM2, Lanzaboote (Secure Boot)
## Key Features
- GNOME as the primary desktop (Hyprland available but disabled)
- COSMIC available as a specialisation (`nixos-rebuild switch --specialisation cosmic`)
- Gaming — Steam, Gamemode, Gamescope, Lossless Scaling (`lsfg-vk`)
- AMD GPU management via LACT
- CoolerControl for fan curves
- Impermanence (ephemeral root)
- iwd as the Wi-Fi backend
- VSCodium as `$EDITOR`/`$VISUAL`
## Desktop Specialisations
| Specialisation | Description |
|---|---|
| *(default)* | GNOME |
| `cosmic` | COSMIC DE (enables `mjallen.desktop.cosmic`, disables GNOME/Hyprland) |
## Network
- **Hostname**: matt-nixos
- **Wi-Fi backend**: iwd (via NetworkManager)
## Configuration Files
| File | Purpose |
|---|---|
| `default.nix` | Main config |
| `boot.nix` | Lanzaboote, kernel |
| `filesystems.nix` | Disk layout |
| `sops.nix` | Secret declarations |
| `wifi-fixer.nix` | NetworkManager Wi-Fi workaround |
| `services/lsfg-vk/` | Lossless Scaling frame generation |
| `services/ratbagd/` | Gaming mouse config (libratbag) |
| `services/restic/` | Restic backup jobs |
## Secrets
Secrets are in `secrets/desktop-secrets.yaml`, encrypted for: `matt`, `desktop`, `admin`, `jallen-nas`.

57
docs/systems/nuc-nixos.md Normal file
View File

@@ -0,0 +1,57 @@
# Intel NUC (nuc-nixos)
`systems/x86_64-linux/nuc-nixos/`
## Hardware
- **Device**: Intel NUC
- **Disk**: btrfs with LUKS encryption
- **Security**: TPM2, Lanzaboote (Secure Boot)
- **Kernel**: CachyOS `linux-cachyos-lto` (x86_64-v4 build)
## Key Features
- Headless server (no display manager, watchdog enabled)
- Home Assistant — the primary smart home controller
- OpenThread Border Router (OTBR) for Matter/Thread devices
- Impermanence (ephemeral root, persistent state for HA and related services)
- btrfs filesystem (unlike the bcachefs-based NAS and Pi5)
## Network
- **LAN IP**: 10.0.1.4 (static, `enp2s0`)
- **Gateway / DNS**: 10.0.1.1
- **Firewall**: 1883 (MQTT), 8880/8881 (OTBR), 8192
## Services
| Service | Port | Description |
|---|---|---|
| Home Assistant | 8097 | Smart home controller |
| Mosquitto (MQTT) | 1883 | IoT message broker |
| Zigbee2MQTT | 8080 | Zigbee device bridge |
| Music Assistant | 8095 | Music streaming |
| OTBR | 8880/8881 | OpenThread Border Router (Matter/Thread) |
| ESPHome | — | ESP microcontroller firmware |
| PostgreSQL | — | HA database backend |
## Persistent Directories
The following directories survive reboots via impermanence:
- `/esphome`
- `/var/lib/homeassistant`
- `/var/lib/mosquitto`
- `/var/lib/music-assistant`
- `/var/lib/postgresql`
- `/var/lib/zigbee2mqtt`
## Configuration Files
| File | Purpose |
|---|---|
| `default.nix` | All config in one file — HA, OTBR, network, hardware, impermanence |
## Secrets
Secrets are in `secrets/nuc-secrets.yaml`, encrypted for: `nuc`, `admin_nuc`, `matt`, `admin`, `jallen-nas`.

62
docs/systems/pi5.md Normal file
View File

@@ -0,0 +1,62 @@
# Raspberry Pi 5 (pi5)
`systems/aarch64-linux/pi5/`
## Hardware
- **Board**: Raspberry Pi 5
- **Boot**: UEFI (via `rpi5-uefi`)
- **Storage**: bcachefs
- **Connectivity**: Ethernet (`end0`); Wi-Fi and Bluetooth disabled via device tree overlays
## Key Features
- Headless server (no display, no desktop)
- Nebula VPN **lighthouse** — the central relay for the `jallen-nebula` overlay network
- AdGuard Home DNS server (port 53)
- Docker
- Impermanence (ephemeral root)
- Extensive Raspberry Pi device tree overlays configured (I²C, SPI, UART, SDIO, etc.)
## Network
- **LAN IP**: 10.0.1.2 (static, `end0`)
- **Gateway**: 10.0.1.1
- **DNS**: 1.1.1.1
- **Nebula**: lighthouse at `10.1.1.1`, listening on UDP 4242 (public: `mjallen.dev:4242`)
- Firewall: TCP/UDP 53 open (DNS)
## Nebula Lighthouse
The pi5 acts as the Nebula VPN lighthouse for the whole network. All other Nebula nodes connect to it to discover peers.
```nix
mjallen.services.nebula = {
enable = true;
isLighthouse = true;
port = 4242;
secretsPrefix = "pi5/nebula";
secretsFile = lib.snowfall.fs.get-file "secrets/pi5-secrets.yaml";
hostSecretName = "lighthouse";
};
```
## Services
| Service | Port | Description |
|---|---|---|
| AdGuard Home | 53 | DNS ad-blocking |
| Nebula | 4242 (UDP) | VPN lighthouse |
## Configuration Files
| File | Purpose |
|---|---|
| `default.nix` | Main config |
| `boot.nix` | UEFI boot, kernel |
| `adguard.nix` | AdGuard Home configuration |
| `sops.nix` | Secret declarations (SSH keys, system keys) |
## Secrets
Secrets are in `secrets/pi5-secrets.yaml`, encrypted for: `matt`, `matt_pi5`, `desktop`, `pi5`, `admin`, `jallen-nas`.

View File

@@ -1,213 +1,217 @@
# Troubleshooting Guide
This guide provides solutions for common issues that may arise when using this NixOS configuration.
Common issues and solutions for this NixOS configuration.
## System Issues
## Build Failures
### Failed System Build
### `nixos-rebuild switch` fails
**Problem**: `nixos-rebuild switch` fails with an error.
1. **Syntax error** — the error message includes the file and line number. Common causes: missing `;`, unmatched `{`, wrong type passed to an option.
**Solutions**:
2. **Evaluation error** — read the full error trace. Often caused by a module option receiving the wrong type, or a missing `cfg.enable` guard.
1. **Syntax Errors**:
- Check the error message for file and line number information
- Verify the syntax in the mentioned file
- Common issues include missing semicolons, curly braces, or mismatched quotes
2. **Missing Dependencies**:
- If the error mentions a missing package or dependency:
```
git pull # Update to the latest version
nix flake update # Update the flake inputs
```
3. **Conflicting Modules**:
- Look for modules that might be configuring the same options incompatibly
- Disable one of the conflicting modules or adjust their configurations
4. **Disk Space Issues**:
- Check available disk space with `df -h`
- Clear old generations: `sudo nix-collect-garbage -d`
### Boot Issues
**Problem**: System fails to boot after a configuration change.
**Solutions**:
1. **Boot into a Previous Generation**:
- At the boot menu, select an older generation
- Once booted, revert the problematic change:
```
cd /etc/nixos
git revert HEAD # Or edit the files directly
sudo nixos-rebuild switch
```
2. **Boot from Installation Media**:
- Boot from a NixOS installation media
- Mount your system:
```
sudo mount /dev/disk/by-label/nixos /mnt
sudo mount /dev/disk/by-label/boot /mnt/boot # If separate boot partition
```
- Chroot into your system:
```
sudo nixos-enter --root /mnt
cd /etc/nixos
git revert HEAD # Or edit the files directly
nixos-rebuild switch --install-bootloader
```
## Home Assistant Issues
### Home Assistant Fails to Start
**Problem**: Home Assistant service fails to start.
**Solutions**:
1. **Check Service Status**:
```
systemctl status home-assistant
journalctl -u home-assistant -n 100
3. **Fetch failure** — a flake input or package source can't be downloaded. Check network connectivity, or try:
```bash
nix flake update --update-input <input-name>
```
2. **Database Issues**:
- Check PostgreSQL is running: `systemctl status postgresql`
- Verify database connection settings in Home Assistant configuration
3. **Permission Issues**:
- Check ownership and permissions on config directory:
```
ls -la /var/lib/homeassistant
sudo chown -R hass:hass /var/lib/homeassistant
sudo chmod -R 750 /var/lib/homeassistant
```
4. **Custom Component Issues**:
- Try disabling custom components to isolate the issue:
- Edit `modules/nixos/homeassistant/services/homeassistant/default.nix`
- Comment out the `customComponents` section
- Rebuild: `sudo nixos-rebuild switch`
### Zigbee Device Connection Issues
**Problem**: Zigbee devices fail to connect or are unstable.
**Solutions**:
1. **Verify Device Path**:
- Check the Zigbee coordinator is properly detected:
```
ls -la /dev/ttyUSB*
```
- Update the device path if needed:
- Edit your system configuration
- Set `mjallen.services.home-assistant.zigbeeDevicePath` to the correct path
- Rebuild: `sudo nixos-rebuild switch`
2. **Interference Issues**:
- Move the Zigbee coordinator away from other wireless devices
- Try a USB extension cable to improve positioning
- Change Zigbee channel in Zigbee2MQTT configuration
3. **Reset Zigbee2MQTT**:
```
systemctl restart zigbee2mqtt
4. **Disk space** — build sandbox fills up. Free space:
```bash
sudo nix-collect-garbage -d
df -h /nix
```
### Automation Issues
### Assertion failures
**Problem**: Automations don't run as expected.
If you see `assertion failed`, read the `message` field. For example:
```
error: assertion failed at …/nebula/sops.nix
mjallen.services.nebula.secretsPrefix must be set
```
Set the required option in the system configuration.
**Solutions**:
## Boot Issues
1. **Check Automation Status**:
- In Home Assistant UI, verify the automation is enabled
- Check Home Assistant logs for automation execution errors
### System won't boot after a config change
2. **Entity Issues**:
- Verify entity IDs are correct
- Check if entities are available/connected
- Test direct service calls to verify entity control works
1. At the boot menu, select a previous generation.
2. Once booted, revert the change:
```bash
cd /etc/nixos
git revert HEAD
sudo nixos-rebuild switch --flake .#$(hostname)
```
3. **Trigger Issues**:
- Test the automation manually via Developer Tools > Services
- Use `automation.trigger` service with the automation's entity_id
### Booting from installation media to recover
## Flake Issues
```bash
# Mount the system (adjust device paths as needed)
sudo mount /dev/disk/by-label/nixos /mnt
sudo mount /dev/disk/by-label/boot /mnt/boot
### Flake Input Update Errors
# Chroot in
sudo nixos-enter --root /mnt
cd /etc/nixos
**Problem**: `nix flake update` fails or causes issues.
# Revert and rebuild
git revert HEAD
nixos-rebuild switch --flake .#hostname --install-bootloader
```
**Solutions**:
### Lanzaboote / Secure Boot issues
1. **Selective Updates**:
- Update specific inputs instead of all at once:
```
nix flake lock --update-input nixpkgs
```
If Secure Boot enrolment fails or the system won't verify:
2. **Rollback Flake Lock**:
- If an update causes issues, revert to previous flake.lock:
```
git checkout HEAD^ -- flake.lock
```
```bash
# Check enrolled keys
sbctl status
3. **Pin to Specific Revisions**:
- In `flake.nix`, pin problematic inputs to specific revisions:
```nix
nixpkgs-stable.url = "github:NixOS/nixpkgs/5233fd2ba76a3accb05f88b08917450363be8899";
```
# Re-enrol if needed (run as root)
sbctl enrol-keys --microsoft
## Secret Management Issues
# Sign bootloader files manually
sbctl sign -s /boot/EFI/systemd/systemd-bootx64.efi
```
### Sops Decryption Errors
## SOPS / Secrets Issues
**Problem**: Sops fails to decrypt secrets.
### `secret not found` or permission denied at boot
**Solutions**:
1. Verify the secret key path matches what's declared in the module's `sops.nix`.
2. Check the secret exists in the SOPS file:
```bash
sops --decrypt secrets/nas-secrets.yaml | grep "the-key"
```
3. Check the `owner`/`group` set on the secret matches the service user.
1. **Key Issues**:
- Verify your GPG key is available and unlocked
- Check `.sops.yaml` includes your key fingerprint
### Can't decrypt — wrong age key
2. **Permission Issues**:
- Check file permissions on secret files
- Make sure the user running `nixos-rebuild` has access to the GPG key
The machine's age key is derived from `/etc/ssh/ssh_host_ed25519_key`. If the host key was regenerated, the age key changed and existing secrets can no longer be decrypted.
To fix: re-encrypt the secrets file with the new public key:
```bash
# Get the new public key
nix-shell -p ssh-to-age --run 'ssh-to-age < /etc/ssh/ssh_host_ed25519_key.pub'
# Update .sops.yaml with the new key, then:
sops updatekeys secrets/nas-secrets.yaml
```
### Adding a new secret to an existing file
```bash
sops secrets/nas-secrets.yaml
# Editor opens with decrypted YAML — add your key, save, sops re-encrypts
```
## Nebula VPN Issues
### Peers can't connect
1. Verify the lighthouse is reachable on its public address:
```bash
nc -zvu mjallen.dev 4242
```
2. Check the nebula service on both hosts:
```bash
systemctl status nebula@jallen-nebula
journalctl -u nebula@jallen-nebula -n 50
```
3. Confirm the CA cert, host cert, and host key are all present and owned by the `nebula-jallen-nebula` user:
```bash
ls -la /run/secrets/pi5/nebula/
```
4. Verify the host cert was signed by the same CA as the other nodes:
```bash
nebula-cert verify -ca ca.crt -crt host.crt
```
### Certificate expired
Re-sign the host certificate:
```bash
nebula-cert sign -name "hostname" -ip "10.1.1.x/24" \
-ca-crt ca.crt -ca-key ca.key \
-out-crt host.crt -out-key host.key
# Update SOPS, rebuild
```
## Impermanence Issues
### Service fails because its data directory is missing after reboot
If a service stores state in a path that isn't in the persistence list, it will be wiped on reboot. Add it to `impermanence.extraDirectories`:
```nix
mjallen.impermanence.extraDirectories = [
{ directory = "/var/lib/my-service"; user = "my-service"; group = "my-service"; mode = "0750"; }
];
```
Then move the existing data if needed:
```bash
cp -a /var/lib/my-service /persist/var/lib/my-service
```
## Flake Input Issues
### Input update breaks a build
Roll back the specific input:
```bash
git checkout HEAD^ -- flake.lock
```
Or pin the input to a specific revision in `flake.nix`:
```nix
nixpkgs-unstable.url = "github:NixOS/nixpkgs/abc123def";
```
## Service Issues
### Service won't start
```bash
systemctl status <service>
journalctl -u <service> -n 100 --no-pager
```
### Caddy reverse proxy not routing
1. Check that `reverseProxy.enable = true` is set on the service.
2. Verify the subdomain matches: `reverseProxy.subdomain = "myapp"` → `myapp.mjallen.dev`.
3. Check Caddy logs:
```bash
journalctl -u caddy -n 50
```
### PostgreSQL database missing for a service
If `configureDb = true` is set, the database is created automatically. If it's missing:
```bash
sudo -u postgres createdb my-service
sudo -u postgres psql -c "GRANT ALL ON DATABASE my-service TO my-service;"
```
## Network Issues
### Firewall Blocks Services
### Firewall blocking a service
**Problem**: Services are not accessible due to firewall rules.
Check which ports are open:
```bash
sudo nft list ruleset | grep accept
```
**Solutions**:
Add ports in the system config:
```nix
mjallen.network.firewall.allowedTCPPorts = [ 8080 ];
```
1. **Check Firewall Status**:
```
sudo nix-shell -p iptables --run "iptables -L"
```
2. **Verify Firewall Configuration**:
- Check if ports are properly allowed in the configuration
- Add missing ports if necessary
3. **Temporary Disable Firewall** (for testing only):
```
sudo systemctl stop firewall
# After testing
sudo systemctl start firewall
```
Or if using `mkModule`, set `openFirewall = true` (it's the default).
## Getting Help
If you encounter an issue not covered in this guide:
1. Check the NixOS Wiki: https://nixos.wiki/
2. Search the NixOS Discourse forum: https://discourse.nixos.org/
3. Join the NixOS Matrix/Discord community for real-time help
4. File an issue in the repository if you believe you've found a bug
- NixOS manual: `nixos-help` or https://nixos.org/manual/nixos/stable/
- NixOS Wiki: https://nixos.wiki/
- NixOS Discourse: https://discourse.nixos.org/
- Nix package search: https://search.nixos.org/packages

View File

@@ -4,41 +4,186 @@ Utility functions for the NixOS/nix-darwin configuration. Exposed via Snowfall L
## Directory Structure
- `default.nix`: Main entry point exports `module`, `file`, and `versioning`
- `module/`: Module creation helpers (`mkModule`, `mkOpt`, `mkBoolOpt`, etc.)
- `file/`: File and path utilities
- `versioning/`: Multi-source version pinning helpers (used by packages)
- `default.nix` Main entry point; exports `module`, `file`, and `versioning`
- `module/` Module creation helpers (`mkModule`, `mkContainerService`, `mkSopsEnvFile`, `mkOpt`, etc.)
- `file/` File and path utilities
- `versioning/` Multi-source version pinning helpers (used by packages)
---
## Module Utilities (`lib.mjallen.module`)
### `mkModule`
Creates a NixOS service module with a standard set of options. All config is gated behind `cfg.enable`.
```nix
lib.mjallen.mkModule {
config # NixOS config attrset (pass-through from module args)
name # Service name — used for option path and systemd unit
description # Text for mkEnableOption (defaults to name)
options # Extra options merged into the submodule
moduleConfig # NixOS config body (applied when cfg.enable = true)
domain # Option namespace domain (default: "services")
serviceName # Systemd service name (default: name)
}
```
**Standard options provided for free:**
| Option | Type | Default | Description |
|---|---|---|---|
| `enable` | bool | `false` | Enable/disable the service |
| `port` | int | `80` | Service listen port |
| `listenAddress` | str | `"0.0.0.0"` | Bind address |
| `openFirewall` | bool | `true` | Open TCP+UDP firewall ports |
| `configDir` | str | `/var/lib/<name>` | Config directory |
| `dataDir` | str | `/var/lib/<name>/data` | Data directory |
| `createUser` | bool | `false` | Create a dedicated system user |
| `configureDb` | bool | `false` | Create a PostgreSQL database |
| `environmentFile` | str\|null | `null` | Path to an env-file |
| `extraEnvironment` | attrs | `{}` | Extra environment variables |
| `hashedPassword` | str\|null | `null` | Hashed password for web auth |
| `puid` / `pgid` | str | `"911"` / `"100"` | UID/GID for container services |
| `timeZone` | str | `"UTC"` | Timezone for container services |
| `redis.enable` | bool | `false` | Create a Redis instance for this service |
| `redis.port` | int | `6379` | Redis port |
| `reverseProxy.enable` | bool | `false` | Add a Caddy reverse proxy block |
| `reverseProxy.subdomain` | str | `<name>` | Caddy subdomain |
| `reverseProxy.domain` | str | `"mjallen.dev"` | Caddy base domain |
| `reverseProxy.upstreamUrl` | str\|null | `null` | Override upstream URL |
| `reverseProxy.extraCaddyConfig` | lines | `""` | Extra Caddyfile directives |
**Default behaviour when enabled:**
- Adds Caddy reverse proxy block (if `reverseProxy.enable = true`)
- Opens firewall ports (if `openFirewall = true`)
- Creates system user/group (if `createUser = true`)
- Creates PostgreSQL database (if `configureDb = true`)
- Creates Redis instance (if `redis.enable = true`)
- Adds `RequiresMountsFor` systemd dependency for `configDir` and `dataDir`
---
### `mkContainerService`
Wraps `mkModule` for Podman/OCI container services. Generates the full container definition automatically.
```nix
lib.mjallen.mkContainerService {
config # NixOS config attrset
name # Service/container name
image # OCI image reference (e.g. "ghcr.io/example/app:latest")
internalPort # Port the container listens on internally
description # Human-readable description (defaults to name)
options # Extra mkModule options
volumes # Extra volume mount strings
environment # Extra environment variables (merged with PUID/PGID/TZ)
environmentFiles # List of env-file paths (e.g. SOPS template paths)
extraOptions # Extra --opt strings for the container runtime
devices # Device mappings
extraConfig # Extra NixOS config merged into moduleConfig
}
```
The systemd service is named `podman-<name>`, and the port binding is `<cfg.port>:<internalPort>`.
---
### `mkSopsEnvFile`
Generates a SOPS secrets block and a SOPS template env-file in a single call. Useful for services that need secrets injected as environment variables.
```nix
lib.mjallen.mkSopsEnvFile {
secrets # attrset: sops-key → extra attrs (owner, group, etc.)
name # Template file name, e.g. "myapp.env"
content # Template body (use config.sops.placeholder."key")
restartUnit # Systemd unit to restart when secrets change
owner # File owner (default: "nix-apps")
group # File group (default: "jallen-nas")
mode # File permissions (default: "660")
sopsFile # Default SOPS file for all secrets
}
```
---
### Option helpers
| Function | Signature | Description |
|---|---|---|
| `mkOpt` | `type → default → description → mkOption` | Standard option shorthand |
| `mkOpt'` | `type → default → mkOption` | `mkOpt` without description |
| `mkBoolOpt` | `default → description → mkOption` | Boolean option shorthand |
| `mkBoolOpt'` | `default → mkOption` | Boolean option without description |
| `mkReverseProxyOpt` | `name → attrset` | Standard Caddy reverse proxy sub-options |
---
### Convenience shorthands
| Value | Expands to |
|---|---|
| `enabled` | `{ enable = true; }` |
| `disabled` | `{ enable = false; }` |
---
### Attribute utilities
| Function | Description |
|---|---|
| `mkModule` | Create a NixOS module with standard options (enable, port, reverseProxy, firewall, user, postgresql, redis) |
| `mkOpt` | `type → default → description → mkOption` shorthand |
| `mkOpt'` | `mkOpt` without description |
| `mkBoolOpt` | Boolean `mkOpt` shorthand |
| `mkBoolOpt'` | Boolean `mkOpt` without description |
| `mkReverseProxyOpt` | Standard Caddy reverse proxy sub-options |
| `enabled` | `{ enable = true; }` shorthand |
| `disabled` | `{ enable = false; }` shorthand |
| `capitalize` | Capitalise the first character of a string |
| `boolToNum` | Convert a boolean to 0 or 1 |
| `default-attrs` | Apply `lib.mkDefault` to every value in an attrset |
| `force-attrs` | Apply `lib.mkForce` to every value in an attrset |
| `nested-default-attrs` | Apply `default-attrs` one level deeper |
| `nested-force-attrs` | Apply `force-attrs` one level deeper |
| `enableForSystem` | Filter a module list to only those that match a given system string |
## File Utilities (`lib.mjallen.file`)
---
### String utilities
| Function | Description |
|---|---|
| `getFile` | Resolve a path relative to the flake root |
| `safeImport` | Import a Nix file with a fallback on error |
| `scanDir` | Return a list of directory names under a path |
| `importModulesRecursive` | Recursively discover and import all `default.nix` files under a directory |
| `capitalize` | Capitalise the first character of a string |
---
### Boolean utilities
| Function | Description |
|---|---|
| `boolToNum` | `true → 1`, `false → 0` |
---
## Home Manager Utilities (`lib.mjallen.module`)
### `mkHomeModule`
Creates a Home Manager module with a standard `enable` option.
```nix
lib.mjallen.mkHomeModule {
config # HM config attrset
domain # Option namespace domain, e.g. "programs" or "desktop"
name # Module name, e.g. "btop"
description # Text for mkEnableOption (defaults to name)
options # Extra options merged into the submodule
moduleConfig # HM config body (applied when cfg.enable = true)
}
```
---
## File Utilities (`lib.mjallen.file`)
Helpers for resolving paths relative to the flake root. Primarily used internally by modules and packages.
---
## Versioning Utilities (`lib.mjallen.versioning`)
Used by packages that track multiple upstream variants (e.g. `linux-rpi`, `proton-cachyos`).
See `lib/versioning/default.nix` for the full API.
Used by packages that track multiple upstream variants (e.g. `proton-cachyos`, `linux-rpi`). Reads a `version.json` file and resolves sources with optional variable substitution and per-variant overrides.
See `lib/versioning/default.nix` for the full API and `docs/version.schema.json` for the `version.json` schema.

View File

@@ -1,6 +1,7 @@
{
config,
lib,
pkgs,
namespace,
...
}:
@@ -16,6 +17,16 @@ let
enable = true;
port = cfg.port;
openFirewall = cfg.openFirewall;
allowed-origins = [
"https://10.0.1.3:${toString cfg.port}"
"https://jallen-nas:${toString cfg.port}"
"https://jallen-nas.local:${toString cfg.port}"
];
plugins = with pkgs.${namespace}; [
# cockpit-benchmark
cockpit-podman
cockpit-machines
];
};
};
};

View File

@@ -1,74 +0,0 @@
{
config,
lib,
pkgs,
namespace,
...
}:
with lib;
let
name = "nebula-lighthouse";
cfg = config.${namespace}.services.${name};
ca = config.sops.secrets."pi5/nebula/ca-cert".path;
cert = config.sops.secrets."pi5/nebula/lighthouse-cert".path;
key = config.sops.secrets."pi5/nebula/lighthouse-key".path;
nebulaConfig = lib.${namespace}.mkModule {
inherit config name;
description = "nebula";
options = { };
moduleConfig = {
environment.systemPackages = with pkgs; [ nebula ];
services.nebula.networks = {
jallen-nebula = {
enable = true;
enableReload = true;
isLighthouse = true;
ca = ca;
cert = cert;
key = key;
lighthouse = {
dns = {
enable = false;
host = "localhost";
port = 53;
};
};
listen = {
host = cfg.listenAddress;
port = cfg.port;
};
# lighthouses = [
# "10.1.1.1"
# ];
settings = {
firewall = {
outbound = [
{
# Allow all outbound traffic from this node
port = "any";
proto = "any";
host = "any";
}
];
inbound = [
{
# Allow all outbound traffic from this node
port = "any";
proto = "any";
host = "any";
}
];
};
};
};
};
};
};
in
{
imports = [
nebulaConfig
./sops.nix
];
}

View File

@@ -1,45 +0,0 @@
{
config,
lib,
namespace,
...
}:
with lib;
let
cfg = config.${namespace}.services.nebula-lighthouse;
in
{
config = mkIf cfg.enable {
sops = {
secrets = {
"pi5/nebula/ca-cert" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/pi5-secrets.yaml");
owner = "nebula-jallen-nebula";
group = "nebula-jallen-nebula";
restartUnits = [ "nebula@jallen-nebula.service" ];
};
"pi5/nebula/ca-key" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/pi5-secrets.yaml");
owner = "nebula-jallen-nebula";
group = "nebula-jallen-nebula";
restartUnits = [ "nebula@jallen-nebula.service" ];
};
"pi5/nebula/lighthouse-cert" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/pi5-secrets.yaml");
owner = "nebula-jallen-nebula";
group = "nebula-jallen-nebula";
restartUnits = [ "nebula@jallen-nebula.service" ];
};
"pi5/nebula/lighthouse-key" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/pi5-secrets.yaml");
owner = "nebula-jallen-nebula";
group = "nebula-jallen-nebula";
restartUnits = [ "nebula@jallen-nebula.service" ];
};
};
};
};
}

View File

@@ -8,54 +8,105 @@
with lib;
let
name = "nebula";
cfg = config.${namespace}.services.${name};
ca = config.sops.secrets."jallen-nas/nebula/ca-cert".path;
cert = config.sops.secrets."jallen-nas/nebula/nas-cert".path;
key = config.sops.secrets."jallen-nas/nebula/nas-key".path;
ca = config.sops.secrets."${cfg.secretsPrefix}/ca-cert".path;
cert = config.sops.secrets."${cfg.secretsPrefix}/${cfg.hostSecretName}-cert".path;
key = config.sops.secrets."${cfg.secretsPrefix}/${cfg.hostSecretName}-key".path;
nebulaConfig = lib.${namespace}.mkModule {
inherit config name;
description = "nebula";
options = { };
description = "nebula overlay network node";
options = {
# -----------------------------------------------------------------------
# Role
# -----------------------------------------------------------------------
isLighthouse = lib.${namespace}.mkBoolOpt false "Act as a Nebula lighthouse";
isRelay = lib.${namespace}.mkBoolOpt false "Act as a Nebula relay node";
# -----------------------------------------------------------------------
# Network identity
# -----------------------------------------------------------------------
networkName =
lib.${namespace}.mkOpt types.str "jallen-nebula"
"Nebula network name (used as the systemd service suffix and interface name)";
# -----------------------------------------------------------------------
# SOPS secret location
#
# secretsPrefix — key path prefix inside the SOPS file, e.g. "pi5/nebula"
# The module expects three secrets under this prefix:
# <secretsPrefix>/ca-cert
# <secretsPrefix>/host-cert
# <secretsPrefix>/host-key
#
# secretsFile — path to the SOPS-encrypted YAML that holds the secrets
# -----------------------------------------------------------------------
secretsPrefix = lib.${namespace}.mkOpt types.str "" "SOPS secret key prefix, e.g. \"pi5/nebula\"";
secretsFile =
lib.${namespace}.mkOpt types.str ""
"Path to the SOPS secrets YAML file for this host";
# hostSecretName — the middle segment of the cert/key secret names.
# Secrets are looked up as <secretsPrefix>/<hostSecretName>-cert and
# <secretsPrefix>/<hostSecretName>-key. Defaults to "host"; set to
# e.g. "nas", "lighthouse", or the machine hostname to match existing
# SOPS YAML keys without renaming them.
hostSecretName =
lib.${namespace}.mkOpt types.str "host"
"Secret name segment for cert/key (e.g. \"nas\" looks for nas-cert / nas-key)";
# -----------------------------------------------------------------------
# Peer addressing (ignored on lighthouse nodes)
# -----------------------------------------------------------------------
lighthouses =
lib.${namespace}.mkOpt (types.listOf types.str) [ ]
"Nebula overlay IPs of lighthouse nodes (leave empty on lighthouses)";
staticHostMap = lib.${namespace}.mkOpt (types.attrsOf (
types.listOf types.str
)) { } "Static host map: overlay IP list of public addr:port strings";
# -----------------------------------------------------------------------
# Firewall rules inside the overlay
# -----------------------------------------------------------------------
inboundRules = lib.${namespace}.mkOpt (types.listOf types.attrs) [
{
port = "any";
proto = "any";
host = "any";
}
] "Nebula inbound firewall rules";
outboundRules = lib.${namespace}.mkOpt (types.listOf types.attrs) [
{
port = "any";
proto = "any";
host = "any";
}
] "Nebula outbound firewall rules";
};
moduleConfig = {
environment.systemPackages = with pkgs; [ nebula ];
services.nebula.networks = {
jallen-nebula = {
enable = true;
enableReload = true;
isLighthouse = false;
isRelay = false;
ca = ca;
cert = cert;
key = key;
lighthouses = [
"10.1.1.1"
];
staticHostMap = {
"10.1.1.1" = [
"mjallen.dev:4242"
];
};
settings = {
firewall = {
outbound = [
{
# Allow all outbound traffic from this node
port = "any";
proto = "any";
host = "any";
}
];
inbound = [
{
# Allow all outbound traffic from this node
port = "any";
proto = "any";
host = "any";
}
];
};
};
services.nebula.networks.${cfg.networkName} = {
enable = true;
enableReload = true;
isLighthouse = cfg.isLighthouse;
isRelay = cfg.isRelay;
inherit ca cert key;
lighthouses = cfg.lighthouses;
staticHostMap = cfg.staticHostMap;
listen = {
host = cfg.listenAddress;
port = cfg.port;
};
settings.firewall = {
inbound = cfg.inboundRules;
outbound = cfg.outboundRules;
};
};
};

View File

@@ -7,39 +7,34 @@
with lib;
let
cfg = config.${namespace}.services.nebula;
sopsFile = cfg.secretsFile;
nebulaUser = "nebula-${cfg.networkName}";
nebulaUnit = "nebula@${cfg.networkName}.service";
mkSecret = _key: {
inherit sopsFile;
owner = nebulaUser;
group = nebulaUser;
restartUnits = [ nebulaUnit ];
};
in
{
config = mkIf cfg.enable {
sops = {
secrets = {
"jallen-nas/nebula/ca-cert" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = "nebula-jallen-nebula";
group = "nebula-jallen-nebula";
restartUnits = [ "nebula@jallen-nebula.service" ];
};
assertions = [
{
assertion = cfg.secretsPrefix != "";
message = "mjallen.services.nebula.secretsPrefix must be set (e.g. \"pi5/nebula\")";
}
{
assertion = cfg.secretsFile != "";
message = "mjallen.services.nebula.secretsFile must be set to the path of the SOPS secrets YAML";
}
];
"jallen-nas/nebula/ca-key" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = "nebula-jallen-nebula";
group = "nebula-jallen-nebula";
restartUnits = [ "nebula@jallen-nebula.service" ];
};
"jallen-nas/nebula/nas-cert" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = "nebula-jallen-nebula";
group = "nebula-jallen-nebula";
restartUnits = [ "nebula@jallen-nebula.service" ];
};
"jallen-nas/nebula/nas-key" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = "nebula-jallen-nebula";
group = "nebula-jallen-nebula";
restartUnits = [ "nebula@jallen-nebula.service" ];
};
};
sops.secrets = {
"${cfg.secretsPrefix}/ca-cert" = mkSecret "ca-cert";
"${cfg.secretsPrefix}/${cfg.hostSecretName}-cert" = mkSecret "host-cert";
"${cfg.secretsPrefix}/${cfg.hostSecretName}-key" = mkSecret "host-key";
};
};
}

View File

@@ -6,6 +6,7 @@
nodejs,
npmHooks,
fetchNpmDeps,
requireFile,
stdenv,
}:
let
@@ -16,6 +17,87 @@ let
selected = selectVariant versionSpec null null;
sources = mkAllSources selected;
inherit (selected.variables) version;
# These three packages are published exclusively to GitHub Packages
# (npm.pkg.github.com) which requires authentication — they cannot be
# fetched in the Nix sandbox without a token. Add them to the Nix store
# manually first:
#
# TOKEN=<your GitHub PAT with read:packages scope>
# for pkg in \
# "download/@45Drives/cockpit-css/0.1.12/42ecb717da68e4c31454b5bc6019e3a4fe7dcd6c" \
# "download/@45Drives/cockpit-helpers/0.1.19/29920cb9a0866220cfda58b9db4f34c8435f8960" \
# "download/@45Drives/cockpit-vue-components/0.1.0-beta2/a216666b3e9eb97a30cf47c0b947b4e5661798db"
# do
# curl -L -u "user:$TOKEN" \
# "https://npm.pkg.github.com/$pkg" \
# -o "$(basename $pkg).tgz"
# done
# nix store add-file *.tgz
cockpitCssTarball = requireFile {
name = "cockpit-css-0.1.12.tgz";
# sha512 integrity from yarn.lock
hash = "sha512-RgyedX/5GuriDvLruvmbqb++cIBqIF5py2E4G8/wMtQfUf6QnJqsRLYNp7uzKcLpE2+kjm9pGASdvwV2I2b/YA==";
message = ''
cockpit-benchmark requires @45drives/cockpit-css which is only available
on GitHub Packages (requires authentication). Download it manually:
curl -L -u "user:<GITHUB_PAT>" \
"https://npm.pkg.github.com/download/@45Drives/cockpit-css/0.1.12/42ecb717da68e4c31454b5bc6019e3a4fe7dcd6c" \
-o cockpit-css-0.1.12.tgz
nix store add-file cockpit-css-0.1.12.tgz
'';
};
cockpitHelpersTarball = requireFile {
name = "cockpit-helpers-0.1.19.tgz";
hash = "sha512-dyS3V+XG/9rLGGhFJEA2b+ohrZiGsHteOEktJk9mM9c6WsXJywrlnrHm0YrKksoTUPwXtBY44QrXJNd3zKtvKQ==";
message = ''
cockpit-benchmark requires @45drives/cockpit-helpers which is only available
on GitHub Packages (requires authentication). Download it manually:
curl -L -u "user:<GITHUB_PAT>" \
"https://npm.pkg.github.com/download/@45Drives/cockpit-helpers/0.1.19/29920cb9a0866220cfda58b9db4f34c8435f8960" \
-o cockpit-helpers-0.1.19.tgz
nix store add-file cockpit-helpers-0.1.19.tgz
'';
};
cockpitVueComponentsTarball = requireFile {
name = "cockpit-vue-components-0.1.0-beta2.tgz";
hash = "sha512-QvKCuUlCA9LLrwdGKf1iveiKUvJaExmNZxOUyhxg63BvQwn9rs26uN/MFS2mweCi++Mv6kyN+dJG62L7qCSOXQ==";
message = ''
cockpit-benchmark requires @45drives/cockpit-vue-components which is only
available on GitHub Packages (requires authentication). Download it manually:
curl -L -u "user:<GITHUB_PAT>" \
"https://npm.pkg.github.com/download/@45Drives/cockpit-vue-components/0.1.0-beta2/a216666b3e9eb97a30cf47c0b947b4e5661798db" \
-o cockpit-vue-components-0.1.0-beta2.tgz
nix store add-file cockpit-vue-components-0.1.0-beta2.tgz
'';
};
# Rewrite the package-lock.json to point the three GitHub Packages deps at
# their local store paths so fetchNpmDeps / npm ci can find them offline.
patchedPackageLock =
let
lockFile = "${sources.src}/benchmark/package-lock.json";
in
stdenv.mkDerivation {
name = "cockpit-benchmark-package-lock-patched.json";
nativeBuildInputs = [ jq ];
buildCommand = ''
jq \
--arg cssPath "${cockpitCssTarball}" \
--arg helpersPath "${cockpitHelpersTarball}" \
--arg vuePath "${cockpitVueComponentsTarball}" \
'
.packages["node_modules/@45drives/cockpit-css"].resolved = ("file://" + $cssPath) |
.packages["node_modules/@45drives/cockpit-helpers"].resolved = ("file://" + $helpersPath) |
.packages["node_modules/@45drives/cockpit-vue-components"].resolved = ("file://" + $vuePath)
' ${lockFile} > $out
'';
};
in
stdenv.mkDerivation (finalAttrs: {
pname = "cockpit-benchmark";
@@ -25,6 +107,7 @@ stdenv.mkDerivation (finalAttrs: {
npmDeps = fetchNpmDeps {
src = "${finalAttrs.src}/benchmark";
packageLock = patchedPackageLock;
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
};
@@ -33,19 +116,21 @@ stdenv.mkDerivation (finalAttrs: {
nodejs
npmHooks.npmConfigHook
npmHooks.npmBuildHook
npmHooks.npmInstallHook
];
# fio is the runtime benchmark tool invoked by the plugin's backend script.
passthru.cockpitPath = [ fio ];
# npmConfigHook expects to run in the directory with package.json
preConfigure = ''
cd benchmark
# npmConfigHook expects package.json and node_modules in the working dir
cp -r benchmark/. .
# replace package-lock.json with the patched version that uses store paths
cp ${patchedPackageLock} package-lock.json
chmod u+w package-lock.json
'';
# Write version.js before vite build (mirrors what the Makefile does)
preBuild = ''
# Write version.js before vite build (mirrors what the Makefile does)
pluginVersion="$(jq -r '.version' ../manifest.json)-$(jq -r '.build_number' ../manifest.json)"
echo "export const pluginVersion = \"''${pluginVersion}\";" > src/version.js
'';

View File

@@ -9,7 +9,7 @@
"owner": "45Drives",
"repo": "cockpit-benchmark",
"tag": "v${version}",
"hash": "sha256-YmOCdqAdYPnNcXqCccvI0nVhR/EdYXdkeenmy4DdGK0="
"hash": "sha256-AYGaTwNNAH4rl+AdYAoktkjVBcrBqYcfaihYAEq2Dic="
}
}
}

View File

@@ -11,14 +11,14 @@
"owner": "cockpit-project",
"repo": "cockpit-machines",
"tag": "${version}",
"hash": "sha256-jP/ffo0kwju0xxKMHhDwOsNKO7HjOaJZ/uXYijsElNg="
"hash": "sha256-HAXOjk77y17vI/x4kFCZVNnRYrZFpqhw8PsVKmnznBM="
},
"nodeModules": {
"fetcher": "github",
"owner": "cockpit-project",
"repo": "node-cache",
"rev": "${nodeCacheRev}",
"hash": "sha256-yonEQ7hRskbFDnW/Pc3aOeV7bgu1LCYpi1Ok5/aHeC8="
"hash": "sha256-VZwFbOxtUVYXpIeCpAR3bUOjacf6DXgO6EBHPFWczQU="
},
"cockpitLib": {
"fetcher": "github",

View File

@@ -1,55 +1,55 @@
{
fetchFromGitHub,
lib,
namespace,
nodejs,
stdenv,
}:
let
inherit (lib.trivial) importJSON;
inherit (lib.${namespace}) mkAllSources selectVariant;
stdenv.mkDerivation (finalAttrs: {
versionSpec = importJSON ./version.json;
selected = selectVariant versionSpec null null;
sources = mkAllSources selected;
inherit (selected.variables) version;
in
stdenv.mkDerivation {
pname = "cockpit-podman";
version = "123";
inherit version;
src = fetchFromGitHub {
owner = "cockpit-project";
repo = "cockpit-podman";
tag = finalAttrs.version;
hash = "sha256-N5nhJU9XUsxLWq3mk3bSyorHEM4zSLHt9I+zkdgU2Vk=";
};
src = sources.src;
# Pre-vendored node_modules from cockpit-project/node-cache, pinned via the
# node_modules submodule reference in the source tree.
nodeModules = fetchFromGitHub {
owner = "cockpit-project";
repo = "node-cache";
rev = "e39ef3621b5aefa5bf1c2de7e66a5918fcef620c";
hash = "sha256-+yhHsGEN1IqIxPY7vQysp1ZczcHzXRoNIVN3DyVgwB8=";
};
inherit (sources) nodeModules;
# pkg/lib is checked out from the main cockpit repo at the pinned commit
# referenced in the Makefile (COCKPIT_REPO_COMMIT).
cockpitLib = fetchFromGitHub {
owner = "cockpit-project";
repo = "cockpit";
rev = "5fb84eaefbc5ff4433a21bc452270af8d09e1ab7";
hash = "sha256-FR6TIKQ+3GuDMOMEivDxEx6E/SVIAXh9Cg36JJ694Wc=";
};
# pkg/lib checked out from the main cockpit repo at the commit pinned in
# the Makefile (COCKPIT_REPO_COMMIT).
inherit (sources) cockpitLib;
nativeBuildInputs = [ nodejs ];
# cockpit-podman uses passthru.cockpitPath for the NixOS cockpit module to
# add runtime dependencies to the cockpit service's PATH.
# passthru.cockpitPath is used by the NixOS cockpit module to add runtime
# dependencies to the cockpit service's PATH.
passthru.cockpitPath = [ ];
configurePhase = ''
runHook preConfigure
# Wire up the vendored node_modules
cp -r ${finalAttrs.nodeModules} node_modules
# Replace the empty git submodule placeholder with the real vendored modules.
# Use dotglob so hidden entries (.bin, .package-lock.json, etc.) are included.
rm -rf node_modules
mkdir node_modules
(shopt -s dotglob; cp -r $nodeModules/* node_modules/)
chmod -R u+w node_modules
# Wire up pkg/lib from the pinned cockpit repo
# Node needs package-lock.json at the project root to resolve modules.
cp node_modules/.package-lock.json package-lock.json
# Wire up pkg/lib from the pinned cockpit repo.
mkdir -p pkg
cp -r ${finalAttrs.cockpitLib}/pkg/lib pkg/lib
cp -r $cockpitLib/pkg/lib pkg/lib
chmod -R u+w pkg
runHook postConfigure
@@ -75,9 +75,9 @@ stdenv.mkDerivation (finalAttrs: {
meta = {
description = "Cockpit UI for Podman containers";
homepage = "https://github.com/cockpit-project/cockpit-podman";
changelog = "https://github.com/cockpit-project/cockpit-podman/releases/tag/${finalAttrs.version}";
changelog = "https://github.com/cockpit-project/cockpit-podman/releases/tag/${version}";
license = lib.licenses.lgpl21Plus;
platforms = lib.platforms.linux;
maintainers = [ ];
};
})
}

View File

@@ -3,6 +3,7 @@
# https://search.nixos.org/options and in the NixOS manual (`nixos-help`).
{
lib,
namespace,
...
}:
@@ -103,9 +104,13 @@
# ###################################################
services = {
nebula-lighthouse = {
nebula = {
enable = true;
isLighthouse = true;
port = 4242;
secretsPrefix = "pi5/nebula";
secretsFile = lib.snowfall.fs.get-file "secrets/pi5-secrets.yaml";
hostSecretName = "lighthouse";
};
};

View File

@@ -158,6 +158,13 @@ in
nebula = {
enable = true;
port = 4242;
lighthouses = [ "10.1.1.1" ];
staticHostMap = {
"10.1.1.1" = [ "mjallen.dev:4242" ];
};
secretsPrefix = "jallen-nas/nebula";
secretsFile = lib.snowfall.fs.get-file "secrets/nas-secrets.yaml";
hostSecretName = "nas";
};
netbootxyz = {
enable = false;

View File

@@ -63,7 +63,6 @@ in
"minecraft"
"mongodb"
"nebula"
"nebula-lighthouse"
"netbootxyz"
"nextcloud"
"ntfy"