commit 0cec50d6071d9d8da11b857cc4ce79cf98f33bed Author: Elias Kohout Date: Tue Apr 7 02:34:03 2026 +0200 init by ai diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..68dc93b --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# Secrets (encrypted with sops, but don't auto-commit) +/secrets/secrets.yaml + +# System files +.DS_Store +*.swp +*~ +.vscode/ + +# Temporary files +*.tmp +.#* + +# Nix artifacts +result +result-* +.envrc +.direnv/ + +# Development +.idea/ +*.iml diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..7c74745 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,390 @@ +# Architecture & Design Principles + +An overview of how your portable NixOS configuration is structured and why. + +## Core Design Goals + +1. **Portability**: Deploy to new machines, existing NixOS, or non-NixOS with minimal effort +2. **Modularity**: Enable/disable features independently without tight coupling +3. **Reproducibility**: Flakes + lock files ensure identical environments across machines +4. **Maintainability**: Clear separation of concerns (system vs home, shared vs per-machine) +5. **Secrets Management**: Encrypted, portable secrets with sops-nix +6. **Scalability**: Easy to add new machines and modules + +## Architecture Overview + +``` +nix-los/ +├── flake.nix # Single source of truth for all configurations +│ # Defines: inputs, outputs, configurations +│ +├── hosts/ # Per-machine specific overrides +│ ├── laptop/ # Machine-specific hardware, features +│ └── server/ # (template for new machines) +│ +├── nixos/ # System-level modules (NixOS only) +│ ├── default.nix # Imports all modules +│ └── modules/ # Toggleable features +│ ├── system.nix # Users, sudo, locale +│ ├── development.nix # Languages, tools +│ ├── shell.nix # Shell config +│ └── secrets-example.nix (inactive) +│ +├── home/ # User-level configuration (portable) +│ ├── default.nix # Imports all modules, can run standalone +│ └── modules/ # User-level features +│ ├── shell.nix # Zsh, direnv, starship +│ ├── editor.nix # Neovim, VSCode +│ ├── git.nix # Git configuration +│ └── dev-tools.nix # Tmux, utilities +│ +├── secrets/ # Encrypted credentials +│ ├── .sops.yaml # Encryption keys (DO NOT COMMIT UNENCRYPTED) +│ └── secrets.yaml # Encrypted secrets +│ +├── flake.lock # Pinned versions (COMMIT THIS) +└── docs/ + ├── README.md # Getting started + ├── SETUP.md # Detailed setup instructions + ├── QUICKREF.md # Command reference + ├── CUSTOMIZATION.md # Extension patterns + └── ARCHITECTURE.md # This file +``` + +## Data Flow + +### On a NixOS System + +``` +┌─────────────────────────────────────────┐ +│ flake.nix (configuration) │ +│ - Defines all inputs (nixpkgs, etc) │ +│ - Specifies nixosConfigurations │ +└──────────────────┬──────────────────────┘ + │ + ┌──────────┴──────────┬─────────────────┐ + │ │ │ + ┌────▼────┐ ┌─────▼──────┐ ┌─────▼──────┐ + │ hosts/* │ │ nixos/* │ │ home/* │ + │(device) │ ──────► │(system cfg)│ │(user cfg) │ + └────┬────┘ └─────┬──────┘ └─────┬──────┘ + │ │ │ + └────────────────────┼─────────────────┘ + │ + ┌────────────▼──────────────┐ + │ nixos-rebuild switch │ + │ (applies both system+home)│ + └───────────┬────────────────┘ + │ + ┌───────────────────┴───────────────────┐ + │ │ + ┌────▼──────────────┐ ┌──────────────▼─────┐ + │ NixOS System │ │ Home Manager │ + │ /etc/nixos/* │ │ ~/.config/* │ + │ Services, kernel │ │ Packages, dotfiles │ + └───────────────────┘ └────────────────────┘ +``` + +### On Non-NixOS System + +``` +┌──────────────────────────────────────┐ +│ flake.nix (homeConfigurations only) │ +└──────────────────┬───────────────────┘ + │ + ┌──────────▼──────────────┐ + │ home/* (user config) │ + └──────────┬───────────────┘ + │ + ┌──────────▼──────────────────┐ + │ home-manager switch --flake │ + └──────────┬───────────────────┘ + │ + ┌──────────▼──────────────────┐ + │ Home Manager │ + │ ~/.config, ~/.local/share │ + │ Packages, dotfiles │ + └────────────────────────────┘ +``` + +## Module Design Pattern + +Each module follows this pattern for maximum flexibility: + +```nix +{ config, lib, pkgs, ... }: + +{ + # 1. Define options (schema) + options.custom.feature = { + enable = lib.mkEnableOption "Feature"; + setting1 = lib.mkOption { /* ... */ }; + }; + + # 2. Conditionally implement + config = let + cfg = config.custom.feature; + in lib.mkIf cfg.enable { + # Implementation here + environment.systemPackages = [ /* ... */ ]; + }; +} +``` + +**Why this pattern:** +- ✅ **Declarative**: Clear what can be configured +- ✅ **Composable**: Modules don't interfere +- ✅ **Overridable**: Host can override any setting +- ✅ **Conditional**: Only included when enabled + +## Separation of Concerns + +### System Level (nixos/) - Run once, affects all users + +- OS-level packages (compilers, tools) +- Services (SSH, web servers) +- Bootloader, kernel, hardware +- User creation and permissions +- Firewall, networking +- System-wide environment variables + +**When to put config here:** +- Affects the entire system +- Required by multiple users +- Needs root/sudo privileges + +### User Level (home/) - Per-user, portable + +- Shell configuration and aliases +- Editor settings and plugins +- User-installed packages +- Dotfiles (~/.config/*) +- Environment variables (user-specific) +- Git, SSH client configuration + +**When to put config here:** +- Only one user needs it +- Doesn't require system privileges +- Configurable per-user +- Want to port to non-NixOS systems + +## Configuration Hierarchy + +Settings are applied in this order (later overrides earlier): + +1. **nixos/default.nix** - Base system defaults +2. **nixos/modules/*.nix** - System feature modules +3. **hosts/hostname/default.nix** - Machine-specific overrides +4. **home/default.nix** - User base defaults +5. **home/modules/*.nix** - User feature modules + +Example with `custom.development.languages`: + +```nix +# Start: undefined + +# nixos/modules/development.nix: +# options.custom.development.languages = lib.mkOption { default = []; ... }; + +# hosts/laptop/default.nix: +custom.development.languages = [ "rust" "python" ]; # Override + +# Result: [ "rust" "python" ] +``` + +## Flakes Architecture + +### Inputs (Dependencies) + +```nix +inputs = { + nixpkgs = "..."; # Stable packages + nixpkgs-unstable = "..."; # Cutting-edge packages + home-manager = "..."; # User config management + sops-nix = "..."; # Secrets management + disko = "..."; # Disk partitioning +}; +``` + +**Why these inputs:** +- **nixpkgs + unstable**: Mix stable (secure) with latest (features) +- **home-manager**: User config separate from system +- **sops-nix**: Encrypted secrets, portable +- **disko**: Declarative disk setup for new machines + +### Outputs (What's available) + +```nix +outputs = { + nixosConfigurations = { + laptop = nixosSystem { ... }; # Full system config + server = nixosSystem { ... }; + }; + homeConfigurations = { + "myuser@linux" = homeManagerConfiguration { ... }; # Standalone HM + }; + devShells = { + default = mkShell { ... }; # Development environment + }; + apps = { + installer = { ... }; # Bootstrap helper + }; +} +``` + +## Secrets Flow + +``` +secrets/ +├── .sops.yaml # Key configuration (WHO can decrypt) +└── secrets.yaml (encrypted) + │ + ├─ SSH keys + ├─ API tokens + └─ Passwords + +When applied: + │ + ▼ +Sops decrypts (using ~/.config/sops/age/keys.txt) + │ + ▼ +sops.secrets.* paths available in Nix + │ + ▼ +Placed in /run/secrets/* at boot + │ + ▼ +Referenced in system/home config +``` + +**Key insight**: Secrets are encrypted on disk, decrypted at boot, never stored in nix store in plaintext. + +## Multi-Machine Scaling + +To support N machines: + +1. Add new host in `hosts/newhost/default.nix` +2. Register in `flake.nix` under `nixosConfigurations.newhost` +3. Deploy with: `sudo nixos-rebuild switch --flake .#newhost` + +Each machine: +- Shares `nixos/` modules +- Shares `home/` modules +- Has unique `hosts/` overrides +- Uses same `secrets.yaml` (all machines can decrypt) + +``` +Common Base Per-Machine Override +───────────── ────────────────── +nixos/default.nix → hosts/laptop/default.nix +nixos/modules/ → (machine-specific features) +home/modules/ → (shared everywhere) +``` + +## Update Strategy + +``` +Stable ← └─ Pinned via flake.lock + │ + ├─ Low risk, predictable + └─ Most system components + +Unstable → Override in modules when needed + │ + ├─ Fast-moving + └─ For specific packages (bleeding edge editor, tools) +``` + +Update process: +```bash +# Pin current state +git commit flake.lock + +# Update specific input +nix flake update nixpkgs + +# Test +sudo nixos-rebuild test --flake .#laptop + +# Deploy +sudo nixos-rebuild switch --flake .#laptop + +# Save new state +git commit flake.lock +``` + +## Extension Points + +### Add Feature: Create a new module + +1. Create `nixos/modules/myfeature.nix` or `home/modules/myfeature.nix` +2. Follow module pattern (options + config) +3. Import in `nixos/default.nix` or `home/default.nix` +4. Enable in host config: `custom.myfeature.enable = true` + +### Add Machine: Copy host template + +1. Create `hosts/newmachine/default.nix` +2. Customize for that machine +3. Add to `flake.nix` under `nixosConfigurations` +4. Deploy with `sudo nixos-rebuild switch --flake .#newmachine` + +### Add Dependency: Update flake inputs + +1. Edit `flake.nix` inputs section +2. Run `nix flake update` +3. Commit `flake.lock` + +### Add Secret: Edit secrets.yaml + +1. Run `sops secrets/secrets.yaml` +2. Add key-value pair +3. Reference in module with `config.sops.secrets."key".path` + +## Testing & Safety + +### Before Deploying + +```bash +nix flake check # Syntax validation +nix flake show # Check all outputs +sudo nixos-rebuild test # Build without activating +``` + +### Rollback if Issues + +```bash +# NixOS (automatic previous generation) +sudo nixos-rebuild --rollback switch + +# Home Manager (manual) +home-manager switch --flake .#myuser@linux ~/.local/state/home-manager/previous +``` + +### Validate Changes + +```bash +# What changed? +sudo nixos-rebuild diff --flake .#laptop + +# What will happen? +sudo nixos-rebuild test --flake .#laptop + +# Apply +sudo nixos-rebuild switch --flake .#laptop +``` + +## Performance Considerations + +- **Flakes**: Slow evaluation (1-2 seconds) but reproducible +- **Modularity**: More files but faster edits +- **Secrets**: Decryption only at boot (fast) +- **Unstable**: More binary cache misses (compilation time) + +## See Also + +- **README.md** - Getting started +- **SETUP.md** - Step-by-step installation +- **QUICKREF.md** - Common commands +- **CUSTOMIZATION.md** - Extension patterns diff --git a/CUSTOMIZATION.md b/CUSTOMIZATION.md new file mode 100644 index 0000000..3fe7d14 --- /dev/null +++ b/CUSTOMIZATION.md @@ -0,0 +1,477 @@ +# Customization Guide + +Advanced customization patterns for your portable NixOS setup. + +## Creating Custom Modules + +### Pattern 1: Language-Specific Development Environment + +Create `nixos/modules/languages/rust.nix`: + +```nix +{ config, lib, pkgs, ... }: + +{ + options.custom.languages.rust.enable = lib.mkEnableOption "Rust development"; + + config = lib.mkIf config.custom.languages.rust.enable { + environment.systemPackages = with pkgs; [ + rustup + cargo-edit + cargo-deny + rust-analyzer + ]; + }; +} +``` + +Use in `hosts/laptop/default.nix`: +```nix +custom.languages.rust.enable = true; +``` + +### Pattern 2: Per-Machine Overrides + +In `nixos/default.nix`: +```nix +{ config, lib, pkgs, ... }: + +{ + options.custom = { + isLaptop = lib.mkOption { type = lib.types.bool; default = false; }; + isServer = lib.mkOption { type = lib.types.bool; default = false; }; + }; + + config = { + # Settings that only apply to laptops + power.powertop.enable = lib.mkIf config.custom.isLaptop true; + services.thermald.enable = lib.mkIf config.custom.isLaptop true; + }; +} +``` + +In `hosts/laptop/default.nix`: +```nix +custom.isLaptop = true; +``` + +### Pattern 3: Conditional Package Sets + +```nix +{ config, lib, pkgs, ... }: + +{ + options.custom.tools.enable = lib.mkEnableOption "Extra tools"; + + config = lib.mkIf config.custom.tools.enable { + environment.systemPackages = with pkgs; [ + # Always included + git + curl + + # Only if GUI is available + (lib.optionals (config.custom.hasGui) [ + firefox + vlc + ]) + + # Only on laptops + (lib.optionals config.custom.isLaptop [ + powertop + upower + ]) + ]; + }; +} +``` + +## Common Customizations + +### Add Docker/Podman Support + +Edit `nixos/modules/development.nix`: + +```nix +virtualisation.podman = { + enable = true; + dockerCompat = true; # Alias docker → podman +}; + +virtualisation.docker.enable = lib.mkDefault false; +``` + +### Add Kubernetes Tools + +In `nixos/modules/development.nix`: + +```nix +languagePackages = { + # ... existing languages + kubernetes = with pkgs; [ kubectl helm kustomize ]; +}; +``` + +Use in host: +```nix +custom.development.languages = [ "rust" "kubernetes" ]; +``` + +### Add Desktop Environment + +Create `nixos/modules/desktop.nix`: + +```nix +{ config, lib, pkgs, ... }: + +{ + options.custom.desktop = { + enable = lib.mkEnableOption "Desktop environment"; + environment = lib.mkOption { + type = lib.types.enum [ "gnome" "kde" "xfce" ]; + default = "gnome"; + }; + }; + + config = let + cfg = config.custom.desktop; + in lib.mkIf cfg.enable { + services.xserver.enable = true; + services.xserver.displayManager.gdm.enable = cfg.environment == "gnome"; + services.xserver.desktopManager.gnome.enable = cfg.environment == "gnome"; + + # Similar for KDE, XFCE... + }; +} +``` + +Use in host: +```nix +custom.desktop.enable = true; +custom.desktop.environment = "gnome"; +``` + +### Add SSH Server + +Edit `nixos/modules/system.nix`: + +```nix +services.openssh = { + enable = lib.mkDefault false; + ports = [ 22 ]; + settings = { + PermitRootLogin = "no"; + PasswordAuthentication = false; + }; +}; +``` + +Enable in specific host: +```nix +# hosts/server/default.nix +services.openssh.enable = true; +``` + +### Add Nginx Web Server + +Create `nixos/modules/web.nix`: + +```nix +{ config, lib, pkgs, ... }: + +{ + options.custom.web.enable = lib.mkEnableOption "Web server"; + + config = lib.mkIf config.custom.web.enable { + services.nginx = { + enable = true; + virtualHosts."localhost" = { + listen = [{ addr = "127.0.0.1"; port = 8080; }]; + locations."/".root = "/var/www"; + }; + }; + }; +} +``` + +### Add PostgreSQL Database + +Create `nixos/modules/database.nix`: + +```nix +{ config, lib, pkgs, ... }: + +{ + options.custom.database.postgres.enable = lib.mkEnableOption "PostgreSQL"; + + config = lib.mkIf config.custom.database.postgres.enable { + services.postgresql = { + enable = true; + ensureDatabases = [ "dev" ]; + ensureUsers = [{ + name = "dev"; + ensureDBOwnership = true; + }]; + }; + }; +} +``` + +Enable in host: +```nix +custom.database.postgres.enable = true; +``` + +### Add Docker Containers for Services + +Create `nixos/modules/containers.nix`: + +```nix +{ config, lib, pkgs, ... }: + +{ + virtualisation.podman.enable = true; + + # Define containers to auto-start + virtualisation.podman.containers = { + redis = { + image = "redis:latest"; + ports = [ "6379:6379" ]; + autoStart = lib.mkDefault false; + }; + }; +} +``` + +## Home Manager Customizations + +### Add Starship Configuration + +Edit `home/modules/shell.nix`: + +```nix +programs.starship = { + enable = true; + settings = { + add_newline = true; + character = { + success_symbol = "[➜](bold green)"; + error_symbol = "[➜](bold red)"; + }; + rust = { + disabled = false; + symbol = "🦀 "; + }; + }; +}; +``` + +### Add Zsh Plugins + +Edit `home/modules/shell.nix`: + +```nix +programs.zsh.plugins = [ + { + name = "zsh-autosuggestions"; + src = pkgs.fetchFromGitHub { /* ... */ }; + } + { + name = "powerlevel10k"; + src = pkgs.fetchFromGitHub { /* ... */ }; + file = "powerlevel10k.zsh-theme"; + } +]; +``` + +### Add VSCode Configuration + +Edit `home/modules/editor.nix`: + +```nix +programs.vscode = { + enable = true; + extensions = with pkgs.vscode-extensions; [ + ms-python.python + rust-lang.rust-analyzer + hashicorp.terraform + ]; + userSettings = { + "editor.fontSize" = 14; + "editor.formatOnSave" = true; + "python.linting.enabled" = true; + }; +}; +``` + +### Add SSH Configuration + +Create `home/modules/ssh.nix`: + +```nix +{ config, pkgs, ... }: + +{ + programs.ssh = { + enable = true; + matchBlocks = { + "github.com" = { + host = "github.com"; + user = "git"; + identityFile = "~/.ssh/github"; + identitiesOnly = true; + }; + "*.example.com" = { + user = "myuser"; + identityFile = "~/.ssh/work"; + forwardAgent = true; + }; + }; + }; +} +``` + +Import in `home/default.nix`: +```nix +imports = [ + ./modules/ssh.nix +]; +``` + +### Add Tmux Configuration + +Edit `home/modules/dev-tools.nix`: + +```nix +programs.tmux = { + enable = true; + mouse = true; + baseIndex = 1; + keyMode = "vi"; + + plugins = with pkgs.tmuxPlugins; [ + sensible + vim-tmux-navigator + resurrect + ]; + + extraConfig = '' + # Custom keybindings + bind -n M-h select-pane -L + bind -n M-j select-pane -D + bind -n M-k select-pane -U + bind -n M-l select-pane -R + ''; +}; +``` + +## Integration Patterns + +### Using Unstable Packages Everywhere + +In `home/modules/editor.nix`, use unstable neovim: + +```nix +{ pkgs, pkgs-unstable, ... }: + +{ + programs.neovim = { + enable = true; + package = pkgs-unstable.neovim; + # ... + }; +} +``` + +### Conditional Configuration Based on Hardware + +In `hosts/laptop/default.nix`: + +```nix +{ config, lib, pkgs, ... }: + +{ + # Laptop-specific + services.power-profiles-daemon.enable = true; + services.logind.lidSwitchExternalPower = "ignore"; + + # Wireless + networking.wireless.enable = true; + + # Battery + systemd.services.battery-monitor = { + description = "Monitor battery health"; + wantedBy = [ "multi-user.target" ]; + script = "${pkgs.acpi}/bin/acpi"; + }; +} +``` + +### Using Secrets in Home Manager + +In `home/modules/example.nix`: + +```nix +{ config, sops-nix, ... }: + +{ + imports = [ sops-nix.homeManagerModules.sops ]; + + sops.defaultSopsFile = ../../secrets/secrets.yaml; + + sops.secrets."api/myapi" = { + path = "%r/myapi"; # In ~/.config/sops-nix + }; + + # Use in programs + home.sessionVariables.MY_API_KEY = config.sops.secrets."api/myapi".path; +} +``` + +## Testing Changes Safely + +```bash +# Build without applying +home-manager build --flake .#myusername@linux + +# Check what will change +sudo nixos-rebuild test --flake .#laptop # Activates but doesn't add to boot + +# Compare with current +sudo nixos-rebuild diff --flake .#laptop + +# Rollback if something breaks +nixos-rebuild --rollback switch # NixOS +home-manager switch --flake .#myusername@linux ~/.local/state/home-manager/current # HM +``` + +## Performance Optimization + +### Selective Updates + +Update only specific inputs: +```bash +nix flake update nixpkgs +nix flake update home-manager +``` + +### Parallel Builds + +In `flake.nix`, speed up evaluation: +```bash +NIX_BUILD_CORES=4 sudo nixos-rebuild switch --flake .#laptop +``` + +### Binary Cache + +Use nixpkgs binary cache: +```nix +# nixos/default.nix +nix = { + settings = { + substituters = [ "https://cache.nixos.org" ]; + trusted-public-keys = [ "cache.nixos.org-1:6NCHdD59X431o0gWypQMvvZN1FSVucqL2mGvhiqHIl8=" ]; + }; +}; +``` + +See QUICKREF.md for common operations reference. diff --git a/INDEX.md b/INDEX.md new file mode 100644 index 0000000..9db1c38 --- /dev/null +++ b/INDEX.md @@ -0,0 +1,225 @@ +# Project Index + +Quick reference to all files and their purposes. + +## Getting Started + +Start here in this order: + +1. **README.md** - Feature overview and quick start +2. **SETUP.md** - Step-by-step installation guide +3. **QUICKREF.md** - Command reference for daily use + +## Documentation + +- **README.md** - Overview, features, directory structure, usage patterns +- **SETUP.md** - Detailed setup from scratch, per-scenario instructions +- **QUICKREF.md** - Command reference, common tasks, one-liners +- **CUSTOMIZATION.md** - Advanced patterns, extension examples +- **ARCHITECTURE.md** - Design principles, data flow, scalability +- **INDEX.md** - This file + +## Configuration Files + +### Core Configuration + +- **flake.nix** - Main entry point + - Defines all inputs (nixpkgs, home-manager, sops-nix, disko) + - Specifies all outputs (nixosConfigurations, homeConfigurations) + - Includes development shell and installer app + - **Requires customization**: Replace `youruser` with actual username + +### Host Configurations (Per-Machine) + +- **hosts/laptop/default.nix** - Laptop configuration template + - Networking hostname + - Disko disk partitioning + - Development tools to enable + - **Requires customization**: Hostname, disk device, language selection + +- **hosts/server/default.nix** - Server configuration template + - Minimal development tools + - Same structure as laptop, customize as needed + +### NixOS System Modules (Shared) + +- **nixos/default.nix** - System configuration entry point + - Imports all modules + - System packages (git, curl, vim, htop) + - Nix settings, garbage collection, locale + - **Touch rarely**: Mostly imports + +- **nixos/modules/system.nix** - System base configuration + - User creation (currently `youruser` - customize) + - Sudo configuration + - System state version + - **Options exposed**: `custom.system.enable` + +- **nixos/modules/development.nix** - Development tools module + - Language-specific packages (rust, python, nodejs, go, ruby) + - Build tools (gcc, cmake, gdb, etc) + - Container support (docker/podman) + - **Options exposed**: `custom.development.enable`, `custom.development.languages` + - **Example**: Set `languages = [ "rust" "python" ]` to install + +- **nixos/modules/shell.nix** - Shell configuration + - Zsh, bash, fish support + - Starship prompt, direnv integration + - **Options exposed**: `custom.shell.enable`, `custom.shell.defaultShell` + +- **nixos/modules/secrets-example.nix** - Secrets integration example + - Shows how to use sops-nix for encrypted secrets + - NOT imported by default + - Uncomment in `nixos/default.nix` to enable + - Reference for managing SSH keys, API tokens, passwords + +- **nixos/modules/example-template.nix** - Template for new modules + - Shows the module pattern: options + config + - Copy and customize for new features + +### Home Manager User Configuration (Portable) + +- **home/default.nix** - User configuration entry point + - Imports all home modules + - Home username, home directory, stateVersion + - User-level packages (utilities, tools) + - Environment variables + - **Requires customization**: Username, email (in git.nix) + +- **home/modules/shell.nix** - Shell environment + - Zsh configuration (autosuggestion, syntax highlighting) + - Shell aliases (ls → exa, cat → bat) + - Starship prompt setup + - Direnv integration for per-project shells + - Zsh-z plugin for directory navigation + +- **home/modules/editor.nix** - Editor configuration + - Neovim as primary editor + - LSP setup (language servers) + - Plugins: telescope, lualine, treesitter, git integration + - Alternative: VSCode (commented out) + - **Note**: Basic config, customize for your needs + +- **home/modules/git.nix** - Git configuration + - Git username, email + - Default branch, pull strategy + - Common aliases (st, co, br, ci) + - **Requires customization**: Your name and email + +- **home/modules/dev-tools.nix** - Development utilities + - Debuggers (lldb, gdb) + - Version managers (fnm, pyenv) + - Build tools (cmake, ninja, meson) + - System utilities (tmux, htop, iotop) + - Container tools (podman, podman-compose) + - Tmux configuration with mouse support and vi keybindings + +- **home/modules/example-template.nix** - Template for new user modules + - Shows home-manager module pattern + - Copy and customize for new user features + +### Secrets Management + +- **secrets/.sops.yaml** - SOPS encryption configuration + - Specifies which keys can decrypt secrets + - Points to your age public key + - **Requires**: Replace placeholder with your actual age public key + +- **secrets/secrets.yaml** - Encrypted secrets file + - SSH keys, API tokens, passwords + - Encrypted with sops (safe to commit) + - **Usage**: Edit with `sops secrets/secrets.yaml` + - **Never**: Commit unencrypted version + +## Build & Deployment + +No separate deployment files needed - everything flows through flake.nix: + +``` +flake.nix + ├─ nixosConfigurations.laptop → Deploy with: sudo nixos-rebuild switch --flake .#laptop + ├─ homeConfigurations.youruser@linux → Deploy with: home-manager switch --flake .#youruser@linux + ├─ devShells.default → Enter with: nix develop + └─ apps.installer → Run with: nix run .#installer -- laptop +``` + +## Support Files + +- **.gitignore** - Prevents committing secrets, temp files, nix artifacts +- **flake.lock** - COMMIT THIS: Pins all dependencies for reproducibility + +## Quick Navigation + +### "I want to..." + +| Task | File | Line | Command | +|------|------|------|---------| +| **Change my hostname** | hosts/laptop/default.nix | 8 | `sed -i 's/laptop/myname/' ...` | +| **Change my username** | flake.nix | ~40, 70 | Global replace: `"youruser"` | +| **Add a programming language** | hosts/laptop/default.nix | 35 | Add to `languages = [...]` | +| **Install new system package** | nixos/default.nix | 14 | Add to `systemPackages` | +| **Install new user package** | home/default.nix | 16 | Add to `home.packages` | +| **Change default shell** | nixos/modules/shell.nix | 11 | Change `defaultShell = "fish"` | +| **Add SSH key to secrets** | secrets/secrets.yaml | 8 | `sops secrets/secrets.yaml` | +| **Use unstable package** | home/modules/dev-tools.nix | varies | Use `pkgs-unstable.package` | +| **Create a new module** | nixos/modules/example-template.nix | — | Copy template, customize | +| **Add a new machine** | hosts/ | — | `mkdir newhost && cp laptop/* newhost/` | + +## File Customization Checklist + +On first setup, customize these: + +- [ ] **flake.nix** - Replace all `youruser` (3 locations) +- [ ] **hosts/laptop/default.nix** - Set `networking.hostName`, verify `/dev/sda` disk +- [ ] **home/default.nix** - Set `home.username` +- [ ] **home/modules/git.nix** - Set `userName` and `userEmail` +- [ ] **secrets/.sops.yaml** - Add your age public key +- [ ] **secrets/secrets.yaml** - Add actual SSH keys and API tokens + +## File Statistics + +- **Documentation**: 6 files (README, SETUP, QUICKREF, CUSTOMIZATION, ARCHITECTURE, INDEX) +- **Configuration**: 1 core file (flake.nix) +- **System modules**: 5 files (default, system, development, shell, secrets-example) +- **Home modules**: 6 files (default, shell, editor, git, dev-tools, example-template) +- **Hosts**: 2 example files (laptop, server) +- **Secrets**: 2 files (.sops.yaml, secrets.yaml) +- **Support**: 2 files (.gitignore, flake.lock) + +Total: ~24 files, all under 500 lines each + +## Update Schedule + +### When to update inputs + +```bash +# Monthly (security patches) +nix flake update nixpkgs +sudo nixos-rebuild switch --flake .#laptop + +# Less frequently (minor version bumps) +nix flake update + +# Test before committing +nix flake check +sudo nixos-rebuild test --flake .#laptop +``` + +### When to add modules + +Add modules when: +- Feature can be enabled/disabled independently +- Reused across multiple machines +- Follows the options + config pattern + +## Related Resources + +- NixOS Manual: https://nixos.org/manual/nixos/stable +- Home Manager: https://nix-community.github.io/home-manager +- Nix Flakes: https://nix.dev/manual/nix/latest/command-ref/new-cli/nix3-flake +- sops-nix: https://github.com/mic92/sops-nix +- Disko: https://github.com/nix-community/disko + +--- + +**Next Step**: Read README.md for a feature overview, then SETUP.md for installation instructions. diff --git a/QUICKREF.md b/QUICKREF.md new file mode 100644 index 0000000..c16786a --- /dev/null +++ b/QUICKREF.md @@ -0,0 +1,141 @@ +# Quick Reference + +Common commands and patterns for your portable NixOS setup. + +## Deployment + +| Action | Command | +|--------|---------| +| **Rebuild NixOS** | `sudo nixos-rebuild switch --flake .#laptop` | +| **Rebuild Home** | `home-manager switch --flake .#myusername@linux` | +| **Both** | `sudo nixos-rebuild switch --flake .#laptop` + `home-manager switch --flake .#myusername@linux` | +| **Test (no apply)** | `sudo nixos-rebuild test --flake .#laptop` | +| **Activate Home (test)** | `home-manager build --flake .#myusername@linux` | +| **Check validity** | `nix flake check` | +| **Show outputs** | `nix flake show` | +| **Update inputs** | `nix flake update` | +| **Update one input** | `nix flake update nixpkgs` | + +## Secrets + +| Action | Command | +|--------|---------| +| **Generate age key** | `age-keygen -o -f ~/.config/sops/age/keys.txt` | +| **Get public key** | `age-keygen -y ~/.config/sops/age/keys.txt` | +| **Edit secrets** | `sops secrets/secrets.yaml` | +| **View secrets** | `sops -d secrets/secrets.yaml` | +| **Re-encrypt after .sops.yaml change** | `sops -e secrets/secrets.yaml > temp && mv temp secrets/secrets.yaml` | + +## Development + +| Action | Command | +|--------|---------| +| **Enter dev shell** | `nix develop` | +| **Format Nix files** | `nixpkgs-fmt .` | +| **Check for syntax errors** | `nix flake check` | +| **Evaluate flake** | `nix eval .#` | +| **Get derivation path** | `nix derivation show .#youruser@linux` | + +## Utilities + +| Action | Command | +|--------|---------| +| **List installed packages** | `nix-store -q --requisites /run/current-system` | +| **Find broken symlinks** | `nix store gc --print-roots` | +| **Clear old generations** | `sudo nix-collect-garbage -d` | +| **Clear user generations** | `nix-collect-garbage -d` | +| **Check disk usage** | `du -sh /nix` | + +## Files to Edit for Common Tasks + +| Task | File | +|------|------| +| **Change hostname** | `hosts/laptop/default.nix` (networking.hostName) | +| **Add system packages** | `nixos/default.nix` | +| **Add user packages** | `home/default.nix` | +| **Change shell** | `nixos/modules/shell.nix` (custom.shell.defaultShell) | +| **Enable languages** | `hosts/laptop/default.nix` (custom.development.languages) | +| **Add Git config** | `home/modules/git.nix` | +| **Customize Neovim** | `home/modules/editor.nix` | +| **Add SSH keys** | `secrets/secrets.yaml` (encrypted) | +| **Change username** | `flake.nix`, `home/default.nix`, `nixos/modules/system.nix` | + +## Enable Features by Module + +```bash +# Edit hosts/laptop/default.nix: + +# Development tools +custom.development.enable = true; +custom.development.languages = [ "rust" "python" "nodejs" "go" "ruby" ]; + +# Shell setup +custom.shell.enable = true; +custom.shell.defaultShell = "zsh"; # or bash, fish + +# System module +custom.system.enable = true; +``` + +## Debugging + +| Problem | Solution | +|---------|----------| +| **Can't find package** | Check nixpkgs: `nix search nixpkgs mycpackage` | +| **Module import error** | Check imports in default.nix: `nix flake check` | +| **Config won't build** | Get detailed error: `nix flake show 2>&1 \| tail -50` | +| **Secrets not decrypting** | Verify: `sops -d secrets/secrets.yaml` | +| **Home-manager conflicts** | Backup old config: `mv ~/.bashrc ~/.bashrc.bak` | +| **Stuck rebuild** | Kill and retry: `sudo killall nixos-rebuild` | + +## Git Workflow + +```bash +# After making changes: +git add -A +git commit -m "Update: description" +git push + +# On another machine: +git pull +sudo nixos-rebuild switch --flake .#laptop +``` + +## Multi-Machine Example + +```bash +# Add new host +mkdir -p hosts/workstation +cp hosts/laptop/default.nix hosts/workstation/default.nix + +# Add to flake.nix (copy laptop configuration block and update names) + +# Deploy to new machine +sudo nixos-rebuild switch --flake .#workstation +``` + +## One-Liner Installers + +```bash +# Fresh NixOS to existing machine +git clone ~/nix-config && cd ~/nix-config && sudo nixos-rebuild switch --flake .#laptop + +# Home manager on non-NixOS +curl https://nixos.org/channels/nixos-unstable/latest-nixos-*-linux/default.nix && \ + nix run home-manager -- init --switch --flake .#myusername@linux + +# Update everything +nix flake update && sudo nixos-rebuild switch --flake .#laptop && \ + home-manager switch --flake .#myusername@linux +``` + +## Tips + +- ✅ Always commit `flake.lock` for reproducibility +- ✅ Use `lib.mkDefault` for overridable settings +- ✅ Keep secrets encrypted with sops +- ✅ Test with `test` before `switch` +- ✅ Use `--build-on-remote` for slower machines +- ✅ Check `flake check` before rebuilding +- ✅ Keep separate host configs for different machines +- ✅ Use `home-manager generations` to rollback if needed diff --git a/README.md b/README.md new file mode 100644 index 0000000..a271dc3 --- /dev/null +++ b/README.md @@ -0,0 +1,269 @@ +# Portable NixOS Configuration + +A production-ready, modular NixOS + Home Manager setup with automatic disk partitioning, secrets management, and support for both new and existing systems. + +## Features + +- ✅ **Modular**: Configure system and home separately or together +- ✅ **Portable**: Works on new machines, existing NixOS, or non-NixOS (home-manager only) +- ✅ **Auto-partitioning**: Disko handles disk setup automatically +- ✅ **Secrets**: sops-nix for encrypted, portable secrets +- ✅ **Unstable packages**: Mix stable and unstable nixpkgs +- ✅ **Single command**: Deploy entire system with one command + +## Directory Structure + +``` +nix-config/ +├── flake.nix # Main entry point (inputs + outputs) +├── flake.lock # Pinned versions +├── hosts/ # Per-machine configs +│ ├── laptop/default.nix # Machine-specific settings +│ └── server/default.nix +├── nixos/ # Shared NixOS modules +│ ├── default.nix +│ └── modules/ +│ ├── system.nix # User creation, sudo +│ ├── development.nix # Languages, tools +│ └── shell.nix # Shell config +├── home/ # Shared Home Manager modules +│ ├── default.nix +│ └── modules/ +│ ├── shell.nix # Zsh + direnv +│ ├── editor.nix # Neovim/VSCode +│ ├── git.nix # Git config +│ └── dev-tools.nix # tmux, etc +├── secrets/ +│ ├── .sops.yaml # Encryption config +│ └── secrets.yaml # Encrypted secrets +└── README.md +``` + +## Quick Start + +### 1. Initial Setup + +```bash +# Clone repository +git clone nix-config +cd nix-config + +# Generate age keypair (one-time) +age-keygen -o -f ~/.config/sops/age/keys.txt + +# Update .sops.yaml with your public key +age-keygen -y ~/.config/sops/age/keys.txt +# Copy the output and update secrets/.sops.yaml +``` + +### 2. Personalize Your Config + +Edit these files to match your setup: + +**flake.nix:** +- Change `youruser` to your actual username (3 places) + +**hosts/laptop/default.nix:** +- Set `networking.hostName` +- Verify disk device (change `/dev/sda` if needed) + +**home/default.nix & home/modules/git.nix:** +- Set your username and email +- Customize home packages + +**secrets/secrets.yaml:** +- Add your SSH keys, API tokens, passwords + +### 3. Deploy to Existing NixOS + +```bash +# Rebuild the entire system +sudo nixos-rebuild switch --flake .#laptop + +# Or, just update home-manager +home-manager switch --flake .#youruser@linux +``` + +### 4. Deploy to New Machine (ISO Install) + +```bash +# Boot NixOS live ISO, then: +# (Option A) Manual installation +sudo nix run github:nix-community/disko -- --mode zap --flake .#laptop + +# (Option B) Automated with nixos-anywhere (from another machine) +nix run github:nix-community/nixos-anywhere -- --flake .#laptop root@192.168.1.100 + +# (Option C) One-liner installer +nix run .#installer -- laptop +``` + +### 5. Non-NixOS Machine (Home Manager Only) + +```bash +# Install home-manager and apply config +home-manager switch --flake .#youruser@linux + +# Or use the installer script +nix run .#installer -- laptop +``` + +## Usage Patterns + +### Rebuild After Changes + +```bash +# System + home +sudo nixos-rebuild switch --flake .#laptop + +# Just home-manager +home-manager switch --flake .#youruser@linux + +# Dry-run to see what changes +sudo nixos-rebuild test --flake .#laptop +``` + +### Manage Secrets + +```bash +# Edit encrypted secrets (requires age key) +sops secrets/secrets.yaml + +# Reference in NixOS config: +# sops.secrets."ssh/github_key".owner = "youruser"; +# sops.secrets."ssh/github_key".path = "/home/youruser/.ssh/github_key"; + +# Access in shell: +# cat ${config.sops.secrets."ssh/github_key".path} +``` + +### Enable/Disable Features + +Edit host config (e.g., `hosts/laptop/default.nix`): + +```nix +# Enable development tools for specific languages +custom.development.enable = true; +custom.development.languages = [ "rust" "python" "nodejs" ]; + +# Disable specific modules +custom.shell.enable = false; +``` + +### Add New Modules + +Create `nixos/modules/myfeature.nix`: + +```nix +{ config, lib, pkgs, ... }: + +{ + options.custom.myfeature = { + enable = lib.mkEnableOption "My feature"; + }; + + config = lib.mkIf config.custom.myfeature.enable { + # Your config here + }; +} +``` + +Then import in `nixos/default.nix`: +```nix +imports = [ ./modules/myfeature.nix ]; +``` + +### Development Shell + +```bash +# Load dev environment +nix flake show + +# Enter dev shell with all tools +nix develop +``` + +## Multi-Machine Setup + +To support multiple machines: + +1. Create new host: +```bash +mkdir -p hosts/newhost +cp hosts/laptop/default.nix hosts/newhost/default.nix +``` + +2. Edit `flake.nix` and add: +```nix +newhost = nixpkgs.lib.nixosSystem { + inherit system; + specialArgs = { inherit sops-nix disko; pkgs-unstable = pkgs-unstable; }; + modules = [ + overlayUnstable + sops-nix.nixosModules.sops + disko.nixosModules.disko + ./hosts/newhost/default.nix + ./nixos/default.nix + home-manager.nixosModules.home-manager + { home-manager.users.youruser = import ./home/default.nix; } + ]; +}; +``` + +3. Deploy: +```bash +sudo nixos-rebuild switch --flake .#newhost +``` + +## Troubleshooting + +### Secrets decryption fails +```bash +# Check your age key exists +ls ~/.config/sops/age/keys.txt + +# Verify sops config +sops -d secrets/secrets.yaml + +# Regenerate .sops.yaml with your key +age-keygen -y ~/.config/sops/age/keys.txt +``` + +### Disko disk errors +```bash +# List available disks +lsblk + +# Manually run disko (test mode) +sudo nix run github:nix-community/disko -- --mode doit --flake .#laptop +``` + +### Home-manager import errors +```bash +# Check flake validity +nix flake check + +# Validate syntax +nix flake show +``` + +## Resources + +- [NixOS Manual](https://nixos.org/manual/nixos/stable/) +- [Home Manager](https://nix-community.github.io/home-manager/) +- [sops-nix Documentation](https://github.com/mic92/sops-nix) +- [disko](https://github.com/nix-community/disko) +- [Flakes Guide](https://nix.dev/manual/nix/latest/command-ref/new-cli/nix3-flake.html) + +## Tips for Portability + +1. **Keep secrets encrypted**: Always use sops, never commit plain text secrets +2. **Machine-specific overrides**: Use `lib.mkDefault` in shared modules +3. **Conditionally enable features**: Use `options` + `config = mkIf cfg.enable` +4. **Test before deploying**: Use `nixos-rebuild test` or `home-manager build` +5. **Version your flake**: Commit `flake.lock` for reproducibility +6. **Separate concerns**: System settings → nixos/, User env → home/ + +## License + +MIT diff --git a/SETUP.md b/SETUP.md new file mode 100644 index 0000000..1d13a2d --- /dev/null +++ b/SETUP.md @@ -0,0 +1,364 @@ +# Setup Guide - Step by Step + +This guide walks you through setting up your portable NixOS configuration from scratch. + +## Prerequisites + +- **For new NixOS machines**: NixOS ISO boot media +- **For existing NixOS**: SSH access or local terminal +- **For non-NixOS**: curl, bash + +## Phase 1: Initialize Secrets (One-time) + +### Generate Your Age Key + +```bash +# Create age directory +mkdir -p ~/.config/sops/age + +# Generate keypair +age-keygen -o -f ~/.config/sops/age/keys.txt + +# Extract public key +age-keygen -y ~/.config/sops/age/keys.txt +# Output: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +``` + +### Update Encryption Config + +Edit `secrets/.sops.yaml`: + +```yaml +keys: + - &users | + - -----BEGIN AGE PUBLIC KEY----- + age1YOUR_KEY_HERE_FROM_ABOVE + -----END AGE PUBLIC KEY----- +``` + +### Encrypt Your Secrets + +```bash +# First install sops and age +nix shell nixpkgs#sops nixpkgs#age + +# Edit secrets +sops secrets/secrets.yaml + +# Add your SSH keys, API keys, etc. +# File will be encrypted automatically on save +``` + +## Phase 2: Personalize Configuration + +### Step 1: Update flake.nix + +Replace `youruser` with your actual username: + +```bash +sed -i 's/youruser/myusername/g' flake.nix +sed -i 's/youruser/myusername/g' home/default.nix +``` + +### Step 2: Configure Your Laptop Host + +Edit `hosts/laptop/default.nix`: + +```nix +{ + networking.hostName = "mylaptop"; # Change this + + disko.devices = { + disk.main = { + type = "disk"; + device = "/dev/sda"; # Run 'lsblk' to find your disk + + # For NVMe: device = "/dev/nvme0n1"; + # For SATA: device = "/dev/sda"; + # For RAID: add multiple disks + }; + # ... rest stays the same + }; + + # Enable tools you want + custom.development.enable = true; + custom.development.languages = [ "rust" "python" "nodejs" ]; +} +``` + +### Step 3: Customize Home Configuration + +Edit `home/default.nix`: + +```nix +home.username = "myusername"; # Match your username +home.homeDirectory = "/home/myusername"; +``` + +Edit `home/modules/git.nix`: + +```nix +programs.git = { + enable = true; + userName = "Your Real Name"; + userEmail = "you@example.com"; + # ... rest of config +}; +``` + +## Phase 3: Deploy Strategy Based on Your Situation + +### Scenario A: Deploying to Existing NixOS + +```bash +# 1. Clone repo to your home directory +git clone ~/nix-config +cd ~/nix-config + +# 2. Test the configuration (dry-run) +sudo nixos-rebuild test --flake .#laptop + +# 3. If tests pass, apply the configuration +sudo nixos-rebuild switch --flake .#laptop + +# 4. Also apply home-manager +home-manager switch --flake .#myusername@linux +``` + +### Scenario B: Fresh NixOS Installation (with Auto-Partitioning) + +**On a machine running the NixOS ISO:** + +```bash +# 1. Boot NixOS live ISO +# 2. Connect to network (if needed) +# 3. Clone the repo (copy files via USB or git clone) + +nix flake update # Update to latest packages + +# Option 1: Use disko directly +sudo nix run github:nix-community/disko -- \ + --mode zap \ + --flake .#laptop + +# Option 2: Use nixos-anywhere from another machine +nix run github:nix-community/nixos-anywhere -- \ + --flake .#laptop \ + --build-on-remote \ + root@ + +# Option 3: Manual installation +# 1. Partition disk manually: `sudo fdisk /dev/sda` +# 2. Mount partitions: `sudo mount /dev/sda2 /mnt && sudo mount /dev/sda1 /mnt/boot` +# 3. Generate initial config: `sudo nixos-generate-config --root /mnt` +# 4. Copy your flake.nix to /mnt/etc/nixos/flake.nix +# 5. Install: `sudo nixos-install --flake .#laptop` +``` + +### Scenario C: Non-NixOS Machine (Linux/macOS) + +```bash +# 1. Install nix (if not present) +curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | \ + sh -s -- install + +# 2. Clone and apply home-manager +git clone ~/nix-config +cd ~/nix-config + +# 3. Install home-manager +nix run home-manager/release-24.11 -- init --switch + +# 4. Apply your config +home-manager switch --flake .#myusername@linux +``` + +## Phase 4: Verify Everything Works + +```bash +# Check flake validity +nix flake check + +# Inspect what will be built +nix flake show + +# Check secrets decryption (if using sops) +sops -d secrets/secrets.yaml + +# Verify home-manager config +home-manager packages 2>&1 | head -20 + +# Verify NixOS config (on NixOS machines) +sudo nixos-option system.nixos.version +``` + +## Phase 5: Enable Advanced Features (Optional) + +### Using Unstable Packages + +In any module, use unstable versions: + +```nix +# In home/modules/dev-tools.nix +home.packages = with pkgs; [ + stable_package + pkgs-unstable.latest_package +]; +``` + +### Adding Secrets to NixOS Config + +Create `nixos/modules/secrets.nix`: + +```nix +{ config, sops-nix, ... }: + +{ + imports = [ sops-nix.nixosModules.sops ]; + + sops.defaultSopsFile = ./secrets/secrets.yaml; + sops.age.keyFile = "/home/youruser/.config/sops/age/keys.txt"; + + sops.secrets."ssh/github_key" = { + owner = "youruser"; + group = "users"; + mode = "0600"; + }; + + # Use in config: + # environment.variables.GITHUB_SSH_KEY = "${config.sops.secrets."ssh/github_key".path}"; +} +``` + +### Custom Per-Language Development Shells + +Create `.envrc`: + +```bash +use flake + +# Per-project overrides +layout python +``` + +Then: + +```bash +direnv allow +``` + +## Common Customizations + +### Add a New Programming Language + +Edit `hosts/laptop/default.nix`: + +```nix +custom.development.languages = [ "rust" "python" "nodejs" "go" ]; +``` + +Supported: `rust`, `python`, `nodejs`, `go`, `ruby` (in `nixos/modules/development.nix`) + +### Change Default Shell + +Edit `nixos/modules/shell.nix`: + +```nix +custom.shell.defaultShell = "fish"; # or "bash" +``` + +### Add System Packages + +Edit `nixos/default.nix`: + +```nix +environment.systemPackages = with pkgs; [ + # ... existing packages + mynewtool +]; +``` + +### Add User Home Packages + +Edit `home/default.nix`: + +```nix +home.packages = with pkgs; [ + # ... existing packages + mynewtool +]; +``` + +## Rebuilding After Changes + +```bash +# After modifying any config: + +# 1. Check for syntax errors +nix flake check + +# 2. Test without committing +sudo nixos-rebuild test --flake .#laptop + +# 3. If happy, switch to new config +sudo nixos-rebuild switch --flake .#laptop + +# 4. Update lockfile with latest packages +nix flake update + +# 5. Commit changes +git add -A +git commit -m "Update: " +``` + +## Troubleshooting + +### "Bad substituter" errors + +```bash +# Clear cache +nix store gc + +# Update flake +nix flake update + +# Rebuild +sudo nixos-rebuild switch --flake .#laptop +``` + +### Secrets not decrypting + +```bash +# Verify key exists +ls ~/.config/sops/age/keys.txt + +# Check sops can find the key +sops -d secrets/secrets.yaml + +# Verify .sops.yaml has correct key +cat secrets/.sops.yaml +``` + +### Home-manager conflicts with existing config + +```bash +# Move old config +mv ~/.bashrc ~/.bashrc.bak +mv ~/.zshrc ~/.zshrc.bak + +# Apply home-manager +home-manager switch --flake .#myusername@linux + +# Merge manually if needed +cat ~/.bashrc.bak >> ~/.bashrc +``` + +## Next Steps + +1. **Commit to git**: Version your config +2. **Add to GitHub**: Make it portable between machines +3. **Customize modules**: Create your own in `nixos/modules/` +4. **Backup secrets**: Safely store your age key +5. **Document changes**: Update README as you customize + +See README.md for advanced usage patterns. diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..3fb8695 --- /dev/null +++ b/flake.nix @@ -0,0 +1,203 @@ +{ + description = "Portable NixOS + Home Manager configuration with sops secrets and disko"; + + inputs = { + # Core + nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11"; + nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable"; + + # Flakes + flake-utils.url = "github:numtide/flake-utils"; + + # Home Manager + home-manager = { + url = "github:nix-community/home-manager/release-24.11"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + # Secrets management + sops-nix = { + url = "github:mic92/sops-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + # Disk partitioning + disko = { + url = "github:nix-community/disko"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { self, nixpkgs, nixpkgs-unstable, flake-utils, home-manager, sops-nix, disko }: + let + system = "x86_64-linux"; + + pkgs = import nixpkgs { + inherit system; + config.allowUnfree = true; + }; + + pkgs-unstable = import nixpkgs-unstable { + inherit system; + config.allowUnfree = true; + }; + + # Utility to overlay unstable packages + overlayUnstable = final: prev: { + unstable = pkgs-unstable; + }; + + in { + + # ============================================ + # NixOS System Configurations + # ============================================ + + nixosConfigurations = { + + # Example: Laptop configuration + laptop = nixpkgs.lib.nixosSystem { + inherit system; + + specialArgs = { + inherit sops-nix disko; + pkgs-unstable = pkgs-unstable; + }; + + modules = [ + overlayUnstable + sops-nix.nixosModules.sops + disko.nixosModules.disko + + # Machine-specific config + ./hosts/laptop/default.nix + + # Shared system modules + ./nixos/default.nix + + # Home Manager integration + home-manager.nixosModules.home-manager + { + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + home-manager.extraSpecialArgs = { + inherit sops-nix pkgs-unstable; + }; + home-manager.users.youruser = import ./home/default.nix; + } + ]; + }; + + # Example: Server configuration + server = nixpkgs.lib.nixosSystem { + inherit system; + + specialArgs = { + inherit sops-nix disko; + pkgs-unstable = pkgs-unstable; + }; + + modules = [ + overlayUnstable + sops-nix.nixosModules.sops + disko.nixosModules.disko + + ./hosts/server/default.nix + ./nixos/default.nix + + home-manager.nixosModules.home-manager + { + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + home-manager.extraSpecialArgs = { + inherit sops-nix pkgs-unstable; + }; + home-manager.users.youruser = import ./home/default.nix; + } + ]; + }; + }; + + # ============================================ + # Home Manager Standalone (Non-NixOS systems) + # ============================================ + + homeConfigurations = { + "youruser@linux" = home-manager.lib.homeManagerConfiguration { + inherit pkgs; + extraSpecialArgs = { + pkgs-unstable = pkgs-unstable; + sops-nix = sops-nix; + }; + modules = [ + overlayUnstable + ./home/default.nix + ]; + }; + }; + + # ============================================ + # Development Shell + # ============================================ + + devShells.${system}.default = pkgs.mkShell { + buildInputs = with pkgs; [ + nix + nixpkgs-fmt + sops + age + disko + git + ]; + + shellHook = '' + echo "🔧 NixOS Configuration Development Shell" + echo "Available commands:" + echo " - nix flake check # Check flake validity" + echo " - nix flake show # Show all outputs" + echo " - sudo nixos-rebuild switch --flake .#hostname" + echo " - home-manager switch --flake .#youruser@linux" + echo " - sops secrets/secrets.yaml # Edit encrypted secrets" + ''; + }; + + # ============================================ + # Installer Script + # ============================================ + + apps.${system}.installer = { + type = "app"; + program = toString (pkgs.writeShellScript "installer" '' + set -e + + if [ -z "$1" ]; then + echo "Usage: nix run .#installer -- " + echo "Example: nix run .#installer -- laptop" + exit 1 + fi + + HOSTNAME=$1 + + echo "🚀 Bootstrapping NixOS: $HOSTNAME" + + # Check if on NixOS + if [ -f /etc/os-release ]; then + . /etc/os-release + if [ "$ID" = "nixos" ]; then + echo "✓ Running on NixOS" + sudo nixos-rebuild switch --flake ".#$HOSTNAME" + echo "✓ NixOS system configured" + else + echo "⚠ Not on NixOS - installing home-manager only" + home-manager switch --flake ".#youruser@linux" + echo "✓ Home manager configured" + fi + else + echo "⚠ Cannot determine OS" + exit 1 + fi + ''); + }; + + }; +} diff --git a/home/default.nix b/home/default.nix new file mode 100644 index 0000000..da893ef --- /dev/null +++ b/home/default.nix @@ -0,0 +1,48 @@ +{ config, lib, pkgs, pkgs-unstable, ... }: + +{ + imports = [ + ./modules/shell.nix + ./modules/editor.nix + ./modules/git.nix + ./modules/dev-tools.nix + ]; + + # ============================================ + # Home Manager Shared Configuration + # ============================================ + + home.username = "youruser"; + home.homeDirectory = "/home/youruser"; + home.stateVersion = "24.11"; + + # Home-level packages + home.packages = with pkgs; [ + # Utilities + tree + unzip + zip + fzf + bat + exa + tldr + + # Unstable packages (if needed) + # pkgs-unstable.some-package + ]; + + # Environment variables + home.sessionVariables = { + EDITOR = "vim"; + PAGER = "less"; + }; + + # Home Manager should manage itself + programs.home-manager.enable = true; + + # Locale + home.language = { + base = "en_US.UTF-8"; + }; + +} diff --git a/home/modules/dev-tools.nix b/home/modules/dev-tools.nix new file mode 100644 index 0000000..b0f7e0a --- /dev/null +++ b/home/modules/dev-tools.nix @@ -0,0 +1,54 @@ +{ config, lib, pkgs, pkgs-unstable, ... }: + +{ + # Development tools at user level + home.packages = with pkgs; [ + # Debuggers + lldb + gdb + + # Version managers + fnm # Node version manager + pyenv # Python version manager + + # Build tools + cmake + ninja + meson + + # System tools + tmux + htop + iotop + + # Container tools + podman + podman-compose + + # Cloud/Infrastructure + # terraform + # kubectl + # helm + + # Testing + # pytest # Python + # jest # JavaScript (via npm) + ]; + + # tmux configuration (optional) + programs.tmux = { + enable = true; + baseIndex = 1; + newSessionPath = "$HOME"; + shortcut = "a"; + + extraConfig = '' + # Enable mouse + set -g mouse on + + # Vi-like navigation + setw -g mode-keys vi + ''; + }; + +} diff --git a/home/modules/editor.nix b/home/modules/editor.nix new file mode 100644 index 0000000..aa4b6c3 --- /dev/null +++ b/home/modules/editor.nix @@ -0,0 +1,69 @@ +{ config, lib, pkgs, pkgs-unstable, ... }: + +{ + # Neovim as primary editor + programs.neovim = { + enable = true; + defaultEditor = true; + + extraPackages = with pkgs; [ + ripgrep + fd + tree-sitter + ]; + + # Minimal LSP setup - expand as needed + plugins = with pkgs.vimPlugins; [ + # essentials + nvim-lspconfig + nvim-cmp + cmp-nvim-lsp + luasnip + friendly-snippets + + # ui improvements + telescope-nvim + telescope-fzf-native-nvim + lualine-nvim + nvim-web-devicons + nvim-tree-lua + + # treesitter + nvim-treesitter + nvim-treesitter-context + + # git integration + gitsigns-nvim + vim-fugitive + ]; + + # Basic init.lua configuration + extraConfig = '' + lua << EOF + -- Basic settings + vim.opt.number = true + vim.opt.relativenumber = true + vim.opt.expandtab = true + vim.opt.shiftwidth = 2 + vim.opt.tabstop = 2 + vim.opt.smartindent = true + + -- LSP + local lspconfig = require('lspconfig') + + -- Python + lspconfig.pyright.setup{} + + -- Rust + lspconfig.rust_analyzer.setup{} + + -- Node/JavaScript + lspconfig.ts_ls.setup{} + EOF + ''; + }; + + # Alternative: VS Code (uncomment if preferred) + # programs.vscode.enable = true; + +} diff --git a/home/modules/example-template.nix b/home/modules/example-template.nix new file mode 100644 index 0000000..e9c66fa --- /dev/null +++ b/home/modules/example-template.nix @@ -0,0 +1,56 @@ +{ config, lib, pkgs, ... }: + +# Template for creating new Home Manager modules +# Copy this file and customize for your needs + +{ + options.programs.myapp = { + enable = lib.mkEnableOption "My application"; + + setting1 = lib.mkOption { + type = lib.types.str; + default = "default"; + description = "A configuration setting"; + }; + }; + + config = let + cfg = config.programs.myapp; + in lib.mkIf cfg.enable { + + # Home packages needed for this app + home.packages = with pkgs; [ + # myapp + ]; + + # Home Manager built-in programs and services + # Example: configure a program via home-manager + # programs.neovim.enable = true; + + # Create custom files in home directory + # home.file.".config/myapp/config.yaml".source = ./config.yaml; + + # Set environment variables + # home.sessionVariables = { + # MY_VAR = "value"; + # }; + + }; + +} + +# How to use this module: +# +# 1. Save this template as home/modules/myapp.nix +# +# 2. Import it in home/default.nix: +# imports = [ +# ./modules/myapp.nix +# ]; +# +# 3. Enable in home/default.nix: +# programs.myapp.enable = true; +# programs.myapp.setting1 = "custom value"; +# +# 4. Rebuild: +# home-manager switch --flake .#myusername@linux diff --git a/home/modules/git.nix b/home/modules/git.nix new file mode 100644 index 0000000..bfbdc61 --- /dev/null +++ b/home/modules/git.nix @@ -0,0 +1,30 @@ +{ config, lib, pkgs, ... }: + +{ + programs.git = { + enable = true; + userName = "Your Name"; # TODO: Customize + userEmail = "your.email@example.com"; # TODO: Customize + + extraConfig = { + init.defaultBranch = "main"; + pull.rebase = true; + rebase.autoStash = true; + }; + + aliases = { + st = "status"; + co = "checkout"; + br = "branch"; + ci = "commit"; + unstage = "reset HEAD --"; + last = "log -1 HEAD"; + visual = "log --graph --oneline --all"; + }; + }; + + # GPG key signing (optional, uncomment if using) + # programs.gpg.enable = true; + # services.gpg-agent.enable = true; + +} diff --git a/home/modules/shell.nix b/home/modules/shell.nix new file mode 100644 index 0000000..aacf1aa --- /dev/null +++ b/home/modules/shell.nix @@ -0,0 +1,40 @@ +{ config, lib, pkgs, ... }: + +{ + programs.zsh = { + enable = true; + autosuggestion.enable = true; + syntaxHighlighting.enable = true; + + initExtra = '' + # Custom shell initialization + eval "$(direnv hook zsh)" + eval "$(starship init zsh)" + ''; + + shellAliases = { + ls = "exa -l"; + la = "exa -la"; + tree = "exa --tree"; + cat = "bat"; + cd = "z"; + }; + + plugins = [ + { + name = "z"; + src = pkgs.fetchFromGitHub { + owner = "agkozak"; + repo = "zsh-z"; + rev = "v1.12.0"; + sha256 = "sha256-z7YhKUpn6uEEGT1iFSBpUG+w0D1M9YsvvZW8PwDh8T8="; + }; + } + ]; + }; + + programs.starship.enable = true; + programs.direnv.enable = true; + programs.direnv.nix-direnv.enable = true; + +} diff --git a/hosts/laptop/default.nix b/hosts/laptop/default.nix new file mode 100644 index 0000000..5c99a9c --- /dev/null +++ b/hosts/laptop/default.nix @@ -0,0 +1,57 @@ +{ config, lib, pkgs, disko, sops-nix, ... }: + +{ + imports = [ + disko.nixosModules.disko + ]; + + # ============================================ + # Machine-Specific Configuration + # ============================================ + + networking.hostName = "laptop"; + networking.domain = ""; + + # Disko: Auto-partitioning configuration + # Customize for your disk layout (example: single SSD) + disko.devices = { + disk.main = { + type = "disk"; + device = "/dev/sda"; # Change to your disk + content = { + type = "gpt"; + partitions = { + ESP = { + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + root = { + size = "100%"; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + }; + }; + }; + }; + }; + }; + + # Bootloader + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + # Hardware: auto-detect + hardware.enableAllFirmware = true; + + # Enable features specific to development + custom.development.enable = true; + custom.development.languages = [ "rust" "python" "nodejs" ]; + +} diff --git a/hosts/server/default.nix b/hosts/server/default.nix new file mode 100644 index 0000000..c6443d5 --- /dev/null +++ b/hosts/server/default.nix @@ -0,0 +1,53 @@ +{ config, lib, pkgs, disko, sops-nix, ... }: + +{ + imports = [ + disko.nixosModules.disko + ]; + + # ============================================ + # Server-Specific Configuration + # ============================================ + + networking.hostName = "server"; + networking.domain = ""; + + # Disko: Server disk layout (example: mirror for RAID) + disko.devices = { + disk.main = { + type = "disk"; + device = "/dev/sda"; + content = { + type = "gpt"; + partitions = { + ESP = { + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + root = { + size = "100%"; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + }; + }; + }; + }; + }; + }; + + # Bootloader + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + # Minimal development on servers + custom.development.enable = true; + custom.development.languages = [ "python" ]; + +} diff --git a/nixos/default.nix b/nixos/default.nix new file mode 100644 index 0000000..087bfc1 --- /dev/null +++ b/nixos/default.nix @@ -0,0 +1,44 @@ +{ config, lib, pkgs, pkgs-unstable, ... }: + +{ + imports = [ + ./modules/system.nix + ./modules/development.nix + ./modules/shell.nix + ]; + + # ============================================ + # Shared NixOS Configuration + # ============================================ + + # System packages available to all users + environment.systemPackages = with pkgs; [ + git + curl + wget + vim + htop + ]; + + # Nix settings + nix = { + settings = { + experimental-features = [ "nix-command" "flakes" ]; + auto-optimise-store = true; + }; + gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 30d"; + }; + }; + + # System-wide locale + i18n.defaultLocale = "en_US.UTF-8"; + time.timeZone = "UTC"; + + # Networking basics + networking.useDHCP = lib.mkDefault true; + networking.networkmanager.enable = lib.mkDefault false; + +} diff --git a/nixos/modules/development.nix b/nixos/modules/development.nix new file mode 100644 index 0000000..0540cf8 --- /dev/null +++ b/nixos/modules/development.nix @@ -0,0 +1,50 @@ +{ config, lib, pkgs, pkgs-unstable, ... }: + +{ + options.custom.development = { + enable = lib.mkEnableOption "Development tools"; + languages = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Programming languages to install (rust, python, nodejs, go, etc)"; + }; + }; + + config = let + cfg = config.custom.development; + + languagePackages = { + rust = with pkgs; [ rustup cargo-deny cargo-edit ]; + python = with pkgs; [ python3 python3Packages.pip python3Packages.virtualenv ]; + nodejs = with pkgs; [ nodejs npm pnpm ]; + go = with pkgs; [ go golangci-lint ]; + ruby = with pkgs; [ ruby bundler ]; + }; + + selectedPackages = + lib.concatMap (lang: languagePackages.${lang} or []) cfg.languages; + + in lib.mkIf cfg.enable { + + # Core development tools + environment.systemPackages = with pkgs; [ + git + git-lfs + gnumake + pkg-config + gcc + clang + cmake + gdb + ripgrep + fd + jq + yq-go + ] ++ selectedPackages; + + # Enable container support (optional) + virtualisation.docker.enable = true; + virtualisation.docker.enableOnBoot = false; + + }; +} diff --git a/nixos/modules/example-template.nix b/nixos/modules/example-template.nix new file mode 100644 index 0000000..d0afa36 --- /dev/null +++ b/nixos/modules/example-template.nix @@ -0,0 +1,55 @@ +{ config, lib, pkgs, ... }: + +# Template for creating new NixOS modules +# Copy this file and customize for your needs + +{ + options.custom.example = { + enable = lib.mkEnableOption "Example feature"; + + # Add more options as needed + setting1 = lib.mkOption { + type = lib.types.str; + default = "default value"; + description = "Description of setting1"; + }; + + setting2 = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "A list of values"; + }; + }; + + config = let + cfg = config.custom.example; + in lib.mkIf cfg.enable { + + # Your configuration here + environment.systemPackages = with pkgs; [ + # Add packages needed for this feature + ]; + + # Other NixOS configuration + # services.myservice.enable = true; + + }; + +} + +# How to use this module: +# +# 1. Save this template as nixos/modules/myfeature.nix +# +# 2. Import it in nixos/default.nix: +# imports = [ +# ./modules/myfeature.nix +# ]; +# +# 3. Enable in host config (hosts/laptop/default.nix): +# custom.myfeature.enable = true; +# custom.myfeature.setting1 = "my value"; +# custom.myfeature.setting2 = [ "value1" "value2" ]; +# +# 4. Rebuild: +# sudo nixos-rebuild switch --flake .#laptop diff --git a/nixos/modules/secrets-example.nix b/nixos/modules/secrets-example.nix new file mode 100644 index 0000000..e49ea88 --- /dev/null +++ b/nixos/modules/secrets-example.nix @@ -0,0 +1,69 @@ +{ config, lib, pkgs, sops-nix, ... }: + +# Example: How to use sops-nix for secrets management +# This module is NOT imported by default - uncomment in nixos/default.nix to use + +{ + imports = [ sops-nix.nixosModules.sops ]; + + # Point to your encrypted secrets file + sops.defaultSopsFile = ../../../secrets/secrets.yaml; + + # Age key location (sops-nix will decrypt using this) + sops.age.keyFile = "/home/youruser/.config/sops/age/keys.txt"; + + # Define which secrets to decrypt and where + sops.secrets = { + # SSH keys + "ssh/github_key" = { + owner = "youruser"; + group = "users"; + mode = "0600"; + # Decrypted to: /run/secrets/ssh/github_key + }; + + # API keys + "api_keys/example_api" = { + owner = "youruser"; + group = "users"; + mode = "0600"; + }; + + # Passwords (less recommended, use SSH keys when possible) + "passwords/example_password" = { + owner = "youruser"; + group = "users"; + mode = "0600"; + }; + }; + + # Example: Use decrypted secret in environment variable + environment.variables = { + # GITHUB_SSH_KEY = "${config.sops.secrets."ssh/github_key".path}"; + }; + + # Example: Copy secret to user home (for Git, SSH, etc.) + system.activationScripts.installSecrets = lib.stringAfter [ "users" ] '' + mkdir -p /home/youruser/.ssh + cp ${config.sops.secrets."ssh/github_key".path} /home/youruser/.ssh/github + chown youruser:users /home/youruser/.ssh/github + chmod 0600 /home/youruser/.ssh/github + ''; + +} + +# Usage in other modules: +# +# To use decrypted secrets in other config files, reference like: +# ${config.sops.secrets."ssh/github_key".path} +# +# Example in Git config: +# programs.git.extraConfig = { +# core.sshCommand = "ssh -i ${config.sops.secrets."ssh/github_key".path}"; +# }; +# +# Example in home-manager: +# programs.ssh.matchBlocks.github = { +# host = "github.com"; +# identityFile = "${config.sops.secrets."ssh/github_key".path}"; +# }; diff --git a/nixos/modules/shell.nix b/nixos/modules/shell.nix new file mode 100644 index 0000000..c32d133 --- /dev/null +++ b/nixos/modules/shell.nix @@ -0,0 +1,28 @@ +{ config, lib, pkgs, ... }: + +{ + options.custom.shell = { + enable = lib.mkEnableOption "Shell configuration" // { default = true; }; + defaultShell = lib.mkOption { + type = lib.types.str; + default = "zsh"; + description = "Default shell (bash, zsh, fish)"; + }; + }; + + config = let + cfg = config.custom.shell; + in lib.mkIf cfg.enable { + + programs.zsh.enable = cfg.defaultShell == "zsh"; + programs.bash.enable = true; + programs.fish.enable = cfg.defaultShell == "fish"; + + # Common shell packages + environment.systemPackages = with pkgs; [ + starship + direnv + ]; + + }; +} diff --git a/nixos/modules/system.nix b/nixos/modules/system.nix new file mode 100644 index 0000000..e84ec67 --- /dev/null +++ b/nixos/modules/system.nix @@ -0,0 +1,25 @@ +{ config, lib, pkgs, ... }: + +{ + options.custom.system = { + enable = lib.mkEnableOption "Custom system module" // { default = true; }; + }; + + config = lib.mkIf config.custom.system.enable { + # System-wide settings + system.stateVersion = "24.11"; + + # Users + users.users.youruser = { + isNormalUser = true; + extraGroups = [ "wheel" "docker" ]; + shell = pkgs.zsh; + }; + + # Sudo + security.sudo.enable = true; + + # SSH (disabled by default, enable in host config if needed) + services.openssh.enable = lib.mkDefault false; + }; +} diff --git a/secrets/.sops.yaml b/secrets/.sops.yaml new file mode 100644 index 0000000..0d32dd1 --- /dev/null +++ b/secrets/.sops.yaml @@ -0,0 +1,34 @@ +# SOPS configuration for secrets management +# https://github.com/mozilla/sops + +keys: + - &users | + - -----BEGIN AGE PUBLIC KEY----- + Your-Age-Public-Key-Here + -----END AGE PUBLIC KEY----- + + # SSH key-based decryption (recommended for machines) + - &machines | + - -----BEGIN AGE PUBLIC KEY----- + Laptop-Host-Key-Public-Key-Here + -----END AGE PUBLIC KEY----- + +creation_rules: + # Production secrets + - path_regex: ^secrets\.yaml$ + key_groups: + - age: + - *users + - *machines + +# For first-time setup: +# 1. Generate your age keypair: +# age-keygen -o -f ~/.config/sops/age/keys.txt +# +# 2. Extract your public key: +# age-keygen -y ~/.config/sops/age/keys.txt +# +# 3. Replace "Your-Age-Public-Key-Here" with the output +# +# 4. For machine-specific keys, use SSH: +# ssh-keyscan hostname | ssh-to-age -private-key-file ~/.config/sops/age/keys.txt