Quick Start: Chạy được Terraform + Proxmox trong 5 phút
Mình chạy homelab với Proxmox VE quản lý 12 VM và container — đây là playground để test mọi thứ trước khi đưa lên production. Sau 6 tháng dùng Terraform để quản lý toàn bộ hạ tầng đó, mình không còn muốn click chuột tạo VM thủ công nữa. Mọi thứ đều là code, có thể review, rollback và tái tạo lại trong vài phút.
Trước khi đi vào chi tiết, thử ngay để cảm nhận:
Bước 1: Cài Terraform
# Ubuntu/Debian
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform
terraform version
Bước 2: Tạo API Token trên Proxmox
Vào Proxmox Web UI → Datacenter → Permissions → API Tokens → Add. Tạo token cho user root@pam, bỏ tick “Privilege Separation” để token có đủ quyền. Copy token string — nó chỉ hiện 1 lần.
Bước 3: File cấu hình tối thiểu
terraform {
required_providers {
proxmox = {
source = "bpg/proxmox"
version = "~> 0.60"
}
}
}
provider "proxmox" {
endpoint = "https://192.168.1.100:8006/"
api_token = "root@pam!terraform=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
insecure = true # bỏ nếu có SSL cert hợp lệ
}
resource "proxmox_virtual_environment_vm" "ubuntu_vm" {
name = "ubuntu-test"
node_name = "pve"
vm_id = 200
cpu {
cores = 2
}
memory {
dedicated = 2048
}
disk {
datastore_id = "local-lvm"
file_id = "local:iso/ubuntu-22.04-live-server-amd64.iso"
interface = "virtio0"
size = 20
}
network_device {
bridge = "vmbr0"
}
}
terraform init
terraform plan
terraform apply
Chạy xong, VM ubuntu-test xuất hiện ngay trên Proxmox dashboard — không cần click một cái gì cả.
Giải thích chi tiết: Provider bpg/proxmox hoạt động thế nào
Hiện tại có 2 provider phổ biến cho Proxmox: Telmate/proxmox (cũ, ít được maintain) và bpg/proxmox (mới hơn, active, hỗ trợ nhiều resource hơn). Mình đã thử cả hai và chuyển sang bpg sau khi Telmate không xử lý Cloud-Init đúng cách trên Ubuntu 22.04.
Các resource type chính
proxmox_virtual_environment_vm— tạo và quản lý VMproxmox_virtual_environment_container— LXC containerproxmox_virtual_environment_download_file— download ISO hoặc cloud imageproxmox_virtual_environment_pool— tạo resource poolproxmox_virtual_environment_user— quản lý user Proxmox
Workflow thực tế với Cloud-Init
Clone từ template có Cloud-Init là cách mình dùng mỗi ngày. VM boot xong là SSH được luôn, không cần cài tay.
resource "proxmox_virtual_environment_vm" "web_server" {
name = "web-prod-01"
node_name = "pve"
vm_id = 201
clone {
vm_id = 9000 # ID của template Ubuntu Cloud-Init
full = true # full clone, không phụ thuộc template
}
cpu {
cores = 4
type = "x86-64-v2-AES"
}
memory {
dedicated = 4096
}
network_device {
bridge = "vmbr0"
model = "virtio"
}
initialization {
ip_config {
ipv4 {
address = "192.168.1.201/24"
gateway = "192.168.1.1"
}
}
user_account {
username = "ubuntu"
keys = [file("~/.ssh/id_ed25519.pub")]
}
dns {
servers = ["1.1.1.1", "8.8.8.8"]
}
}
lifecycle {
ignore_changes = [
initialization, # tránh re-apply mỗi lần plan
]
}
}
Nâng cao: Quản lý nhiều VM với for_each và module
Khi số VM tăng lên — mình có 12 cái — việc copy-paste resource block trở nên không thể maintain. Dùng for_each kết hợp locals giải quyết gọn:
locals {
vms = {
"web-01" = { cores = 2, memory = 2048, ip = "192.168.1.201", vm_id = 201 }
"web-02" = { cores = 2, memory = 2048, ip = "192.168.1.202", vm_id = 202 }
"db-01" = { cores = 4, memory = 8192, ip = "192.168.1.210", vm_id = 210 }
"cache" = { cores = 2, memory = 4096, ip = "192.168.1.220", vm_id = 220 }
}
}
resource "proxmox_virtual_environment_vm" "vms" {
for_each = local.vms
name = each.key
node_name = "pve"
vm_id = each.value.vm_id
clone {
vm_id = 9000
full = true
}
cpu {
cores = each.value.cores
}
memory {
dedicated = each.value.memory
}
initialization {
ip_config {
ipv4 {
address = "${each.value.ip}/24"
gateway = "192.168.1.1"
}
}
user_account {
username = "ubuntu"
keys = [file("~/.ssh/id_ed25519.pub")]
}
}
}
Thêm VM mới chỉ cần thêm 1 dòng vào locals.vms. Muốn xóa thì xóa dòng đó rồi terraform apply.
Output để kết hợp với Ansible
Terraform tạo VM xong, Ansible lo phần provision bên trong. Kết hợp hai tool này là workflow mình đang dùng cho production:
output "vm_ips" {
value = {
for k, v in proxmox_virtual_environment_vm.vms :
k => v.initialization[0].ip_config[0].ipv4[0].address
}
}
# Lấy IP để tạo Ansible inventory động
terraform output -json vm_ips | jq -r 'to_entries[] | "\(.key) ansible_host=\(.value | split("/")[0])"'
Tips thực tế sau 6 tháng dùng trên production
1. Tạo template Cloud-Init đúng cách — bước quan trọng nhất
Template phải được tạo từ cloud image, không phải từ ISO cài tay. Đây là điều mình mất nhiều thời gian nhất lúc đầu:
# Chạy trên Proxmox host
wget https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img
qm create 9000 --name "ubuntu-22.04-cloud" --memory 2048 --cores 2 --net0 virtio,bridge=vmbr0
qm importdisk 9000 jammy-server-cloudimg-amd64.img local-lvm
qm set 9000 --scsihw virtio-scsi-pci --scsi0 local-lvm:vm-9000-disk-0
qm set 9000 --boot c --bootdisk scsi0
qm set 9000 --ide2 local-lvm:cloudinit
qm set 9000 --serial0 socket --vga serial0
qm set 9000 --agent enabled=1
qm template 9000
2. Lưu state file an toàn với remote backend
State file (terraform.tfstate) là thứ Terraform dùng để biết VM nào đang tồn tại. Mất file này là mất track toàn bộ. Dùng MinIO tự host như một S3 backend là giải pháp tốt cho homelab:
terraform {
backend "s3" {
bucket = "terraform-state"
key = "proxmox/homelab.tfstate"
region = "main"
endpoint = "http://192.168.1.50:9000"
skip_credentials_validation = true
skip_metadata_api_check = true
skip_region_validation = true
force_path_style = true
}
}
3. Luôn review plan trước khi apply
# Save plan ra file, review kỹ rồi mới apply
terraform plan -out=tfplan
terraform show tfplan
terraform apply tfplan
# Xóa 1 VM cụ thể (không xóa hết)
terraform destroy -target='proxmox_virtual_environment_vm.vms["web-01"]'
Lỗi thường gặp và cách fix
- Cloud-Init không apply: Kiểm tra template có IDE drive cloudinit chưa — thiếu bước
qm set 9000 --ide2 local-lvm:cloudinit - Permission denied khi apply: API token cần các quyền
VM.Allocate,VM.Clone,Datastore.AllocateSpace,VM.Config.Network - Terraform stuck ở “waiting for VM to start”: QEMU Guest Agent chưa cài trong template — thiếu
qm set 9000 --agent enabled=1 - Destroy không thành công: VM đang có snapshot thì Terraform không tự xóa được — phải vào Proxmox xóa snapshot tay trước. Mình từng mất 2 tiếng debug lỗi này
Sau khi setup xong toàn bộ hạ tầng homelab bằng Terraform, mình tốn chưa đến 10 phút để tái tạo lại từ đầu nếu cần. Đó là lý do IaC với Proxmox xứng đáng bỏ thời gian setup ban đầu.

