Goal
Provide a Terraform provider for Beszel, a lightweight self-hosted server monitoring tool, so that hubs, systems, users, alerts and user settings can be declared and managed as code instead of clicked together through the web UI. No Terraform provider existed for Beszel before this one.
Stack
The provider is written in Go using the Terraform Plugin Framework. Beszel exposes its data through a PocketBase-backed REST API, so the schema was derived directly from Beszel’s own source, its migrations and collection definitions, rather than from documentation alone. Testing combines unit tests against an httptest server with acceptance tests run against a real Beszel hub via Docker Compose. Documentation is generated with terraform-plugin-docs, and releases are cut with GoReleaser on tag push.
Key Decisions
The provider models beszel_system, beszel_user, beszel_alert, beszel_user_settings and beszel_universal_token, each with its own real complications: agent-written read-only fields on systems, a write-only password field on the auth collection with no read-back, a composite natural key used instead of PocketBase’s own record id, and singleton upsert semantics for user settings. Universal tokens carry their own quirk: Beszel scopes that endpoint to the caller’s own record and forbids superuser callers outright, so the client impersonates the target user through PocketBase’s superuser impersonation route before calling it.
The collections Beszel’s own agents populate, such as stats, history and container telemetry, stay out of scope. Terraform is a poor fit for data a separate live process owns and continuously writes, and modeling it would mean fighting the agent for control.
Because regular Beszel users cannot create or list systems arbitrarily, the provider requires superuser credentials to function. That is documented as a real constraint rather than smoothed over.
Outcome
Released as v0.1.0 on the public Terraform Registry as the first Terraform provider available for Beszel, with v0.2.0 following shortly after to add the universal token resource, a full worked getting-started guide, and a CHANGELOG.
Further Details
The build followed a staged plan carried out with Claude Code: provider setup and scaffolding, core framework and shared client logic, individual resources, CI/CD, then release tooling. Reviewing the finished repository against Beszel’s own source, rather than trusting the generated code at face value, was the deciding step before making it public.
