diff --git a/agents.md b/agents.md deleted file mode 100644 index d255344..0000000 --- a/agents.md +++ /dev/null @@ -1,28 +0,0 @@ -# NixOS Repository Quick Reference - -## Quick Commands -- **Test build**: `nixos-rebuild build --flake .#` -- **List systems**: `nix flake show` -- **Commit**: `git add files && git commit -m "msg"` - -## Systems -- **warp**: Server + nginx + forgejo -- **skip**: Server + nginx only -- **framework/aurora/labrizor**: Desktop systems - -## Key Files -- `flake.nix`: System definitions -- `systems/.nix`: Hardware/boot configs -- `servers/.nix`: Service configs -- `users/.nix`: User configs - -## Testing Workflow -1. Always `git status` first - affects flake evaluation -2. Stage changes (`git add`) before building - prevents Nix store issues -3. Test with `nixos-rebuild build --flake .#` -4. Check success message: `"Done. The new configuration is /nix/store/..."` - -## Important -- Server configs may contain hardcoded credentials - use agenix or systemd credentials for production -- Both warp and skip build successfully -- Repository root: `/home/jsutter/src/nixos` diff --git a/docs/README-unstable and stable packages.md b/docs/README-unstable and stable packages.md new file mode 100755 index 0000000..402d6f9 --- /dev/null +++ b/docs/README-unstable and stable packages.md @@ -0,0 +1,117 @@ +# Hybrid Package Management: Stable + Unstable + +This NixOS configuration uses a hybrid approach where the system runs on the stable NixOS 24.05 branch but can selectively use packages from the unstable branch when needed. + +## How It Works + +The `flake.nix` includes both stable and unstable nixpkgs inputs: + +```nix +inputs = { + nixpkgs.url = "nixpkgs/nixos-24.05"; # Stable base + nixpkgs-unstable.url = "nixpkgs/nixos-unstable"; # Unstable packages + # ... other inputs +}; +``` + +The unstable packages are made available to all system configurations via `specialArgs`: + +```nix +nixosConfigurations = { + framework = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = { + pkgs-unstable = import nixpkgs-unstable { + system = "x86_64-linux"; + config.allowUnfree = true; + }; + }; + modules = [ /* ... */ ]; + }; +}; +``` + +## Using Unstable Packages + +### In System Configuration Files + +To use an unstable package in any `.nix` configuration file: + +1. **Add `pkgs-unstable` to the function parameters:** + ```nix + { config, pkgs, pkgs-unstable, ... }: + ``` + +2. **Use the unstable package:** + ```nix + environment.systemPackages = with pkgs; [ + # Stable packages + firefox + git + + # Unstable packages + pkgs-unstable.windsurf + pkgs-unstable.some-other-package + ]; + ``` + +### Example: Current Usage + +See `desktop/dev.nix` for a working example: + +```nix +{ config, pkgs, pkgs-unstable, ... }: + +{ + environment.systemPackages = with pkgs; [ + # Stable packages + nodejs + rpi-imager + + # Unstable packages + pkgs-unstable.windsurf # Use windsurf from unstable + ]; +} +``` + +## When to Use Unstable Packages + +Use unstable packages when: +- A package is not available in the stable branch +- You need a newer version with specific features or bug fixes +- You're developing with cutting-edge tools + +## Benefits of This Approach + +1. **System Stability**: Core system components use stable, well-tested packages +2. **Package Availability**: Access to the latest packages when needed +3. **Selective Updates**: Choose which packages to get from unstable +4. **Easy Maintenance**: Clear separation between stable and unstable dependencies + +## Adding New Unstable Packages + +To add a new unstable package: + +1. Find the configuration file where you want to add the package +2. Ensure the file accepts `pkgs-unstable` parameter +3. Add `pkgs-unstable.package-name` to the appropriate list +4. Test with `nixos-rebuild dry-run --flake .#framework` +5. Apply with `nixos-rebuild switch --flake .#framework` + +## Updating Packages + +- **Stable packages**: Updated when you update the flake lock +- **Unstable packages**: Updated when you run `nix flake update` + +To update only unstable packages: +```bash +nix flake lock --update-input nixpkgs-unstable +``` + +## Current Unstable Packages in Use + +- `windsurf` - Modern code editor (in `desktop/dev.nix`) + +--- + +This hybrid approach gives you the stability of NixOS stable with the flexibility to use cutting-edge packages when needed. diff --git a/docs/agents.md b/docs/agents.md new file mode 100755 index 0000000..d599dcc --- /dev/null +++ b/docs/agents.md @@ -0,0 +1,1136 @@ +# NixOS Configuration Repository - AI Agent Guide + +This guide provides everything you need to know to work efficiently with this NixOS configuration repository. Keep this file handy when making changes. + +## Repository Overview + +This repository manages NixOS configurations for multiple systems using flakes and Home Manager. All systems are defined declaratively in Nix expressions. + +### Managed Systems + +| Hostname | Type | Hardware | Special Notes | +|----------|------|----------|---------------| +| `framework` | Desktop/Laptop | Framework AMD AI 300 series | User: jsutter, Uses nixos-hardware module | +| `aurora` | Desktop | Custom | Users: jsutter, isutter, aksutter | +| `labrizor` | Desktop | Custom | User: jsutter | +| `skip01` | Server | Custom | Headless, Docker support | +| `warp` | Server | Custom | Minimal headless configuration | + +### Core Technologies + +- **NixOS**: 25.11 (stable channel) +- **Nixpkgs Unstable**: For packages requiring latest versions +- **Home Manager**: Release 25.11 +- **Plasma Manager**: KDE Plasma configuration management +- **Flakes**: For reproducible, declarative system definitions +- **App Flakes**: Standalone flakes for server applications (Immich, Octofriend, etc.) + +## Project Structure + +``` +nixos/ +├── appflakes/ # Standalone flake inputs for server applications +│ ├── immich/ # Self-hosted photo/video backup (Docker Compose) +│ └── octofriend/ # CLI coding assistant +├── desktop/ # Desktop environment configurations +│ ├── plasma.nix # KDE Plasma + Plasma Manager +│ ├── dev.nix # Development tools and languages +│ ├── office.nix # Office applications +│ ├── gaming.nix # Games and gaming platforms +│ ├── media.nix # Audio/video software +│ ├── virtualization.nix # VMs and containers +│ ├── tailscale.nix # VPN configuration +│ ├── 2dprinting.nix # Printer setup +│ ├── 3dprinting.nix # 3D printer tools +│ ├── dnm.nix # Framework-specific config +│ └── stp-elc-udmshare.nix # Specific mount/share config +├── docs/ # Documentation +│ └── agents.md # This file +├── servers/ # Server service modules +│ ├── common.nix # Common server settings (Docker enablement) +│ ├── forgejo.nix # Forgejo Git server module +│ └── hugo.nix # Hugo web server module (Docker compose) +├── systems/ # Hardware-specific configurations +│ ├── common.nix # Shared system settings (bootloader, nix config, etc.) +│ ├── framework.nix # Framework laptop hardware config +│ ├── aurora.nix # Aurora desktop hardware config +│ ├── labrizor.nix # Labrizor desktop hardware config +│ ├── skip01.nix # Skip01 server config +│ └── warp.nix # Warp server config +├── users/ # User configurations with Home Manager +│ ├── common-home.nix # Shared user packages and settings +│ ├── jsutter.nix # Primary user configuration +│ ├── isutter.nix # Secondary user configuration +│ └── aksutter.nix # Secondary user configuration +└── flake.nix # Top-level flake definition +``` + +### App Flakes Architecture + + +The `appflakes/` directory contains standalone flakes for server applications. These are self-contained, reusable flake definitions that can be used independently or integrated into NixOS configurations. + +**Current App Flakes:** +- `immich/`: Self-hosted photo and video backup solution (Docker Compose deployment) +- `octofriend/`: CLI coding assistant packaged for Nix/NixOS + +**App Flake Structure:** +```nix +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + # Additional inputs as needed + }; + + outputs = { self, nixpkgs, flake-utils, ... }: + { + # NixOS module (if applicable) + nixosModules.app-name = nixosModule; + + # Package definition + packages = flake-utils.lib.eachDefaultSystem (system: { ... }); + + # App entry (if CLI tool) + apps.default = ...; + }; +} +``` + +**Using App Flakes:** + +1. **As a local input in main flake.nix:** + ```nix + inputs = { + immich = { url = "path:./appflakes/immich"; }; + }; + + outputs = { self, nixpkgs, immich, ... }: { + nixosConfigurations.server = nixpkgs.lib.nixosSystem { + modules = [ + immich.nixosModules.immich-docker + ./systems/server.nix + ]; + }; + }; + ``` + +2. **Directly on a system:** + ```bash + # Use app flake package on any system + nix run .#appflakes/octofriend + ``` + +### Server Service Modules + +The `servers/` directory contains NixOS modules for server-specific services. These differ from appflakes in that they are modules designed to be included in NixOS configurations rather than standalone flakes. + +**Server Module Pattern:** + +1. **Define options module-wide:** + ```nix + { config, pkgs, lib, ... }: + let + cfg = config.services.service-name; + in { + options.services.service-name = { + enable = mkEnableOption "Service description"; + + domain = mkOption { + type = types.str; + example = "service.example.com"; + description = "Domain name for the service"; + }; + + # Additional options... + }; + } + ``` + +2. **Configure service only if enabled:** + ```nix + config = mkIf cfg.enable { + # Service dependencies (PostgreSQL, Nginx, etc.) + + # Main service configuration + services.service-name = { + enable = true; + settings = { ... }; + }; + + # Reverse proxy configuration (Nginx) + services.nginx.virtualHosts.${cfg.domain} = { ... }; + + # Firewall rules + networking.firewall.allowedTCPPorts = [ ... ]; + + # Backup systemd services + systemd.services.service-name-backup = { ... }; + }; + ``` + +**Common Server Module Elements:** + +- **Database backing:** PostgreSQL (`services.postgresql`) +- **Reverse proxy:** Nginx with SSL/TLS (`services.nginx`) +- **Firewall:** Open required ports (`networking.firewall`) +- **Backups:** Systemd timers for automated backups +- **Logging:** Centralized logging configuration +- **Monitoring:** Optional Prometheus/metrics endpoints +- **Security:** Hardening options, secret management + +**Creating a New Server Module:** + +1. Create `servers/.nix` +2. Follow the standard module pattern with options +3. Use `mkIf cfg.enable` for conditional configuration +4. Include backup systemd service with timer +5. Add firewall rules if service is network-accessible +6. Document required secrets/password files +7. Test on a headless system first (`skip01` or `warp`) + +**Server Module Organization:** + +- `servers/common.nix`: Shared server infrastructure (Docker, etc.) +- `servers/forgejo.nix`: Forgejo Git server complete configuration +- `servers/hugo.nix`: Hugo static site server with Docker compose +- Additional server modules can be added as needed + +**Headless System Configuration:** + +Headless systems (`skip01`, `warp`) follow simplified patterns: + +```nix +{ + networking.hostName = "hostname"; + + # Minimal hardware configuration + boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "ahci" ]; + boot.kernelModules = [ "kvm-intel" ]; + + # Enable container support + virtualisation.docker.enable = true; + + # SSH for remote administration + services.openssh = { + enable = true; + settings.PasswordAuthentication = false; + }; + + # Disable desktop services + services.xserver.enable = false; +} +``` + +**Deploying Server Service Modules:** + +1. Add server module to system configuration: + ```nix + in { + nixosConfigurations.skip01 = nixpkgs.lib.nixosSystem { + modules = [ + ./systems/common.nix + ./servers/forgejo.nix # Add server module + ./systems/skip01.nix + { services.forgejo.enable = true; } + ]; + }; + } + ``` + +2. Configure service options: + ```nix + { + services.forgejo = { + domain = "git.example.com"; + database.passwordFile = "/run/keys/forgejo-db"; + }; + } + ``` + +3. Test on server system: + ```bash + nixos-rebuild dry-run --flake .#skip01 + sudo nixos-rebuild switch --flake .#skip01 + ``` + +**Secrets Management for Servers:** + +Server services often require secrets (database passwords, API keys, OAuth secrets). Store these securely: + +- Use `/run/keys/` for runtime secrets (systemd credentials) +- Use environment files with restricted permissions +- Never commit secrets to the repository +- Example: `passwordFile` options that point to secure paths + +**Backup Strategy for Server Services:** + +Server modules include automated backup services: + +```nix +systemd.services.service-backup = { + description = "Service backup service"; + serviceConfig = { + Type = "oneshot"; + User = "service-user"; + ExecStart = "${pkgs.service}/bin/service backup"; + }; +}; + +systemd.timers.service-backup = { + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = "daily"; + Persistent = true; + }; +}; +``` + +**Testing Server Modules:** + +Always test server modules on headless systems before deploying to production: + +```bash +# Check flake outputs +nix flake show + +# Dry-run for server system +sudo nixos-rebuild dry-run --flake .#server-hostname + +# Build without switching +sudo nixos-rebuild build --flake .#server-hostname + +# Switch to new configuration +sudo nixos-rebuild switch --flake .#server-hostname +``` + +**Monitoring and Maintenance:** + +- Check service status: `systemctl status service-name` +- View logs: `journalctl -u service-name` +- Monitor backup timers: `systemctl list-timers` +- Verify firewall rules: `nft list ruleset` +- Check Docker containers: `docker ps` (if using Docker-based services) + +``` + +## Core Principles + +### 1. Declarative Configuration +- All system state must be defined in Nix expressions +- Never use imperative commands for permanent changes +- Every configuration change should be reproducible + +### 2. Modular Architecture +- Maintain separation between hardware, software, and user configurations +- Use existing modules before creating new ones +- Follow the established directory structure strictly + +### 3. Security First +- Never expose sensitive data (passwords, private keys, API tokens) +- Use proper user privilege separation +- Validate all external inputs and configurations + +## Configuration Patterns + +### Function Parameters + +Always include the appropriate parameters based on what the module needs: + +```nix +# For modules using unstable packages +{ config, pkgs, pkgs-unstable, lib, ... }: + +# For stable-only modules +{ config, pkgs, lib, ... }: + +# For modules using special args from flake +{ config, pkgs, pkgs-unstable, lib, octofriend, ... }: + +# For Home Manager modules +{ pkgs, ... }: +``` + +### System Configuration Pattern + +```nix +{ config, lib, pkgs, ... }: +{ + # Always include hostname first + networking.hostName = "system-name"; + + # Hardware configuration + fileSystems."/" = { + device = "/dev/disk/by-partlabel/primary"; + fsType = "ext4"; + }; + fileSystems."/boot" = { + device = "/dev/disk/by-partlabel/ESP"; + fsType = "vfat"; + }; + + # System-specific settings + # Group related configurations together +} +``` + +### User Configuration Pattern + +```nix +{ config, pkgs, pkgs-unstable, home-manager, ... }: +{ + # System user definition + users.users.username = { + shell = pkgs.zsh; + isNormalUser = true; + description = "User Description"; + extraGroups = [ "networkmanager" "wheel" ]; # Only essential groups + }; + + # Home Manager configuration + home-manager.users.username = { + home.username = "username"; + home.homeDirectory = "/home/username"; + home.stateVersion = "25.05"; + + # User configurations + }; +} +``` + +### Desktop Module Pattern + +```nix +{ config, pkgs, pkgs-unstable, lib, ... }: +{ + # System packages for this category + environment.systemPackages = with pkgs; [ + package1 + package2 + ]; + + # Configuration options + services.service-name.enable = true; + + # Home Manager integrations (if applicable) +} +``` + +## Package Management Guidelines + +### Stable vs Unstable Packages + +```nix +# PREFERRED: Use stable packages by default +environment.systemPackages = with pkgs; [ + firefox + git + vim +]; + +# ACCEPTABLE: Use unstable when necessary +# Add comments explaining why unstable is needed +environment.systemPackages = with pkgs; [ + firefox + pkgs-unstable.windsurf # Latest features not in stable +]; +``` + +### Package Selection Criteria + +1. **Use stable unless**: Package doesn't exist OR needs newer version +2. **Document reasons**: Always comment why unstable is used +3. **Test thoroughly**: Unstable packages may have issues +4. **Review regularly**: Check if unstable packages can move to stable + +### Common Package Sets by Module + +- `dev.nix`: IDEs, languages, development tools +- `office.nix`: LibreOffice, productivity apps +- `gaming.nix`: Steam, Lutris, game launchers +- `media.nix`: Audio/video players, editors +- `virtualization.nix`: VirtualBox, Docker, other virt tools +- `plasma.nix`: KDE Plasma applications and themes + +## System-Specific Information + +### Framework (`framework.nix`) +- Uses `nixos-hardware` module: `framework-amd-ai-300-series` +- Additional modules: `dnm.nix`, `stp-elc-udmshare.nix` +- Single user: jsutter + +### Aurora (`aurora.nix`) +- Multi-user system: jsutter, isutter, aksutter +- Additional modules: `3dprinting.nix`, `2dprinting.nix` +- No specialized hardware module + +### Labrizor (`labrizor.nix`) +- Single user: jsutter +- Additional modules: `3dprinting.nix` +- No specialized hardware module + +### Common Settings (`systems/common.nix`) +Includes: +- Hardware firmware and fwupd +- NetworkManager with VPN plugins (OpenVPN, OpenConnect) +- Systemd-boot EFI bootloader +- Latest kernel +- Nix settings with experimental features (flakes, nix-command) +- Weekly garbage collection (7-day retention) +- Auto-optimized Nix store +- Trusted users: root, jsutter +- Timezone: America/Los_Angeles +- Locale: en_US.UTF-8 +- PipeWire audio stack +- SSH service enabled +- Zsh shell enabled +- Passwordless sudo for wheel group +- Flatpak enabled +- USB plugdev group rules + +### Server Common Settings (`servers/common.nix`) +Includes: +- Docker containerization enabled for server services + +## File Naming Conventions + +- Use lowercase with hyphens: `vpn-config.nix`, `development-tools.nix` +- System configurations must match hostname: `framework.nix`, `aurora.nix` +- User configurations must match username: `jsutter.nix`, `isutter.nix` +- Common configurations: `common.nix`, `common-home.nix` + +## Code Style + +- Use 2-space indentation +- Align attribute lists consistently +- Add comments for non-obvious configurations +- Group related configurations together + +Example: +```nix +{ + # Audio configuration + sound.enable = true; + hardware.pulseaudio.enable = false; + security.rtkit.enable = true; + services.pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + }; +} +``` + +Server module example: +```nix +{ config, pkgs, lib, ... }: + +let + cfg = config.services.example-service; +in { + options.services.example-service = { + enable = mkEnableOption "Example service"; + domain = mkOption { + type = types.str; + example = "service.example.com"; + description = "Domain name for the service"; + }; + port = mkOption { + type = types.port; + default = 8080; + description = "Service port number"; + }; + }; + + config = mkIf cfg.enable { + systemd.services.example-service = { + description = "Example service"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${pkgs.example}/bin/example --port ${toString cfg.port}"; + Restart = "on-failure"; + }; + }; + + services.nginx.virtualHosts.${cfg.domain} = { + forceSSL = true; + enableACME = true; + locations."/".proxyPass = "http://localhost:${toString cfg.port}"; + }; + + networking.firewall.allowedTCPPorts = [ 80 443 ]; + }; +} +``` + +## Common Workflows + +### Adding a New Package + +1. Determine appropriate module (desktop/, systems/, users/) +2. Check if package exists in stable channel: `nix search nixpkgs package-name` +3. Use unstable only if necessary with documentation +4. Add to appropriate environment.systemPackages or home.packages +5. Run dry-run before applying +6. Update relevant documentation if it affects multiple systems + +Example: +```nix +# In desktop/dev.nix +environment.systemPackages = with pkgs; [ + # Added for Python development + python312 + python312Packages.pip + pkgs-unstable.windsurf # Latest AI features not in stable +]; +``` + +### Creating a New Desktop Module + +1. Create file in `desktop/` with descriptive name +2. Include proper function parameters +3. Add packages, services, and configurations +4. Test module independently +5. Add to `commonDesktopModules` in flake.nix if for all desktops +6. Add to specific system in flake.nix if selective + +### Adding a New System + +1. Create `systems/.nix` following existing patterns +2. Set `networking.hostName = ""` +3. Configure hardware (fileSystems, hardware-specific settings) +4. Add system entry to `flake.nix`: +```nix +new-system = mkSystem { + modules = commonDesktopModules ++ [ + ./systems/new-system.nix + ./users/username.nix + ]; +}; +``` +5. Test with dry-run and build + +### Modifying User Configuration + +1. Edit appropriate file in `users/` +2. For shared changes: modify `common-home.nix` +3. For user-specific changes: modify `.nix` +4. Home Manager configuration goes in `home-manager.users.` + +### Creating a New Server Module + +1. Create `servers/.nix` following the module pattern +2. Define options using `mkOption` for all configurable parameters +3. Use `mkIf cfg.enable` to wrap all configuration +4. Include database, reverse proxy (Nginx), and firewall configuration +5. Add automated backup systemd service with timer +6. Document required secrets (passwordFile paths, API keys) +7. Test on headless system first + +### Creating a New App Flake + +1. Create `appflakes//` directory with `flake.nix` +2. Include `nixpkgs` and `flake-utils` as inputs +3. Define outputs with `packages` (and optionally `nixosModules`, `apps`) +4. Use `flake-utils.lib.eachDefaultSystem` for multi-system support +5. Add local input reference in main `flake.nix` if needed +6. Test build with `nix build .#appflakes/` + +### Adding a Server Service to a System + +1. Choose target system (typically headless: `skip01` or `warp`) +2. Add server module to system's modules list in `flake.nix`: +```nix +nixosConfigurations.server = mkSystem { + modules = [ + ./systems/common.nix + ./servers/common.nix + ./servers/service-name.nix + ./systems/server.nix + { services.service-name.enable = true; } + ]; +}; +``` +3. Configure service-specific options in host config or separate file +4. Set up secret files (e.g., `/run/keys/service-db`) +5. Run dry-run and test before switching + +## Testing and Validation + +### Pre-commit Testing + +ALWAYS run these commands before submitting changes: + +```bash +# 1. Syntax check +nix flake check + +# 2. Dry run for affected systems (run for ALL affected) +sudo nixos-rebuild dry-run --flake .#framework +sudo nixos-rebuild dry-run --flake .#aurora +sudo nixos-rebuild dry-run --flake .#labrizor + +# 3. Check flake outputs +nix flake show + +# For server configurations, also test: +sudo nixos-rebuild dry-run --flake .#skip01 +sudo nixos-rebuild dry-run --flake .#warp +``` + +### Applying Changes + +```bash +# Build and switch (active system only) +sudo nixos-rebuild switch --flake .#hostname + +# Build only (test without switching) +sudo nixos-rebuild build --flake .#hostname + +# Build and boot (adds to GRUB menu) +sudo nixos-rebuild boot --flake .#hostname +``` + +### Build Verification + +- Test on at least one system before merging +- Verify all services start correctly: `systemctl status` +- Check for package conflicts +- Validate hardware-specific configurations +- For server modules: verify Docker containers run, check systemd timers, validate firewall rules + +### Updating Packages + +```bash +# Update flake inputs +nix flake update + +# Check what changed +nix flake diff + +# Rebuild after update +sudo nixos-rebuild switch --flake .#hostname +``` + +## Security Rules + +### Sensitive Data Handling + +- **NEVER** commit plaintext passwords +- **NEVER** commit private SSH keys +- **NEVER** commit API tokens or secrets +- **ALWAYS** use hashed passwords: `hashedPassword = "$6$..."` +- **CONSIDER** using sops-nix for advanced secret management + +### User Privilege Management + +```nix +# GOOD: Minimal necessary groups +extraGroups = [ "networkmanager" "wheel" "audio" ]; + +# BAD: Over-privileged users +extraGroups = [ "networkmanager" "wheel" "audio" "video" "input" "disk" "lp" "scanner" ]; +``` + +### SSH Key Management + +```nix +# GOOD: Use authorizedKeys for SSH access +openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBNVUh+RrcOSMRV6qysnsdPs5AyK8dSm4QhhnwgpikyI user@domain" +]; + +# FORBIDDEN: Never include private keys +``` + +## Rollback Procedures + +### Configuration Rollback + +```bash +# List available generations +sudo nix-env --list-generations --profile /nix/var/nix/profiles/system + +# Rollback to previous working generation +sudo nixos-rebuild switch --profile-name generation-123 + +# Or use rollback shortcut +sudo nixos-rebuild switch --rollback + +# Rollback specific system +sudo nixos-rebuild switch --rollback --flake .#hostname +``` + +### Emergency System Recovery + +If a system fails to boot after changes: + +1. Boot from installation media +2. Mount root filesystem: `mount /dev/disk/by-partlabel/primary /mnt` +3. Roll back: `sudo nixos-rebuild switch --rollback --install-bootloader /mnt` +4. Identify and fix configuration issues +5. Test before rebooting + +### Booting into Previous Generations + +At boot time (GRUB menu): +1. Hold Shift during boot to see GRUB menu +2. Select "Advanced options for NixOS" +3. Choose previous generation + +## NixOS Installation (New System) + +```bash +# Partition disk (example for NVMe) +sudo parted /dev/nvme0n1 -- mklabel gpt +sudo parted /dev/nvme0n1 -- mkpart primary ext4 512MB 100% +sudo parted /dev/nvme0n1 -- mkpart ESP fat32 1MB 512MB +sudo parted /dev/nvme0n1 -- set 2 esp on +sudo mkfs.ext4 /dev/disk/by-partlabel/primary +sudo mkfs.vfat /dev/disk/by-partlabel/ESP + +# Mount filesystems +sudo mount -o rw /dev/disk/by-partlabel/primary /mnt/ +sudo mkdir /mnt/boot +sudo mount -o rw /dev/disk/by-partlabel/ESP /mnt/boot/ +sudo mkdir /mnt/root +sudo git clone https://git.symbiotrip.com/jsutter/nixos /mnt/root/nixos + +# Install (no root password, impure for git access) +sudo -i +cd /mnt/root/nixos +nixos-install --flake .# --no-root-password --impure + +# Set password after install +nixos-enter --root '/mnt' +passwd jsutter +``` + +## Module Dependencies + +### Known Dependencies + +- `plasma.nix` depends on: `common.nix`, `home-manager` +- `dev.nix` is included in all desktop systems +- All desktop systems include: `common.nix`, `plasma.nix`, `dev.nix`, `office.nix`, `gaming.nix`, `media.nix`, `virtualization.nix`, `tailscale.nix` +- User files include Home Manager configuration + +### Avoiding Circular Dependencies + +- Don't import system modules into user modules +- Use `common.nix` for shared system settings only +- Use `common-home.nix` for shared user settings only +- Hardware-specific modules should not depend on desktop modules + +## Emergency Tools + +### Useful Commands + +```bash +# Check what packages provide a command +nix-locate bin/commandname + +# Search for packages +nix search nixpkgs package-name +nix search nixpkgs-unstable package-name + +# Check Nix store size +du -sh /nix/store + +# Garbage collect manually +sudo nix-collect-garbage -d + +# Profile Nix operations +sudo nix-env --profile /nix/var/nix/profiles/system --list-generations + +# Check hardware info +lshw +lspci +lsusb +lsblk +hwinfo +``` + +## Troubleshooting Common Issues + +### Build Errors + +1. Read the error message carefully +2. Check for syntax errors in the modified file +3. Verify all attributes are closed properly +4. Run `nix flake check` to validate syntax + +### Service Failures + +```bash +# Check service status +systemctl status service-name + +# View service logs +journalctl -u service-name -e + +# Restart service +systemctl restart service-name +``` + +### Package Conflicts + +- If two modules try to enable the same service with different settings +- Use `lib.mkForce` to override settings if necessary +- Or consolidate the configuration in one place + +## Flakes Reference + +### Input Structure + +```nix +inputs = { + nixpkgs.url = "nixpkgs/nixos-25.11"; # Stable + nixpkgs-unstable.url = "nixpkgs/nixos-unstable"; # Unstable + nixos-hardware.url = "github:NixOS/nixos-hardware/master"; + home-manager.url = "github:nix-community/home-manager/release-25.11"; + plasma-manager.url = "github:nix-community/plasma-manager"; + octofriend.url = "path:./appflakes/octofriend"; # Local flake +}; +``` + +### Special Args + +Available in all modules: +- `pkgs`: Stable Nix packages +- `pkgs-unstable`: Unstable Nix packages +- `octofriend`: Local octofriend flake + +### Output Structure + +```nix +outputs = { + self, # Self reference + nixpkgs, # Stable packages + nixpkgs-unstable, # Unstable packages + nixos-hardware, # Hardware modules + home-manager, # Home Manager + plasma-manager, # Plasma Manager + octofriend # Custom app flake +}: { + nixosConfigurations = { + framework = { ... }; # Define each system + aurora = { ... }; + labrizor = { ... }; + }; +}; +``` + +## Documentation Requirements + +### Code Comments + +- Explain non-obvious configurations +- Document reasons for unstable package usage +- Note hardware-specific requirements +- Reference external dependencies + +Example: +```nix +# Use unstable neovim for LuaLS integration not in stable +pkgs-unstable.neovim # Latest features needed for Lua development +``` + +### Commit Messages + +Use clear, descriptive commit messages: +- Reference affected systems/modules +- Explain reasoning for significant changes +- Include testing steps when applicable + +Example: +``` +feat(framework): Add 3D printing support for Prusa printers + +- Added 3dprinting.nix module with PrusaSlicer and Cura +- Installed USB rules for Prusa devices +- Added to framework system configuration + +Tested: Prusa MK4 recognized and can start print via USB +``` + +## Performance Considerations + +### Nix Settings + +The repository uses optimized Nix settings: +- `auto-optimise-store`: Auto-optimizes the Nix store +- `keep-outputs = true`: Keeps build outputs +- `keep-derivations = true`: Keeps derivations for evaluation +- `download-buffer-size`: 512MB for faster downloads + +### Garbage Collection + +Automatically runs weekly: +- Deletes builds older than 7 days +- Run manually: `sudo nix-collect-garbage -d` + +### Build Caching + +Consider using `nix-serve` or Cachix for: +- Faster rebuilds +- Shared cache across systems +- CI/CD integration + +## Resources + +### Official Documentation +- [NixOS Manual](https://nixos.org/manual/nixos/stable/) +- [Home Manager Manual](https://nix-community.github.io/home-manager/) +- [Nix Pills](https://nixos.org/guides/nix-pills/) +- [NixOS Wiki](https://nixos.wiki/) + +### Community Resources +- [NixOS Discourse](https://discourse.nixos.org/) +- [NixOS subreddit](https://reddit.com/r/NixOS/) +- [NixOS Matrix](https://matrix.to/#/#nixos:nixos.org) + +### Package Search +- [search.nixos.org](https://search.nixos.org/packages) +- Command line: `nix search nixpkgs package-name` + +## Quick Reference + +### Essential Commands + +| Action | Command | +|--------|---------| +| Update system | `sudo nixos-rebuild switch --flake .#hostname` | +| Dry run | `sudo nixos-rebuild dry-run --flake .#hostname` | +| Rollback | `sudo nixos-rebuild switch --rollback` | +| Update flakes | `nix flake update` | +| Check flakes | `nix flake check` | +| Search packages | `nix search nixpkgs name` | +| Garbage collect | `sudo nix-collect-garbage -d` | + +**Server-Specific Commands:** +| Action | Command | +|--------|---------| +| Check service status | `systemctl status service-name` | +| View service logs | `journalctl -u service-name` | +| List active timers | `systemctl list-timers` | +| Check Docker containers | `docker ps` | +| View Docker logs | `docker logs container-name` | +| Restart docker-compose stack | `docker-compose -f /etc/compose/service/docker-compose.yml restart` | +| Check firewall rules | `nft list ruleset` | +| Verify SSL certificates | `certbot certificates` | +| List backup directory | `ls -lh /var/backups/service-name` | +| Run manual backup | `systemctl start service-backup` | + +### File Paths Reference + +| Type | Location | +|------|----------| +| Common system settings | `systems/common.nix` | +| System hardware config | `systems/.nix` | +| Common user settings | `users/common-home.nix` | +| User config | `users/.nix` | +| Desktop apps | `desktop/.nix` | +| Server common settings | `servers/common.nix` | +| Server service modules | `servers/.nix` | +| App flakes | `appflakes//flake.nix` | +| Docker compose configs | `/etc/compose//docker-compose.yml` | +| Backup directories | `/var/backups//` | +| Runtime secrets | `/run/keys/` | +| Flake definition | `flake.nix` | + +## Maintenance & Changelog + +This section tracks changes to the repository structure and when this document was updated. Keep this in sync! + +### Current Repository State +- **Last Updated**: February 2026 +- **NixOS Version**: 25.11 +- **Managed Systems**: 5 (framework, aurora, labrizor, skip01, warp) +- **Users**: jsutter (primary), isutter, aksutter +- **App Flakes**: 2 (immich, octofriend) +- **Server Modules**: 3 (common, forgejo, hugo) + +### Repository Change Log + +| Date | Change | Updated Sections | +|------|--------|------------------| +| 2026-02 - Created | Created `agents.md` with comprehensive guide | All sections | +| 2026-02 - Removed | Removed .clinerules file, consolidated into agents.md | Maintenance section | +| 2026-02 - Cleanup | Removed unused gnome.nix module, common-headless.nix; removed allowBroken setting | System structure | +| 2026-02 - Cleanup | Removed commented packages across multiple files; fixed trailing whitespace | Code quality | +| 2026-02 - Cleanup | Removed .clinerules file; deleted gnome.nix (unused); common-headless.nix (duplicated) | File structure | +| 2026-02 - Improvement | Added result, *.swp, *~ to .gitignore | Maintenance | +| 2026-02 - Added | Added appflakes directory (immich, octofriend) and servers directory (forgejo, hugo) | Project structure, all server sections | +| 2026-02 - Documentation | Added comprehensive server module patterns, appflake architecture, server workflows, server-specific commands | Repository Overview, Workflows, Quick Reference | + +### When to Update This Document + +Update `agents.md` when any of the following occur: + +- **Structural Changes**: + - New system added to `flake.nix` + - New user configuration added + - New or renamed desktop module + - Directory restructuring + - New app flake added to `appflakes/` + - New server module added to `servers/` + +- **Configuration Changes**: + - New shared settings in `systems/common.nix` + - New shared user settings in `users/common-home.nix` + - New shared settings in `servers/common.nix` + - Changes to module pattern or function parameters + - New package categories or organizational changes + - Changes to server module standard pattern + - Updates to headless system configuration patterns + +- **Technology Updates**: + - NixOS version changes + - Channel updates (stable/unstable) + - New major inputs added to flake + - Significant Nix configuration changes + - New app flake with different architecture + - Changes to Docker/compose deployment patterns + +- **Procedure Changes**: + - New testing workflow + - Changed emergency procedures + - Updated installation steps + - New common commands + - New server deployment or backup procedures + - Changes to secrets management approach for servers + +- **Server Changes**: + - New server service added to production + - Changes to backup strategy for server services + - Updates to monitoring or logging for servers + - New headless system deployed or configured + - Security hardening changes for server modules + +### Update Template + +When making changes, add an entry using this format: + +``` +| YYYY-MM - One-line description | More detail if needed | Section(s) affected | +| --- | --- | --- | +``` + +### Version History for agents.md + +- **v1.1** (2026-02): Added comprehensive server module patterns, appflake architecture, server workflows, and server-specific commands +- **v1.0** (2025-01): Initial creation with full repository documentation + +## Getting Help + +When unsure about something: +1. Check this documentation first +2. Review existing similar configurations +3. Search NixOS manual and wiki +4. Test changes with dry-run before applying + +--- + +**Remember**: This repository values declarative, reproducible configurations. When in doubt, prefer explicit configuration over implicit behavior. Test thoroughly, document changes, and never skip the dry-run step! \ No newline at end of file diff --git a/flake.nix b/flake.nix index 8f5fbd6..280dde0 100755 --- a/flake.nix +++ b/flake.nix @@ -85,17 +85,9 @@ ./systems/common.nix ./users/jsutter.nix ./systems/warp.nix - ./servers/nginx.nix ./servers/forgejo.nix ]; }; - skip = mkSystem { - modules = [ - ./systems/common.nix - ./users/jsutter.nix - ./systems/skip.nix - ]; - }; }; }; } diff --git a/servers/forgejo.nix b/servers/forgejo.nix index 24c485a..e8bd8f5 100755 --- a/servers/forgejo.nix +++ b/servers/forgejo.nix @@ -12,50 +12,25 @@ let adminUser = "jsutter"; adminEmail = "jsutter@symbiotrip.com"; + in { - # DNS-based ACME certificate configuration - # Uses defaults (dnsProvider, email, credentials) from nginx.nix - security.acme.certs.${fqdn} = { - # Group needs to be set so nginx can read the certificate - group = config.services.nginx.group; - - # Inherit DNS challenge configuration from security.acme.defaults (set in nginx.nix) - # This includes: dnsProvider = "cloudflare", environmentFile with Cloudflare token, email - - # Explicitly ensure DNS mode (not HTTP-01) - webroot = null; - }; - - # Nginx virtual host for Forgejo + security.acme.certs.${fqdn}.group = config.services.nginx.group; services.nginx.virtualHosts.${fqdn} = { - # CRITICAL FIX: Don't set enableACME = true - # That would create an HTTP-01 challenge handler, which conflicts with DNS challenge - # Instead, we use useACMEHost to reference the DNS-obtained certificate - enableACME = false; # Disable automatic ACME for this vhost - useACMEHost = fqdn; # Use the certificate obtained via DNS challenge - forceSSL = true; - - # acmeRoot is not needed/used with DNS challenge method - # acmeRoot = null; # Removed - implicit with enableACME = false - + enableACME = true; + useACMEHost = fqdn; + acmeRoot = null; extraConfig = '' client_max_body_size 512M; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - - # Logging for debugging - access_log /var/log/nginx/${fqdn}-access.log; - error_log /var/log/nginx/${fqdn}-error.log warn; ''; - locations."/".proxyPass = "http://localhost:${toString srv.HTTP_PORT}"; }; - # Forgejo service configuration services.forgejo = { enable = true; database.type = "postgres"; @@ -66,8 +41,6 @@ in DOMAIN = fqdn; ROOT_URL = "https://${fqdn}/"; HTTP_PORT = 3000; - # Bind to localhost only - nginx handles public HTTPS - LOCAL_ROOT_URL = "http://localhost:3000/"; }; service.DISABLE_REGISTRATION = true; @@ -87,13 +60,7 @@ in }; }; - # Ensure nginx starts after ACME certificate is available - systemd.services.nginx = { - after = [ "acme-${fqdn}.service" "acme-${fqdn}-renew.service" ]; - requires = [ "acme-${fqdn}.service" ]; - }; - - # Create/ensure admin user on startup + # Create/ensure admin user systemd.services.forgejo.preStart = let adminCmd = "${lib.getExe cfg.package} admin user"; in '' @@ -105,10 +72,9 @@ in --must-change-password=false || true ''; - # Enable Docker for Forgejo Actions runner + # Actions runner (runs jobs in Docker containers per labels) virtualisation.docker.enable = true; - # Configure Forgejo Actions runner services.gitea-actions-runner = { package = pkgs.forgejo-runner; instances.default = { diff --git a/servers/nginx.nix b/servers/nginx.nix index 47927cc..d76e7c9 100644 --- a/servers/nginx.nix +++ b/servers/nginx.nix @@ -1,9 +1,8 @@ { config, lib, pkgs, ... }: let # WARNING: this ends up world-readable in the Nix store if you inline it. - # For production, use agenix or pass through systemd credentials cloudflareEnv = pkgs.writeText "cloudflare-acme.env" '' - CLOUDFLARE_DNS_API_TOKEN=umnyPSYOr9U3m404_IBMl4PTOzg29nz_XzNEGw2v + umnyPSYOr9U3m404_IBMl4PTOzg29nz_XzNEGw2v ''; in { diff --git a/systems/skip.nix b/systems/skip.nix deleted file mode 100755 index deb8e98..0000000 --- a/systems/skip.nix +++ /dev/null @@ -1,78 +0,0 @@ -{ config, lib, pkgs, modulesPath, ... }: { - networking.hostName = "skip"; - - fileSystems."/" = - { device = "/dev/disk/by-partlabel/primary"; - fsType = "ext4"; - }; - fileSystems."/boot" = - { device = "/dev/disk/by-partlabel/ESP"; - fsType = "vfat"; - }; - - # CPU Settings for 13th gen Intel Core i5 - hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; - - # Boot and kernel modules for Intel NUC - boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usb_storage" "sd_mod" ]; - boot.initrd.kernelModules = [ ]; # No graphics drivers needed for headless - boot.kernelModules = [ "kvm-intel" ]; # Intel virtualization support - boot.extraModulePackages = []; - - # Server-specific kernel parameters - boot.kernelParams = [ - "intel_iommu=on" # Enable IOMMU for virtualization - ]; - - networking.useDHCP = lib.mkDefault true; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - - # Power management optimized for server use - powerManagement = { - enable = true; - cpuFreqGovernor = "ondemand"; - }; - - # Thermal management - services.thermald.enable = true; - - # Server-oriented settings - services.openssh = { - enable = true; - settings = { - PasswordAuthentication = false; - KbdInteractiveAuthentication = false; - PermitRootLogin = "no"; - }; - }; - - # Swap configuration (smaller for server use) - swapDevices = [ - { - device = "/swapfile"; - size = 8192; # 8GB swap for server workload - priority = 0; - } - ]; - - # Enable hardware monitoring (CLI only) - hardware.sensor.iio.enable = true; - - # Network performance tuning for server use - boot.kernel.sysctl = { - "net.core.rmem_max" = 134217728; - "net.core.wmem_max" = 134217728; - "net.ipv4.tcp_rmem" = "4096 65536 134217728"; - "net.ipv4.tcp_wmem" = "4096 65536 134217728"; - "net.core.netdev_max_backlog" = 5000; - }; - - # Disable unnecessary services for server use - services.xserver.enable = lib.mkForce false; - services.pipewire.enable = lib.mkForce false; - - # Enable container support for future server services - virtualisation.docker.enable = true; - virtualisation.podman.enable = lib.mkDefault true; -} diff --git a/systems/warp.nix b/systems/warp.nix index 6d3b210..c241292 100755 --- a/systems/warp.nix +++ b/systems/warp.nix @@ -26,8 +26,6 @@ networking.useDHCP = lib.mkDefault true; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; # Power management optimized for server use