# bpg/terraform-provider-proxmox: a fork that states its support matrix as refusals

> This is a Go provider for Proxmox Virtual Environment, forked from a repository that is no longer maintained, and the most useful page in its readme is the compatibility section, which promises 9.x, tolerates 8.x without testing it, and refuses 7.x outright. It also needs an SSH key to the host alongside its API token, which the dependency list explains and the documentation leaves unstated.

**bpg/terraform-provider-proxmox** — Terraform / OpenTofu Provider for Proxmox VE

- Repository: https://github.com/bpg/terraform-provider-proxmox
- Website: https://bpg.sh/docs/
- Stars: 2,238 · Forks: 320
- Language: Go
- License: MPL-2.0
- Published: 2026-09-30 · Updated: 2026-09-30 · Language: en
- Canonical page: https://hysenlabs.com/projects/bpg-terraform-provider-proxmox

## The support matrix is three lines, and two of them are refusals

Most provider readmes bury compatibility in a table of tested versions. This one leads with it, and the lead is a decision rather than a list. The compatibility promise is Proxmox 9.x, currently named as 9.2, and the known issues section is where the detail sits. Proxmox 8.x is supported, and the wording is careful: some functionality might be limited or might not work as expected, testing against 8.x is not a priority, and issues specific to 8.x will not be addressed. Proxmox 7.x is not supported at all, and the wording is that some features might work, they do not test against it, and issues specific to it will not be addressed. Two sentences of refusal, delivered early and without hedging, are worth more to an evaluator than a compatibility table that claims everything works. They tell you where the project is spending its time and they tell you what will happen to your bug report. The versioning statement in the same spirit is that while the provider is on a 0.x version it is not guaranteed to be backward compatible with all previous minor versions, and that they will try to maintain backward compatibility between versions as much as possible. That is an unusually honest pairing: a refusal to promise, followed by a statement of intent. The practical consequence is that a provider upgrade should be treated as a change with a plan attached rather than a routine bump, and the state file is the thing to snapshot first. The requirements section is equally specific about the rest of the environment: TLS 1.3 on the API endpoint with legacy 1.2 optionally supported, Terraform 1.5 or later or OpenTofu 1.6 or later, and a higher floor for particular features, since write-only attributes need Terraform 1.11 or OpenTofu 1.10.

## A fork of an unmaintained provider, kept by one person who says so

The lineage is stated in a single line: this is a fork of a provider that is no longer maintained. That is the whole origin story, and it is worth pausing on what it means. A provider is not a library you import and pin; it is a binary that Terraform or OpenTofu downloads and runs inside your planning process, with credentials, and it decides what your infrastructure looks like. So the question of who maintains it is not a question about commit frequency, it is a question about who you call when a plan proposes something wrong. The readme answers it in a disclaimer that is more specific than most. The project is described as a personal open-source initiative by one maintainer, not affiliated with, endorsed by or associated with any of their current or former employers, and all opinions, code and documentation are stated to be those of the maintainer and individual contributors. A second paragraph says the project is not affiliated with the vendor that makes Proxmox and that the name and logo are used for information only. Both statements are the right thing to say and together they describe the risk profile accurately: this is infrastructure tooling maintained by one person, on their own time, unrelated to either the vendor or an employer, and the maintainer has written that down rather than leaving you to infer it. The licence is the Mozilla Public License version 2, which for a provider is a good fit, since it requires publication of modifications to the provider itself without imposing anything on the configurations or the infrastructure you manage with it. The sponsoring page and the contributor list are both linked, and the version record shows a current patch line with releases in the last month, so the project is being maintained in the present tense. The honest summary is that the maintainer is the durability story, and the readme is unusually straight about it.

## The provider needs SSH to the host as well as a token for the API

This is the detail that will cost you an afternoon if you meet it from an error message, so it is worth reading in the readme first. The example environment requires a working key agent with a key authorised on the Proxmox host, and the readme is explicit about the consequence: the default provider configuration authenticates to the API with a token, so there is no password to fall back to for SSH, and you must either have an agent configured or explicitly set an SSH password or private key in the provider block. A declarative provider that also opens an SSH session to the hypervisor is doing something the API alone does not explain, and the dependency list answers it. The module requires an SFTP library, a known-hosts verifier for SSH host keys, a Windows named-pipe library for the plugin transport, and a retry library. So the provider authenticates over SSH in addition to talking to the API, verifies the host's key against a known-hosts store, and moves files that way, which is consistent with the kind of operation that has no API: getting content onto a node. Two consequences for configuration. The first is that a Proxmox API token is not sufficient, which means your pipeline needs an SSH key as well, and a key agent is awkward inside most CI systems, so a private key in the provider block or in a variable is the more realistic setup. The second is that the example variables file includes a root password alongside the token, and a variables file is exactly the kind of file people commit, so that value deserves the same care as any other secret. The token format in the example is worth reading once, since it is the shape Proxmox expects: a user and realm, an exclamation mark, a token name, an equals sign and the secret. What the readme does not say is which specific operations need the SSH path, and that is worth confirming in the documentation before you assume a token is enough for a given resource.

## High availability is the gap, and on 9.x it is a brand new API

The known issues section contains the single most consequential fact for anyone running a production cluster, and it is two items. The first is that Proxmox 9.x introduced a new API for managing high availability resources and the provider does not support it yet, with an issue reference for the detail. The second is the drift problem, and it is the reason the first one matters. If a virtual machine or container is created with the provider but is then managed by a high availability cluster, the cluster may migrate it to a different node without the provider being aware of it. Read the two together and the shape is clear. You can declare HA-managed workloads, and the cluster is free to move them, and the tool you are declaring them with does not know where they are. That is not a bug in your configuration, it is a mismatch between a declarative model that tracks identity and location and a control plane that is allowed to change location underneath it. The consequence for a state file is that a subsequent plan can see a resource as needing to move back, and the tool's answer may be to re-create it. So the practical guidance is not to run HA-managed guests under this provider until the new API is implemented, and if you already are, to know what the drift looks like before it happens rather than during a change window. The other thing in the section is a good reminder of the general shape of provider work: a hypervisor release that adds an API surface requires provider work before that surface is usable, and the version you pin determines which surfaces you have.

## The default test suite is regression, and acceptance tests need a real cluster

The testing section is short and its honesty is the story. To test the provider you run one make target:

```bash
make test
```

And then there is a sentence that reframes what that means: the tests are limited to regression tests, ensuring backward compatibility. That is a deliberate philosophy rather than a shortfall, and it is defensible for this kind of project. The most damaging failure mode for a provider is not a wrong value in a plan, it is a change that makes existing state unreadable or reinterprets a schema, and a regression suite aimed at backward compatibility targets exactly that risk. What it does not target is correctness against a real hypervisor, and the readme says so. A limited number of acceptance tests live in a directory, mostly covering new functionality built with the newer framework, and they are not run by default because they need a Proxmox environment to exist. They are run with a separate script that requires an environment file in the project root, and the connection is configured through environment variables. So the picture is a fast default suite protecting compatibility, and a slower suite that can create real resources and is run by whoever has a cluster to hand. The example directory is the other half of that story, holding configuration files for data sources and resources covering nodes, storage, users, roles, pools, containers and virtual machines, which is the fastest way to see what the provider actually exposes. There is also a dedicated guide for standing up Proxmox inside a virtual machine so you can run the example against it, which is a generous thing for a project to provide and removes the most common excuse for not trying it.

```bash
virtual_environment_endpoint      = "https://pve.example.com:8006/"
virtual_environment_ssh_username  = "terraform"
virtual_environment_api_token     = "terraform@pve!provider=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
virtual_environment_root_password = "your-root-password"
```

## Two framework implementations in one binary, with 1.0 as the destination

The future work section contains a migration plan and a version number, which together are the most useful forward-looking information in the readme. The provider is built on the second version of Terraform's software development kit, which the readme calls legacy and in maintenance mode. Work has started to migrate to the new plugin framework, with the stated aim of releasing the result as a new major version 1.0. The dependency list is where you can see that this is genuinely in progress rather than aspirational. Both frameworks are present, the older SDK and the newer one, along with the framework's companion libraries for timeouts and for validators, its logging and transport packages, and a multiplexing library whose entire purpose is to serve several provider implementations from one binary. The top-level directories tell the same story from the other side, with one directory holding the legacy implementation, one holding the new framework implementation, and one holding the API client that both use. So this is a staged migration, executed the way a provider migration has to be: old and new code coexisting in a single binary while the resource surface is moved across one at a time. That is the right approach, and it has a consequence you should plan for. The 1.0 release is where the framework change becomes visible to users, and framework changes can affect how state is represented and how values are validated, so a 0.x to 1.0 jump is the point at which state written by your current provider needs attention. Snapshot the state before that upgrade, read the migration notes when they appear, and treat the version number as a scheduled piece of work rather than a surprise.

## Registries, manual binaries, and provenance you can check with gh

Distribution follows the convention for this kind of provider, and the readme names all three routes. The provider is published to the Terraform registry and to the OpenTofu registry, and both are linked, which matters more than it used to because the two tools are diverging and a provider that supports both has to be tested against both. For manual installation you can take the binaries from the releases page. And there is a third option that is worth more attention than it first appears, because the readme says you can use the gh command line tool to verify the provenance of the binaries, and links a page describing the attestations. Signed provenance for a binary that runs inside your planning process with credentials is a real supply-chain control, and the fact that a personal project publishes it is a good sign about how the maintainer thinks about risk. The same thinking shows up in the build tooling, where the release version is a single line in the makefile carrying a marker that a release tool rewrites, and where the pinned linter version carries a marker naming the automation that updates it. The build itself handles the two tools the provider supports by checking whether the OpenTofu binary is present and using it if so, falling back to Terraform otherwise, and it handles Windows separately with a different platform string, an executable extension and a path conversion. The plugin executable is written with its version in the filename, which is what lets a locally built binary be used in place of a registry download, and the example target wires that up by pointing Terraform at a separate command line configuration file and a plugin cache directory before applying. That is the standard way to develop a provider against your own build, and having the example create and then destroy its own resources means a single command leaves nothing behind.

```toml
	github.com/hashicorp/terraform-plugin-mux v0.23.1
	github.com/hashicorp/terraform-plugin-sdk/v2 v2.40.1
	github.com/hashicorp/terraform-plugin-testing v1.16.0
	github.com/pkg/sftp v1.13.11
	github.com/rogpeppe/go-internal v1.16.0
	github.com/skeema/knownhosts v1.3.3
```

## The documentation lives on a personal domain, and the repository is full of agent instructions

A provider's documentation is the product as much as the code is, so where it lives matters. Here it does not live in the repository. The readme points at a documentation site on a personal domain for full usage, and the compatibility, input and architecture documents that exist in the tree are explicitly about development rather than use. That is a defensible choice, because provider documentation with versioned examples and generated reference pages is painful to keep in a repository, and it is also a continuity risk for the same reason the single maintainer is. Two files in the tree address that partially. One is a configuration for a documentation integration service, which suggests the documentation is exposed in a form that code assistants can read, so an assistant can answer questions about this provider from the published docs. The other is a link checker configuration, so the links inside the documentation are verified automatically, which is the kind of small thing that separates documentation that stays accurate from documentation that quietly rots. The repository is unusually well equipped around its own process. There are committed git hooks, a linter configuration, a formatter configuration, a markdown linter configuration, release automation with a manifest and a configuration, an editor configuration, a development container, and a top-level makefile that a contributor reads before touching anything. There are also five separate sets of instructions for coding assistants, at the root and under a hidden directory, in two named assistant formats and a generic one. That is a lot of files for the same purpose, and it tells you something real about how maintenance work on this project is expected to happen in 2026. The example directory and a second examples directory both exist, which is worth a glance before you assume you have found the configuration reference, because one of them is driven by the make targets and the other is documentation snippets.

## Conclusion

This provider is the right choice if your cluster is on Proxmox 9.x and you want infrastructure as code over it, because the support promise is narrow, explicit and current, and a provider that says it will not answer questions about 7.x saves you from discovering that by filing them. Check three things before you write any configuration. Whether you run high availability, because resource management for it is not supported on 9.x yet and the new API for it has not been implemented, and an HA cluster that migrates a guest behind the provider's back is a state drift problem you will meet. How you will supply SSH, since the provider authenticates to the host in addition to the API and the default configuration offers no password fallback, so an agent with an authorised key or an explicit key in the provider block is required from the first plan. And when you will move to 1.0, because the provider is being migrated from the legacy SDK to the plugin framework with a major version as the destination, and state written by a 0.x build is the thing most likely to need attention at that boundary.

## FAQ

### Which Proxmox versions does the provider support?

Proxmox 9.x, currently 9.2, is the compatibility promise. Version 8.x is supported but not tested as a priority and issues specific to it will not be addressed, and 7.x is not supported at all, with the readme stating that 7.x-specific issues will not be addressed either.

### Why does the provider need SSH access in addition to an API token?

The default configuration authenticates to the API with a token and has no password fallback for SSH, so you must have a key agent with a key authorised on the host or set an SSH password or private key in the provider block. The dependencies include an SFTP library and a known-hosts verifier, so the provider authenticates over SSH and verifies the host key as well as talking to the API.

### Can I manage high availability resources with this provider?

Not on 9.x, because that release introduced a new API for high availability resource management which the provider does not support yet. The readme also warns that a guest created with the provider but managed by an HA cluster can be migrated to another node without the provider noticing.

### What does the test suite actually test?

The default suite is limited to regression tests that ensure backward compatibility, run with make test. A limited number of acceptance tests exist in a separate directory for newer functionality, need a real Proxmox environment, and are run with a separate script that requires an environment file in the project root.

### What changes at version 1.0?

The provider is being migrated from the second generation software development kit to the new plugin framework, with 1.0 as the target major version. Both implementations and a multiplexing library are already in the dependencies, so the two coexist in one binary, and the jump is where state written by a 0.x build is most likely to need attention.

## Sources

- [bpg/terraform-provider-proxmox on GitHub](https://github.com/bpg/terraform-provider-proxmox)
- [License: MPL-2.0](https://github.com/bpg/terraform-provider-proxmox/blob/main/LICENSE)
- [Project website](https://bpg.sh/docs/)
- [README](https://github.com/bpg/terraform-provider-proxmox/blob/main/README.md)
- [Releases](https://github.com/bpg/terraform-provider-proxmox/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/bpg-terraform-provider-proxmox
