Proxmox VE
Proxmox VE is a production-tier adapter . All writes route through the staged dual-gate - no change reaches the hypervisor until an operator explicitly applies it. The adapter implements credential redaction, guest-agent write-path gating, VNC ticket protection, typed-confirm gating, and multi-tenant task isolation; the apply path is covered by a regression test suite.
What works
Section titled “What works”| Domain | Operations |
|---|---|
| VMs | Create, start, stop, reboot, suspend, console, migrate, delete |
| LXC containers | Create, start, stop, reboot, console, migrate, delete |
| Snapshots | Create, restore, delete per VM/CT |
| Storage | CRUD, ISO upload/list, template management |
| Backups | Schedule backups, restore from PBS/local |
| Cluster | Membership, quorum status, HA group management |
| Nodes | Status, resource usage, tasks |
| Replication | Replication job list and status |
| SDN | Zone/vnet/subnet CRUD |
| Ceph | Status, OSD management, pool list |
| Firewall | Per-VM and node-level firewall rules |
| Guest agent | File read/write/exec (gated to site_admin+) |
PMG (Proxmox Mail Gateway) is not covered. Live cluster reconfiguration (add/remove nodes) requires shell access; it is not exposed through the API.
Adapter tier
Section titled “Adapter tier”| DG | CB | RR | TS | SSRF | RG |
|---|---|---|---|---|---|
| ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Prerequisites
Section titled “Prerequisites”- Proxmox VE 7.x or 8.x
- A dedicated API token for FreeSDN (preferred over username/password)
- The token user must have the
PVEAdminor a custom role with the permissions described below
Creating an API token in Proxmox
Section titled “Creating an API token in Proxmox”# On the Proxmox node, create a dedicated user and tokenpveum user add freesdn@pve --comment "FreeSDN management"pveum role add FreesdnRole \ --privs "VM.Allocate,VM.Config.CDROM,VM.Config.CPU,VM.Config.Disk,VM.Config.HWType,VM.Config.Memory,VM.Config.Network,VM.Config.Options,VM.Console,VM.Migrate,VM.Monitor,VM.PowerMgmt,VM.Snapshot,VM.Snapshot.Rollback,VM.Audit,Datastore.AllocateSpace,Datastore.AllocateTemplate,Datastore.Audit,Pool.Allocate,SDN.Allocate,SDN.Audit,Sys.Audit,Sys.Modify,Sys.PowerMgmt"pveum acl modify / --user freesdn@pve --role FreesdnRolepveum user token add freesdn@pve freesdn --privsep 0Copy the token secret - it is shown only once.
Adding a Proxmox cluster
Section titled “Adding a Proxmox cluster”Proxmox authentication is embedded directly in the controller record. There is no separate credential store step for Proxmox - pass token_id and token_secret inside the config dict:
# Add controller (API token auth - recommended)curl -X POST https://freesdn.example.com/api/v1/controllers \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>" \ -H "Content-Type: application/json" \ -d '{ "name": "PVE Cluster", "controller_type": "proxmox", "site_id": "<site-uuid>", "host": "pve.example.com", "port": 8006, "config": { "token_id": "freesdn@pve!freesdn", "token_secret": "<token-uuid-secret>" } }'
# Trigger discoverycurl -X POST https://freesdn.example.com/api/v1/discovery/controllers/<controller-uuid> \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>"If you prefer username/password auth instead of an API token, omit config and pass username and password at the top level of the controller payload.
FreeSDN will enumerate all nodes, VMs, and containers in the cluster.
Staged writes
Section titled “Staged writes”Every mutation is staged first. Applies require both gates open:
ADAPTER_READ_ONLY=falsein the FreeSDN environmentforce: trueon the apply request
This prevents accidental VM power operations or config changes. See Adapter Contract and Pending Changes for the apply flow.
Example: stage a VM stop, then apply it:
# Stage a VM power-offcurl -X POST 'https://freesdn.example.com/api/v1/gateway-proxmox-vm/<controller-id>/changes/proxmox.vm.stop?operation=create' \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>" \ -H "Content-Type: application/json" \ -d '{"payload": {"node": "pve1", "vmid": 100}, "target_id": "100"}'
# Apply (on Pending Changes page, or via API)curl -X POST https://freesdn.example.com/api/v1/gateway-vpn/changes/<change-uuid>/apply \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>" \ -H "Content-Type: application/json" \ -d '{"force": true}'Guest agent
Section titled “Guest agent”The QEMU guest agent provides file read/write and command execution inside running VMs. Because this is a high-privilege operation, it is gated to site_admin or higher:
# Read a file from a VM (site_admin required)curl -X POST 'https://freesdn.example.com/api/v1/hypervisor/controllers/<controller-id>/nodes/pve1/qemu/100/agent/file-read' \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>" \ -H "Content-Type: application/json" \ -d '{"file": "/etc/hostname"}'SDN management
Section titled “SDN management”FreeSDN can create and manage Proxmox SDN zones, VNETs, and subnets:
# List SDN zonescurl https://freesdn.example.com/api/v1/gateway-proxmox-sdn/<controller-id>/zones \ -H "Cookie: freesdn_access=<token>"
# Create a VNET (staged - no direct POST /vnets endpoint exists)curl -X POST 'https://freesdn.example.com/api/v1/gateway-proxmox-sdn/<controller-id>/changes/proxmox.sdn.vnet_create?operation=create' \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>" \ -H "Content-Type: application/json" \ -d '{"payload": {"vnet": "vnet10", "zone": "localzone", "tag": 10}}'Snapshots
Section titled “Snapshots”# Stage a snapshot create (writes are staged, not applied directly)curl -X POST 'https://freesdn.example.com/api/v1/gateway-proxmox-snapshot/<controller-id>/changes/proxmox.snapshot.create?operation=create' \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>" \ -H "Content-Type: application/json" \ -d '{"payload": {"node": "pve1", "vmid": 100, "vm_type": "qemu", "snapname": "pre-upgrade", "description": "Before kernel upgrade"}}'
# List snapshots (live read)curl 'https://freesdn.example.com/api/v1/gateway-proxmox-snapshot/<controller-id>/nodes/pve1/qemu/100/snapshots' \ -H "Cookie: freesdn_access=<token>"Backend route prefix
Section titled “Backend route prefix”12 sub-routers, one per feature domain:
/api/v1/gateway-proxmox-vm/- VM lifecycle/api/v1/gateway-proxmox-container/- LXC lifecycle/api/v1/gateway-proxmox-node/- node info and tasks/api/v1/gateway-proxmox-storage/- storage CRUD + ISO/api/v1/gateway-proxmox-backup/- backup schedules + restore/api/v1/gateway-proxmox-cluster/- cluster status/api/v1/gateway-proxmox-ha/- HA group management/api/v1/gateway-proxmox-snapshot/- VM/CT snapshots/api/v1/gateway-proxmox-replication/- replication jobs/api/v1/gateway-proxmox-sdn/- SDN zones/vnets/subnets/api/v1/gateway-proxmox-ceph/- Ceph status + OSDs/api/v1/gateway-proxmox-firewall/- per-VM + node firewall
Frontend pages
Section titled “Frontend pages”- HypervisorPage - cluster overview, node cards, VM/CT grid
- Child components in
frontend/src/pages/hypervisor/components/- detail panels for VMs, storage, HA status
Gotchas
Section titled “Gotchas”- Self-signed TLS - Proxmox nodes use self-signed certificates by default. FreeSDN accepts them. If you deploy with a trusted CA, set the CA bundle in
EXTRA_CA_CERTS. - API token format - Proxmox API tokens are
<user>@<realm>!<tokenid>=<secret>. Theusernamefield should befreesdn@pve!freesdn; theapi_keyfield should be the UUID secret frompveum. - Port 8006 - Proxmox defaults to port 8006. Include it in the
hostURL. - HA group names - HA group names are cluster-scoped; collisions across organizations are possible if multiple FreeSDN tenants share a cluster. Use a naming convention like
freesdn-<org-slug>-<group>.