Pulumi Hetzner Cloud Infrastructure Provisioning

The integration of Pulumi with Hetzner Cloud represents a paradigm shift for engineers moving away from static configuration files toward true Infrastructure as Code (IaC). By leveraging the Pulumi Hetzner Cloud provider, developers can utilize general-purpose programming languages to manage virtual machines, storage, and networking resources. This approach replaces the limitations of domain-specific languages with the full power of software engineering practices, allowing for complex conditional logic, scalable loops, and programmatic resource management. At its core, the Pulumi HCloud provider acts as a wrapper around the Hetzner Cloud SDK, enabling the programmatic definition of cloud resources that are then reconciled against the actual state of the Hetzner Cloud environment.

Provider Architecture and Ecosystem Integration

The Pulumi Hetzner Cloud provider is designed to interact directly with the Hetzner Cloud API, utilizing the official Hetzner Cloud SDK to execute requests. This architecture ensures that any capability available via the SDK is potentially accessible through Pulumi's resource abstractions. The provider is not limited to a single language, reflecting Pulumi's philosophy of language agnosticism.

The available language packages for the Hetzner Cloud provider are detailed in the following table:

Language Package Name / Import Path Installation Method
JavaScript/TypeScript @pulumi/hcloud npm or yarn
Python pulumi-hcloud pip
Go github.com/pulumi/pulumi-hcloud/sdk/go/hcloud go get
.NET Pulumi.HCloud dotnet add package
Java com.pulumi/hcloud Maven/Gradle

The use of these packages allows users to define their infrastructure in a way that integrates seamlessly with their existing CI/CD pipelines. For instance, a developer using TypeScript can use the @pulumi/hcloud package to define a server, while a Python developer can use pulumi-hcloud to achieve the identical result. This versatility ensures that the barrier to entry for utilizing Hetzner Cloud infrastructure is minimized, as it does not require learning a new, proprietary language.

Comprehensive Installation Workflow

To begin deploying resources on Hetzner Cloud using Pulumi, several systemic prerequisites must be met. These requirements ensure that the local environment can communicate with the Pulumi state engine and the Hetzner API.

The necessary prerequisites include:

  • A valid Hetzner Cloud account for resource hosting.
  • The Pulumi CLI installed on the local machine.
  • Node.js (version 20 or later) for those utilizing TypeScript or JavaScript.
  • A configured API token with necessary permissions.

For users on macOS or Linux, the Pulumi CLI can be installed via a shell script:

curl -fsSL https://get.pulumi.com | sh

Windows users should utilize the dedicated installer available at pulumi.com/docs/install. Once the installation process is complete, the operational status of the CLI should be verified by executing the following command:

pulumi version

After verification, the project must be initialized. This process creates the necessary scaffolding for the infrastructure code. For a TypeScript project, the initialization command is:

pulumi new typescript

Alternatively, to accept all default settings and bypass interactive prompts, the following command can be used:

pulumi new typescript -y

This action generates a standardized directory structure:

  • index.ts: The primary entry point where infrastructure code is defined.
  • package.json: Manages project dependencies.
  • tsconfig.json: Configures the TypeScript compiler.
  • Pulumi.yaml: Defines the project name and the runtime environment.

Once the project structure is established, the specific Hetzner Cloud provider must be added to the project. For Node.js environments, this is achieved via npm:

npm install @pulumi/hcloud

Or via yarn:

yarn add @pulumi/hcloud

Authentication and Credential Management

Authentication is a critical layer of the Pulumi-Hetzner integration. Pulumi does not store Hetzner credentials on its own servers; instead, it relies on the Hetzner Cloud SDK to authenticate requests from the local machine to the Hetzner API.

To obtain the necessary credentials, the user must navigate to the Hetzner Cloud console, select the Security menu from the left-hand sidebar, and enter the API tokens tab. A new token is generated by clicking Generate API token. It is imperative that this token is granted both Read and Write permissions to allow Pulumi to not only view the state of the infrastructure but also to modify or create resources.

There are two primary methods for providing this token to Pulumi:

  1. Environment Variables: This method is ideal for ephemeral environments or local testing. The token is passed via the HCLOUD_TOKEN variable.

export HCLOUD_TOKEN=XXXXXXXXXXXXXX

  1. Pulumi Configuration: This method is preferred for teams and multi-user access, as the token is stored alongside the Pulumi stack. To ensure the token is not stored in plain text, the --secret flag must be utilized.

pulumi config set hcloud:token XXXXXXXXXXXXXX --secret

The use of the --secret flag ensures that the token is encrypted, preventing sensitive API keys from being committed to version control in a readable format.

Configuration Parameters and Fine-Tuning

Beyond the authentication token, the Pulumi Hetzner Cloud provider offers several configuration points to optimize how the provider interacts with the API.

The available configuration parameters are:

  • hcloud:token: The API token used for authentication. This can be set via the configuration file or the HCLOUD_TOKEN environment variable.
  • hcloud:endpoint: This optional parameter allows users to override the default API endpoint, which is https://api.hetzner.cloud/v1.
  • hcloud:pollInterval: This setting determines the interval at which the client polls for action completions. The default is 500ms.

The hcloud:pollInterval is particularly important when managing large-scale deployments. If a user encounters rate limiting errors from the Hetzner API, increasing this interval can mitigate the frequency of requests and stabilize the deployment process.

Provisioning Virtual Infrastructure

Once the environment is configured and the API token is set, resources can be provisioned. Pulumi allows for the definition of servers, volumes, networks, firewalls, and load balancers.

To provision a basic virtual server, the index.ts file should be configured with the following code:

```typescript
import * as hcloud from "@pulumi/hcloud";

new hcloud.Server("server", {
serverType: "cx22",
image: "ubuntu-24.04"
});
```

In this implementation, the serverType is set to cx22, which is noted as the smallest and most cost-effective server type available on the platform. The image is specified as ubuntu-24.04. To apply this configuration and create the actual resource in the Hetzner Cloud, the user executes:

pulumi up

After the command completes, the server becomes visible in the Servers section of the Hetzner Cloud console. To avoid ongoing costs when the resource is no longer needed, the server can be removed using the destroy command:

pulumi destroy

For more complex deployments, different values can be applied to meet specific needs. For example, a configuration might use the following specifications:

  • Server name: my-first-server
  • Location: nbg1 (Nuremberg)
  • Server type: cx23
  • OS image: ubuntu-24.04

Advanced Use Cases and Software Deployment

While Pulumi is exceptionally powerful for provisioning the hardware and networking layers of a cloud environment, it is important to distinguish between infrastructure provisioning and software installation. Pulumi and Terraform are dedicated tools for the creation of resources (the "virtual hardware"); they are not intended for the installation of software packages within the operating system of the provisioned server.

Despite this distinction, Pulumi can be used to set up the foundation for various high-performance applications. Examples include:

  • WireGuard VPN Servers: Using Pulumi to spin up and tear down VPN servers on demand to manage costs.
  • frp (Fast Reverse Proxy) Setups: Deploying a server to act as a reverse proxy to expose local home lab services to the internet. frp supports multiple protocols, including TCP, UDP, HTTP, and HTTPS, allowing users to bypass NAT or firewalls by using a server with a public IP address.

The ability to programmatically create these environments allows for a "disposable infrastructure" model, where a server is provisioned for a specific task and then destroyed immediately after, optimizing cost and security.

State Management and Execution

Pulumi manages the lifecycle of infrastructure by maintaining a state file, which serves as the record of what exists in the cloud. This state can be managed in two ways:

  1. Pulumi Cloud: A hosted service that is free for individuals and provides a centralized location for state and collaboration.
  2. Local State: For users who prefer not to use a cloud account, state can be stored locally.

To initialize local state management, the following command is used:

pulumi login --local

This ensures that the record of the infrastructure resides on the local machine. When pulumi up is executed, Pulumi compares the current desired state (defined in the code) with the actual state of the Hetzner Cloud. If a discrepancy is found, Pulumi performs the minimum number of actions necessary to bring the infrastructure into alignment. This idempotent behavior ensures that running the same code multiple times does not result in duplicate resources.

Comparative Analysis of Infrastructure Tooling

The transition to Pulumi for Hetzner Cloud management is particularly beneficial for those building complex infrastructure. Unlike traditional tools that rely on static declarations, Pulumi's use of real programming languages is not a gimmick; it provides genuine advantages for scaling and conditional logic.

The implications of using a real language include:

  • Loops: The ability to provision fifty servers using a simple for loop rather than repeating a block of configuration fifty times.
  • Conditionals: The ability to provision different resources based on the environment (e.g., a smaller server for dev and a larger one for prod).
  • Abstractions: The ability to create custom classes or functions that encapsulate complex infrastructure patterns, which can then be reused across multiple projects.

This programmatic approach transforms infrastructure from a series of manual tasks into a software development process, allowing for the application of version control, unit testing, and code reviews to the very foundation of the cloud environment.

Summary Analysis of the Pulumi-Hetzner Integration

The integration of Pulumi with Hetzner Cloud provides a robust framework for managing modern cloud infrastructure. By abstracting the Hetzner Cloud SDK into a multi-language provider, Pulumi enables the use of TypeScript, Python, Go, .NET, and Java for infrastructure management. This flexibility allows organizations to align their infrastructure code with their primary application code, reducing the cognitive load on developers.

The operational flow—from installation and API token generation to the execution of pulumi up—is streamlined, though it requires a strict adherence to security practices, specifically the use of --secret when handling API tokens. The capacity to manage not only servers but also load balancers, firewalls, and networks ensures that the entirety of the Hetzner Cloud ecosystem can be orchestrated from a single codebase.

Furthermore, the distinction between resource provisioning and software configuration remains a critical architectural boundary. While Pulumi handles the virtualized hardware, the subsequent software layer remains the responsibility of configuration management tools or custom scripts. However, the speed and efficiency with which Pulumi can deploy the underlying hardware make it an ideal partner for high-performance applications like WireGuard or frp, where the infrastructure is often transient.

Ultimately, the shift toward a programmatic infrastructure model provided by Pulumi allows for a level of scalability and complexity that is unattainable with traditional configuration tools. By treating infrastructure as software, users can achieve higher reliability, better cost control, and faster deployment cycles within the Hetzner Cloud environment.

Sources

  1. Pulumi
  2. PyPI
  3. rasc.ch Blog - Pulumi Hetzner
  4. rasc.ch Blog - Pulumi FRP
  5. Hetzner Community

Related Posts