Proxmox SDN with Terraform¶
Module: hybridops-tech/sdn/proxmox · GitHub: terraform-proxmox-sdn
Prerequisites: Proxmox VE 8.x with SDN enabled · dnsmasq installed · Linux control node with Terraform (and Terragrunt if using the stack workflow).
What the module manages¶
| Layer | What gets provisioned |
|---|---|
| Proxmox SDN | Zone, VNets, subnets |
| Host networking | L3 gateways on vnet* interfaces |
| Egress | SNAT via uplink bridge |
| DHCP | dnsmasq units per subnet |
Three toggles control host-level behaviour:
enable_host_l3 = true # gateway IPs on vnet* interfaces
enable_snat = true # SNAT out of zone_bridge
enable_dhcp = true # dnsmasq DHCP (requires enable_host_l3 = true)
1. Proxmox API token¶
In the Proxmox UI, create an API token (automation@pam!infra-token) with SDN, node networking, and node-read permissions. Then export on your control node:
export PROXMOX_URL="https://<PROXMOX-IP>:8006/api2/json"
export PROXMOX_TOKEN_ID="automation@pam!infra-token"
export PROXMOX_TOKEN_SECRET="<UUID>"
export PROXMOX_NODE="<NODE-NAME>"
2. Option A: Standalone Terraform¶
mkdir -p ~/proxmox-sdn && cd ~/proxmox-sdn
touch main.tf variables.tf terraform.tfvars
main.tf
terraform {
required_version = ">= 1.5.0"
required_providers {
proxmox = {
source = "bpg/proxmox"
version = ">= 0.50.0"
}
}
}
provider "proxmox" {
endpoint = var.proxmox_url
api_token = var.proxmox_token
insecure = var.proxmox_insecure
}
module "sdn" {
source = "hybridops-tech/sdn/proxmox"
version = "~> 0.1.5"
zone_name = "hybzone"
zone_bridge = "vmbr0"
proxmox_node = var.proxmox_node
proxmox_host = var.proxmox_host
enable_host_l3 = true
enable_snat = true
enable_dhcp = true
dns_domain = "hybridops.local"
dns_lease = "24h"
vnets = {
vnetmgmt = {
vlan_id = 10
description = "Management network"
subnets = {
mgmt = {
cidr = "10.10.0.0/24"
gateway = "10.10.0.1"
dhcp_range_start = "10.10.0.100"
dhcp_range_end = "10.10.0.200"
dhcp_dns_server = "8.8.8.8"
}
}
}
}
proxmox_url = var.proxmox_url
proxmox_token = var.proxmox_token
proxmox_insecure = var.proxmox_insecure
}
terraform.tfvars
proxmox_url = "https://<PROXMOX-IP>:8006/api2/json"
proxmox_token = "root@pam!terraform=<YOUR-API-TOKEN-SECRET>"
proxmox_insecure = true
proxmox_node = "<NODE-NAME>"
proxmox_host = "<PROXMOX-IP>"
terraform init && terraform plan && terraform apply
3. Option B: Terragrunt (HybridOps stack)¶
In network-sdn/terragrunt.hcl:
include "root" {
path = find_in_parent_folders("root.hcl")
}
terraform {
source = "tfr://registry.terraform.io/hybridops-tech/sdn/proxmox?version=0.1.5"
}
locals {
proxmox_url = local.env.PROXMOX_URL
proxmox_token = "${local.env.PROXMOX_TOKEN_ID}=${local.env.PROXMOX_TOKEN_SECRET}"
proxmox_insecure = true
proxmox_node = local.env.PROXMOX_NODE
proxmox_host = split(":", local.env.PROXMOX_HOST)[0]
}
inputs = {
zone_name = "hybzone"
zone_bridge = "vmbr0"
proxmox_node = local.proxmox_node
proxmox_host = local.proxmox_host
enable_host_l3 = true
enable_snat = true
enable_dhcp = true
dns_domain = "hybridops.local"
dns_lease = "24h"
vnets = {
vnetmgmt = { vlan_id = 10, description = "Management", subnets = { submgmt = { cidr = "10.10.0.0/24", gateway = "10.10.0.1", dhcp_range_start = "10.10.0.120", dhcp_range_end = "10.10.0.220", dhcp_dns_server = "8.8.8.8" } } }
vnetobs = { vlan_id = 11, description = "Observability", subnets = { subobs = { cidr = "10.11.0.0/24", gateway = "10.11.0.1", dhcp_range_start = "10.11.0.120", dhcp_range_end = "10.11.0.220", dhcp_dns_server = "8.8.8.8" } } }
vnetdev = { vlan_id = 20, description = "Development", subnets = { subdev = { cidr = "10.20.0.0/24", gateway = "10.20.0.1" } } }
vnetprod = { vlan_id = 40, description = "Production", subnets = { subprod = { cidr = "10.40.0.0/24", gateway = "10.40.0.1" } } }
}
proxmox_url = local.proxmox_url
proxmox_token = local.proxmox_token
proxmox_insecure = local.proxmox_insecure
}
cd network-sdn && terragrunt init && terragrunt plan && terragrunt apply
4. Verify¶
# SDN objects
ssh root@<PROXMOX_HOST> 'pvesh get /cluster/sdn/zones'
ssh root@<PROXMOX_HOST> 'pvesh get /cluster/sdn/vnets'
# Host networking
ssh root@<PROXMOX_HOST> 'ip addr show | grep "inet 10\."'
# DHCP units
ssh root@<PROXMOX_HOST> 'systemctl list-units "dnsmasq@hybridops-sdn-dhcp-*" --no-pager'
5. Naming constraints¶
Proxmox SDN enforces: IDs ≤ 8 characters, lowercase, no dashes.
- Valid:
hybzone,vnetmgmt,vclst01m - Invalid:
basic-zone,vnet-mgmt
6. Key outputs¶
| Output | Description |
|---|---|
zone_name |
SDN zone ID |
vnets |
Map of VNet keys → id, zone, vlan_id |
subnets |
Map of <vnet>-<subnet> → CIDR, gateway, DHCP config |
References¶
- SDN Operations Runbook: day-two operational procedures, validation checks, and troubleshooting for a deployed SDN
- ADR-0101 – VLAN Allocation Strategy
- ADR-0102 – Proxmox as Intra-Site Core Router
- ADR-0104 – Static IP Allocation (Terraform IPAM)
- Network SDN Stack README