# Automating Virtual Machines on Proxmox with Terraform

Managing virtual machines manually on Proxmox is straightforward for one or two servers, but as soon as you start spinning up multiple nodes, automation becomes essential. This is where **Terraform** shines. In this blog, I will share my journey of provisioning **Talos virtual machines** on a Proxmox host using Terraform, entirely declaratively, with the Proxmox API accessed securely over a **Pangolin tunnel**.

## Installing Terraform on macOS

Terraform is a command-line tool for building, changing, and versioning infrastructure safely and efficiently. On macOS, the easiest way to install Terraform is via Homebrew:

```yaml
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
```

After installation, verify it is working:

```yaml
terraform version
```

You should see the installed version displayed. Terraform is now ready to manage your infrastructure.

---

## Why Terraform with Proxmox?

Terraform allows you to describe your infrastructure as code. Instead of clicking through the Proxmox web interface, you define **VMs, disks, networks, and other resources in** `.tf` files. Terraform can then apply, update, or destroy these resources automatically.

For Proxmox, we are using the **Telmate provider** (`Telmate/proxmox`), which interacts with Proxmox via its REST API. The official documentation for the VM resource can be found here:

[Terraform Proxmox VM\_QEMU Resource](https://registry.terraform.io/providers/Telmate/proxmox/latest/docs/resources/vm_qemu)

This documentation is invaluable for understanding all the supported arguments and disk/network options.

---

## Environment Setup

My Proxmox host is securely exposed through a **Pangolin tunnel**. This allows me to access the Proxmox API remotely without exposing it publicly. If you want to understand how to set up the tunnel, I wrote detailed guides earlier:

* [Running Talos Kubernetes Behind a Pangolin Tunnel](https://blog.nyzex.in/running-talos-kubernetes-behind-a-pangolin-tunnel)
    
* [Self-hosting Pangolin Newt on Your Own Server](https://blog.nyzex.in/self-hosting-pangolin-newt-on-your-own-server)
    

With the tunnel in place, I can interact with `https://proxmox.nyzex.in` safely by configuring Pangolin resource.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1762971705509/0a93b111-7d9a-41bc-98c7-864e23352564.png align="center")

* **Terraform on your Mac** runs `init`, `plan`, and `apply`.
    
* Terraform uses the **Telmate Proxmox provider** to talk to the Proxmox API.
    
* Communication is done securely via the **Pangolin tunnel** at [`tunnel.nyzex.in`](http://tunnel.nyzex.in).
    
* Proxmox provisions the VM:
    
    * ISO is mounted on IDE0 for boot/install.
        
    * Main disk is created on local-lvm (32 GB, raw format).
        
    * VM network is attached to vmbr0.
        
* VM boots from ISO, ready for Talos installation
    

---

## Uploading the Talos ISO

Before creating the VM with Terraform, I manually uploaded the Talos ISO to the Proxmox ISO storage:

```yaml
/var/lib/vz/template/iso/metal-amd64.iso
```

This avoids network download issues and ensures Terraform can mount the ISO during VM creation.

## Terraform Configuration Files

The Terraform configuration consists of **two main files**: [`main.tf`](http://main.tf) and [`vm.tf`](http://vm.tf).

### [main.tf](http://main.tf)

This file sets up the Terraform provider and authentication with Proxmox:

```yaml
terraform {
  required_providers {
    proxmox = {
      source  = "Telmate/proxmox"
      version = "3.0.2-rc04"
    }
  }
  required_version = ">= 1.0"
}

provider "proxmox" {
  pm_api_url      = "https://proxmox.nyzex.in/api2/json"  # Proxmox API endpoint via Pangolin
  pm_user         = "root@pam"                             # Proxmox user
  pm_password     = "super-secret-password"               # Proxmox password
  pm_tls_insecure = true                                   # Ignore TLS certificate warnings
  pm_debug        = true                                   # Enable debug logging
}
```

This provider block ensures Terraform can authenticate with Proxmox through the API.

---

### [vm.tf](http://vm.tf)

This file defines the Talos virtual machine with proper boot order, disks, and network configuration:

```yaml
resource "proxmox_vm_qemu" "talos_vm" {
  name        = "talos-terraform-test"       # VM name
  target_node = "my-pve1"                  # Proxmox node to deploy on
  bootdisk    = "ide0"                       # Boot from CD-ROM first
  onboot      = true                          # Start VM automatically
  agent       = 1                             # Enable QEMU guest agent
  boot        = "order=ide0;scsi0;net0"     # Boot order: CD-ROM, then main disk, then network

  cpu {
    cores   = 2
    sockets = 1
  }

  memory = 2048                               # RAM in MB

  # Disks
  disks {
    ide {
      ide0 {
        cdrom {
          iso = "local:iso/metal-amd64.iso"   # ISO path in Proxmox storage
        }
      }
    }
    scsi {
      scsi0 {
        disk {
          storage = "local-lvm"              # VM disk storage
          size    = "32G"                     # Disk size
          format  = "raw"                     # Disk format
        }
      }
    }
  }

  # Network interface
  network {
    id     = 0
    model  = "virtio"
    bridge = "vmbr0"                         # Connect to Proxmox bridge
  }
}
```

---

### How it Works

1. Terraform provisions the VM on Proxmox using the API.
    
2. The ISO is mounted on the IDE0 CD-ROM drive.
    
3. The main VM disk is created on `local-lvm`.
    
4. Network interface is attached to `vmbr0`.
    
5. The VM boots from the CD-ROM first, allowing Talos installation onto the main disk.
    

Once installation is complete, the boot disk can be changed to `scsi0` to boot directly from Talos without the ISO.

---

## Applying the Terraform Configuration

After creating the `.tf` files:

```yaml
terraform init       # Initialize Terraform and download providers
terraform plan       # Review planned actions
terraform apply      # Apply configuration and provision the VM
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1762971183899/d560cc27-e96a-4727-a725-26274e7c2b3b.png align="center")

Terraform will create the VM, mount the ISO, and configure the disk and network. You can then open the Proxmox console to complete the Talos installation.

After apply, you might get an error:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1762971234123/0d7fe204-d83c-4273-81c0-a66d6171da90.png align="center")

Not to fear! because if you navigate to your proxmox, you will see that your VM was actually created properly, weird but okay XD

---

## Conclusion

Terraform allows fully automated provisioning of Talos virtual machines on Proxmox. Combined with the Pangolin tunnel, it provides a secure and reproducible workflow. Once configured, you can scale to multiple nodes and manage your Talos Kubernetes clusters entirely through code.

This setup is ideal for anyone running **home labs, secure development environments, or experimental Kubernetes clusters**, and it ensures consistency and repeatability across deployments.
