Files
nixos-servers/scripts/create-host/README.md
Torjus Håkestad 83de9a3ffb
Some checks failed
Run nix flake check / flake-check (push) Has been cancelled
pipeline: add testing improvements for branch-based workflows
Implement dual improvements to enable efficient testing of pipeline changes
without polluting master branch:

1. Add --force flag to create-host script
   - Skip hostname/IP uniqueness validation
   - Overwrite existing host configurations
   - Update entries in flake.nix and terraform/vms.tf (no duplicates)
   - Useful for iterating on configurations during testing

2. Add branch support to bootstrap mechanism
   - Bootstrap service reads NIXOS_FLAKE_BRANCH environment variable
   - Defaults to master if not set
   - Uses branch in git URL via ?ref= parameter
   - Service loads environment from /etc/environment

3. Add cloud-init disk support for branch configuration
   - VMs can specify flake_branch field in terraform/vms.tf
   - Automatically generates cloud-init snippet setting NIXOS_FLAKE_BRANCH
   - Uploads snippet to Proxmox via SSH
   - Production VMs omit flake_branch and use master

4. Update documentation
   - Document --force flag usage in create-host README
   - Add branch testing examples in terraform README
   - Update TODO.md with testing workflow
   - Add .generated/ to gitignore

Testing workflow: Create feature branch, set flake_branch in VM definition,
deploy with terraform, iterate with --force flag, clean up before merging.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-01 16:34:28 +01:00

6.9 KiB

NixOS Host Configuration Generator

Automated tool for generating NixOS host configurations, flake.nix entries, and Terraform VM definitions for homelab infrastructure.

Installation

The tool is available in the Nix development shell:

nix develop

Usage

Basic Usage

Create a new host with DHCP networking:

python -m scripts.create_host.create_host create --hostname test01

Create a new host with static IP:

python -m scripts.create_host.create_host create \
  --hostname test01 \
  --ip 10.69.13.50/24

Create a host with custom resources:

python -m scripts.create_host.create_host create \
  --hostname bighost01 \
  --ip 10.69.13.51/24 \
  --cpu 8 \
  --memory 8192 \
  --disk 100G

Dry Run Mode

Preview what would be created without making changes:

python -m scripts.create_host.create_host create \
  --hostname test01 \
  --ip 10.69.13.50/24 \
  --dry-run

Force Mode (Regenerate Existing Configuration)

Overwrite an existing host configuration (useful for testing):

python -m scripts.create_host.create_host create \
  --hostname test01 \
  --ip 10.69.13.50/24 \
  --force

This mode:

  • Skips hostname and IP uniqueness validation
  • Overwrites files in hosts/<hostname>/
  • Updates existing entries in flake.nix and terraform/vms.tf (doesn't duplicate)
  • Useful for iterating on configuration templates during testing

Options

  • --hostname (required): Hostname for the new host

    • Must be lowercase alphanumeric with hyphens
    • Must be unique (not already exist in repository)
  • --ip (optional): Static IP address with CIDR notation

    • Format: 10.69.13.X/24
    • Must be in 10.69.13.0/24 subnet
    • Last octet must be 1-254
    • Omit this option for DHCP configuration
  • --cpu (optional, default: 2): Number of CPU cores

    • Must be at least 1
  • --memory (optional, default: 2048): Memory in MB

    • Must be at least 512
  • --disk (optional, default: "20G"): Disk size

    • Examples: "20G", "50G", "100G"
  • --dry-run (flag): Preview changes without creating files

  • --force (flag): Overwrite existing host configuration

    • Skips uniqueness validation
    • Updates existing entries instead of creating duplicates

What It Does

The tool performs the following actions:

  1. Validates the configuration:

    • Hostname format (RFC 1123 compliance)
    • Hostname uniqueness
    • IP address format and subnet (if provided)
    • IP address uniqueness (if provided)
  2. Generates host configuration files:

    • hosts/<hostname>/default.nix - Import wrapper
    • hosts/<hostname>/configuration.nix - Full host configuration
  3. Updates repository files:

    • flake.nix - Adds new nixosConfigurations entry
    • terraform/vms.tf - Adds new VM definition
  4. Displays next steps for:

    • Reviewing changes with git diff
    • Verifying NixOS configuration
    • Verifying Terraform configuration
    • Committing changes
    • Deploying the VM

Generated Configuration

Host Features

All generated hosts include:

  • Full system imports from ../../system:

    • Nix binary cache integration
    • SSH with root login
    • SOPS secrets management
    • Internal ACME CA integration
    • Daily auto-upgrades with auto-reboot
    • Prometheus node-exporter
    • Promtail logging to monitoring01
  • VM guest agent from ../../common/vm

  • Hardware configuration from ../template/hardware-configuration.nix

Networking

Static IP mode (when --ip is provided):

systemd.network.networks."ens18" = {
  matchConfig.Name = "ens18";
  address = [ "10.69.13.50/24" ];
  routes = [ { Gateway = "10.69.13.1"; } ];
  linkConfig.RequiredForOnline = "routable";
};

DHCP mode (when --ip is omitted):

systemd.network.networks."ens18" = {
  matchConfig.Name = "ens18";
  networkConfig.DHCP = "ipv4";
  linkConfig.RequiredForOnline = "routable";
};

DNS Configuration

All hosts are configured with:

  • DNS servers: 10.69.13.5, 10.69.13.6 (ns1, ns2)
  • Domain: home.2rjus.net

Examples

Create a test VM with defaults

python -m scripts.create_host.create_host create --hostname test99

This creates a DHCP VM with 2 CPU cores, 2048 MB memory, and 20G disk.

Create a database server with static IP

python -m scripts.create_host.create_host create \
  --hostname pgdb2 \
  --ip 10.69.13.52/24 \
  --cpu 4 \
  --memory 4096 \
  --disk 50G

Preview changes before creating

python -m scripts.create_host.create_host create \
  --hostname test99 \
  --ip 10.69.13.99/24 \
  --dry-run

Error Handling

The tool validates input and provides clear error messages for:

  • Invalid hostname format (must be lowercase alphanumeric with hyphens)
  • Duplicate hostname (already exists in repository)
  • Invalid IP format (must be X.X.X.X/24)
  • Wrong subnet (must be 10.69.13.0/24)
  • Invalid last octet (must be 1-254)
  • Duplicate IP address (already in use)
  • Resource constraints (CPU < 1, memory < 512 MB)

Integration with Deployment Pipeline

This tool implements Phase 2 of the automated deployment pipeline:

  1. Phase 1: Template building ✓ (build-and-deploy-template.yml)
  2. Phase 2: Host configuration generation ✓ (this tool)
  3. Phase 3: Bootstrap automation (planned)
  4. Phase 4: Secrets management (planned)
  5. Phase 5: DNS automation (planned)
  6. Phase 6: Full integration (planned)

Development

Project Structure

scripts/create-host/
├── create_host.py          # Main CLI entry point (typer app)
├── __init__.py            # Package initialization
├── validators.py          # Validation logic
├── generators.py          # File generation using Jinja2
├── manipulators.py        # Text manipulation for flake.nix and vms.tf
├── models.py              # Data models (HostConfig)
├── templates/
│   ├── default.nix.j2     # Template for default.nix
│   └── configuration.nix.j2  # Template for configuration.nix
└── README.md              # This file

Testing

Run the test cases from the implementation plan:

# Test 1: DHCP host with defaults
python -m scripts.create_host.create_host create --hostname testdhcp --dry-run

# Test 2: Static IP host
python -m scripts.create_host.create_host create \
  --hostname test50 --ip 10.69.13.50/24 --dry-run

# Test 3: Custom resources
python -m scripts.create_host.create_host create \
  --hostname test51 --ip 10.69.13.51/24 \
  --cpu 8 --memory 8192 --disk 100G --dry-run

# Test 4: Duplicate hostname (should error)
python -m scripts.create_host.create_host create --hostname ns1 --dry-run

# Test 5: Invalid subnet (should error)
python -m scripts.create_host.create_host create \
  --hostname testbad --ip 192.168.1.50/24 --dry-run

# Test 6: Invalid hostname (should error)
python -m scripts.create_host.create_host create --hostname Test_Host --dry-run

License

Part of the nixos-servers homelab infrastructure repository.