diff --git a/coder/proxmox-vm/Readme.md b/coder/proxmox-vm/Readme.md new file mode 100644 index 0000000..ed0fd13 --- /dev/null +++ b/coder/proxmox-vm/Readme.md @@ -0,0 +1,161 @@ +--- +display_name: Proxmox VM +description: Provision VMs on Proxmox VE as Coder workspaces +icon: ../../../../.icons/proxmox.svg +verified: false +tags: [proxmox, vm, cloud-init, qemu] +--- + +# Proxmox VM Template for Coder + +Provision Linux VMs on Proxmox as [Coder workspaces](https://coder.com/docs/workspaces). The template clones a cloud‑init base image, injects user‑data via Snippets, and runs the Coder agent under the workspace owner's Linux user. + +## Prerequisites + +- Proxmox VE 8/9 +- Proxmox API token with access to nodes and storages +- SSH access from Coder provisioner to Proxmox VE +- Storage with "Snippets" content enabled +- Ubuntu cloud‑init image/template on Proxmox + - Latest images: https://cloud-images.ubuntu.com/ ([source](https://cloud-images.ubuntu.com/)) + +## Prepare a Proxmox Cloud‑Init Template (once) + +Run on the Proxmox node. This uses a RELEASE variable so you always pull a current image. + +```bash +# Choose a release (e.g., jammy or noble) +RELEASE=jammy +IMG_URL="https://cloud-images.ubuntu.com/${RELEASE}/current/${RELEASE}-server-cloudimg-amd64.img" +IMG_PATH="/var/lib/vz/template/iso/${RELEASE}-server-cloudimg-amd64.img" + +# Download cloud image +wget "$IMG_URL" -O "$IMG_PATH" + +# Create base VM (example ID 999), enable QGA, correct boot order +NAME="ubuntu-${RELEASE}-cloudinit" +qm create 999 --name "$NAME" --memory 4096 --cores 2 \ + --net0 virtio,bridge=vmbr0 --agent enabled=1 +qm set 999 --scsihw virtio-scsi-pci +qm importdisk 999 "$IMG_PATH" local-lvm +qm set 999 --scsi0 local-lvm:vm-999-disk-0 +qm set 999 --ide2 local-lvm:cloudinit +qm set 999 --serial0 socket --vga serial0 +qm set 999 --boot 'order=scsi0;ide2;net0' + +# Enable Snippets on storage 'local' (one‑time) +pvesm set local --content snippets,vztmpl,backup,iso + +# Convert to template +qm template 999 +``` + +Verify: + +```bash +qm config 999 | grep -E 'template:|agent:|boot:|ide2:|scsi0:' +``` + +### Enable Snippets via GUI + +- Datacenter → Storage → select `local` → Edit → Content → check "Snippets" → OK +- Ensure `/var/lib/vz/snippets/` exists on the node for snippet files +- Template page → Cloud‑Init → Snippet Storage: `local` → File: your yml → Apply + +## Configure this template + +Edit `terraform.tfvars` with your environment: + +```hcl +# Proxmox API +proxmox_api_url = "https://:8006/api2/json" +proxmox_api_token_id = "!" +proxmox_api_token_secret = "" + +# SSH to the node (for snippet upload) +proxmox_host = "" +proxmox_password = "" +proxmox_ssh_user = "root" + +# Infra defaults +proxmox_node = "pve" +disk_storage = "local-lvm" +snippet_storage = "local" +bridge = "vmbr0" +vlan = 0 +clone_template_vmid = 999 +``` + +### Variables (terraform.tfvars) + +- These values are standard Terraform variables that the template reads at apply time. +- Place secrets (e.g., `proxmox_api_token_secret`, `proxmox_password`) in `terraform.tfvars` or inject with environment variables using `TF_VAR_*` (e.g., `TF_VAR_proxmox_api_token_secret`). +- You can also override with `-var`/`-var-file` if you run Terraform directly. With Coder, the repo's `terraform.tfvars` is bundled when pushing the template. + +Variables expected: + +- `proxmox_api_url`, `proxmox_api_token_id`, `proxmox_api_token_secret` (sensitive) +- `proxmox_host`, `proxmox_password` (sensitive), `proxmox_ssh_user` +- `proxmox_node`, `disk_storage`, `snippet_storage`, `bridge`, `vlan`, `clone_template_vmid` +- Coder parameters: `cpu_cores`, `memory_mb`, `disk_size_gb` + +## Proxmox API Token (GUI/CLI) + +Docs: https://pve.proxmox.com/wiki/User_Management#pveum_tokens + +GUI: + +1. (Optional) Create automation user: Datacenter → Permissions → Users → Add (e.g., `terraform@pve`) +2. Permissions: Datacenter → Permissions → Add → User Permission + - Path: `/` (or narrower covering your nodes/storages) + - Role: `PVEVMAdmin` + `PVEStorageAdmin` (or `PVEAdmin` for simplicity) +3. Token: Datacenter → Permissions → API Tokens → Add → copy Token ID and Secret +4. Test: + +```bash +curl -k -H "Authorization: PVEAPIToken=!=" \ + https:// < PVE_HOST > :8006/api2/json/version +``` + +CLI: + +```bash +pveum user add terraform@pve --comment 'Terraform automation user' +pveum aclmod / -user terraform@pve -role PVEAdmin +pveum user token add terraform@pve terraform --privsep 0 +``` + +## Use + +```bash +# From this directory +coder templates push --yes proxmox-cloudinit --directory . | cat +``` + +Create a workspace from the template in the Coder UI. First boot usually takes 60–120s while cloud‑init runs. + +## How it works + +- Uploads rendered cloud‑init user‑data to `:snippets/.yml` via the provider's `proxmox_virtual_environment_file` +- VM config: `virtio-scsi-pci`, boot order `scsi0, ide2, net0`, QGA enabled +- Linux user equals Coder workspace owner (sanitized). To avoid collisions, reserved names (`admin`, `root`, etc.) get a suffix (e.g., `admin1`). User is created with `primary_group: adm`, `groups: [sudo]`, `no_user_group: true` +- systemd service runs as that user: + - `coder-agent.service` + +## Troubleshooting quick hits + +- iPXE boot loop: ensure template has bootable root disk and boot order `scsi0,ide2,net0` +- QGA not responding: install/enable QGA in template; allow 60–120s on first boot +- Snippet upload errors: storage must include `Snippets`; token needs Datastore permissions; path format `:snippets/` handled by provider +- Permissions errors: ensure the token's role covers the target node(s) and storages +- Verify snippet/QGA: `qm config | egrep 'cicustom|ide2|ciuser'` + +## References + +- Ubuntu Cloud Images (latest): https://cloud-images.ubuntu.com/ ([source](https://cloud-images.ubuntu.com/)) +- Proxmox qm(1) manual: https://pve.proxmox.com/pve-docs/qm.1.html +- Proxmox Cloud‑Init Support: https://pve.proxmox.com/wiki/Cloud-Init_Support +- Terraform Proxmox provider (bpg): `bpg/proxmox` on the Terraform Registry +- Coder – Best practices & templates: + - https://coder.com/docs/tutorials/best-practices/speed-up-templates + - https://coder.com/docs/tutorials/template-from-scratch \ No newline at end of file