Files
nixos-servers/terraform/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

4.7 KiB

OpenTofu Configuration for Proxmox

This directory contains OpenTofu configuration for managing Proxmox VMs using a parameterized, multi-VM deployment system.

Setup

  1. Create a Proxmox API token:

    • Log into Proxmox web UI
    • Go to Datacenter → Permissions → API Tokens
    • Click Add
    • User: root@pam, Token ID: terraform
    • Uncheck "Privilege Separation"
    • Save the token secret (shown only once)
  2. Configure credentials:

    cd terraform
    cp terraform.tfvars.example terraform.tfvars
    # Edit terraform.tfvars with your Proxmox details
    
  3. Initialize OpenTofu:

    tofu init
    
  4. Test connection:

    tofu plan
    

Defining VMs

All VMs are defined in the vms.tf file in the locals.vms map. Each VM can specify custom configurations or use defaults from variables.tf.

Example: DHCP VM

vms = {
  "simple-vm" = {
    cpu_cores = 2
    memory    = 2048
    disk_size = "20G"
    # No "ip" field = DHCP
  }
}

Example: Static IP VM

vms = {
  "web-server" = {
    ip        = "10.69.13.50/24"
    cpu_cores = 4
    memory    = 4096
    disk_size = "50G"
  }
}

Example: Minimal VM (all defaults)

vms = {
  "test-vm" = {}
}

Example: Multiple VMs

vms = {
  "vm1" = {
    ip = "10.69.13.50/24"
  }
  "vm2" = {
    ip = "10.69.13.51/24"
    cpu_cores = 4
    memory = 8192
  }
  "vm3" = {
    # DHCP
    cpu_cores = 2
    memory = 2048
  }
}

Example: Test VM with Custom Git Branch

For testing pipeline changes without polluting master:

vms = {
  "test-vm" = {
    ip = "10.69.13.100/24"
    flake_branch = "test-pipeline"  # Bootstrap from this branch
  }
}

This VM will bootstrap from the test-pipeline branch instead of master. Production VMs should omit the flake_branch field.

Configuration Options

Each VM in the vms map supports the following fields (all optional):

Field Description Default
ip Static IP with CIDR (e.g., "10.69.13.50/24"). Omit for DHCP DHCP
gateway Network gateway (used with static IP) 10.69.13.1
cpu_cores Number of CPU cores 2
memory Memory in MB 2048
disk_size Disk size (e.g., "20G", "100G") "20G"
flake_branch Git branch for bootstrap (for testing, omit for production) master
target_node Proxmox node to deploy to "pve1"
template_name Template VM to clone from "nixos-25.11.20260128.fa83fd8"
storage Storage backend "local-zfs"
bridge Network bridge "vmbr0"
vlan_tag VLAN tag 13
ssh_public_key SSH public key for root See variables.tf
nameservers DNS servers "10.69.13.5 10.69.13.6"
search_domain DNS search domain "home.2rjus.net"

Defaults are defined in variables.tf and can be changed globally.

Deployment Commands

Deploy All VMs

tofu apply

Deploy Specific VM

tofu apply -target=proxmox_vm_qemu.vm[\"vm-name\"]

Destroy Specific VM

tofu destroy -target=proxmox_vm_qemu.vm[\"vm-name\"]

View Deployed VMs

tofu output vm_ips
tofu output deployment_summary

Plan Changes

tofu plan

Outputs

After deployment, OpenTofu provides two outputs:

vm_ips: IP addresses and SSH commands for each VM

vm_ips = {
  "vm1" = {
    ip = "10.69.13.50"
    ssh_command = "ssh root@10.69.13.50"
  }
}

deployment_summary: Full specifications for each VM

deployment_summary = {
  "vm1" = {
    cpu_cores = 4
    memory_mb = 4096
    disk_size = "50G"
    ip = "10.69.13.50"
    node = "pve1"
  }
}

Workflow

  1. Edit vms.tf to define your VMs in the locals.vms map
  2. Run tofu plan to preview changes
  3. Run tofu apply to deploy
  4. Run tofu output vm_ips to get IP addresses
  5. SSH to VMs and configure as needed

Files

  • main.tf - Provider configuration
  • variables.tf - Variable definitions and defaults
  • vms.tf - VM definitions and deployment logic
  • cloud-init.tf - Custom cloud-init configuration for branch-specific bootstrap
  • outputs.tf - Output definitions for deployed VMs
  • terraform.tfvars.example - Example credentials file
  • terraform.tfvars - Your actual credentials (gitignored)
  • .generated/ - Auto-generated cloud-init files (gitignored)
  • vm.tf.old - Archived single-VM configuration (reference)

Notes

  • VMs are deployed as full clones (not linked clones)
  • Cloud-init handles initial networking configuration
  • QEMU guest agent is enabled on all VMs
  • All VMs start on boot by default
  • IPv6 is disabled
  • Destroying VMs removes them from Proxmox but does not clean up DNS entries or NixOS configurations