Setting up Kubernetes environments doesn’t have to be expensive or complicated. With Hetzner Cloud’s affordable pricing, Talos Linux’s security-focused immutable OS, and KSail’s unified tooling, you can have a cluster running in minutes. This post walks through the complete setup.
- Why Hetzner + Talos + KSail?
- Step 1: Create a Hetzner Account
- Step 2: Create a Hetzner Project
- Step 3: Generate an API Token
- Step 4: Export the API Token
- Step 5: Install KSail
- Step 6: Scaffold Your Cluster Project
- Step 7: Create the Cluster
- Step 8: Working with Your Cluster
- Step 9: Deploying Workloads
- Cleaning Up
- Cost Considerations
- What’s Next
Why Hetzner + Talos + KSail?
Hetzner Cloud offers some of the most affordable cloud VPS servers in the industry. A capable cx23 server (2 vCPU, 4GB RAM) costs around €3.74/month — significantly cheaper than equivalent offerings from AWS, GCP, or Azure.
Talos Linux is a minimal, immutable operating system designed specifically for Kubernetes. There’s no SSH, no shell, no package manager — just the Talos API and Kubernetes. This dramatically reduces the attack surface and eliminates configuration drift.
KSail brings it all together with a single binary that handles cluster provisioning, GitOps setup, and workload management. Instead of juggling hcloud, talosctl, kubectl, helm, and flux commands, you use one consistent interface.
Step 1: Create a Hetzner Account
If you don’t already have a Hetzner account:
- Go to Hetzner Cloud Console
- Click “Register” and complete the signup process
- Verify your email and complete any required identity verification
Hetzner has documentation for getting started: Account Getting Started Guide.
Step 2: Create a Hetzner Project
Projects in Hetzner Cloud are organizational units that contain your resources (servers, networks, load balancers, etc.). Each project has its own API tokens and billing.
- Log into the Hetzner Cloud Console
- Click “New Project” in the sidebar
- Name your project (e.g., “kubernetes-dev” or “my-homelab”)
- Click “Create”
Step 3: Generate an API Token
KSail needs an API token to provision and manage Hetzner Cloud resources.
- In your project, go to Security → API Tokens
- Click Generate API Token
- Name the token (e.g., “ksail-cluster-management”)
- Select Read & Write permissions — KSail needs to create and delete servers
- Click Generate API Token
- Copy the token immediately — you won’t be able to see it again!
For more details, see Hetzner’s Generating API Token Guide.
Step 4: Export the API Token
KSail reads the Hetzner API token from the HCLOUD_TOKEN environment variable. Add it to your shell configuration:
# For the current session
export HCLOUD_TOKEN="your-api-token-here"
# To persist across sessions, add to your shell config
echo 'export HCLOUD_TOKEN="your-api-token-here"' >> ~/.zshrc # or ~/.bashrc
source ~/.zshrc
You can verify the token is set:
echo $HCLOUD_TOKEN | head -c 10 # Should show first 10 characters
Step 5: Install KSail
KSail is distributed as a single binary. The easiest installation method is via Homebrew:
brew install --cask devantler-tech/tap/ksail
Alternatively, if you have Go installed:
go install github.com/devantler-tech/ksail/v5@latest
Verify the installation:
ksail --version
Step 6: Scaffold Your Cluster Project
KSail’s init command scaffolds a complete project structure. For a basic Talos cluster on Hetzner with Cilium CNI:
mkdir my-cluster && cd my-cluster
ksail cluster init --distribution Talos --provider Hetzner --cni Cilium
This creates ksail.yaml (cluster configuration), talos/ (Talos configs), and k8s/ (your Kubernetes manifests).
For GitOps workflows, add a GitOps engine and external registry:
ksail cluster init \
--distribution Talos \
--provider Hetzner \
--cni Cilium \
--gitops-engine Flux \
--local-registry '${GITHUB_USER}:${GITHUB_TOKEN}@ghcr.io/your-org/your-cluster'
This configures Flux to sync manifests from GitHub Container Registry. See Step 9: Deploying Workloads for the full GitOps workflow.
For all available flags and configuration options, see the KSail documentation:
- CLI flags reference — All
cluster initoptions - ksail.yaml reference — Configuration file schema
- Features overview — CNI, CSI, GitOps, and more
Step 7: Create the Cluster
With your configuration ready, create the cluster:
ksail cluster create
This command:
- Creates servers in Hetzner Cloud
- Configures the private network
- Bootstraps Talos Linux on each node
- Initializes the Kubernetes cluster
- Installs your selected CNI, CSI, and other components
- Configures your local kubeconfig
- Configures your local talosconfig
The process takes 3-5 minutes depending on your cluster size.
You can watch the progress as KSail outputs status updates for each stage.
Step 8: Working with Your Cluster
Once your cluster is running, KSail provides commands for common operations:
ksail cluster info # Show cluster status
ksail cluster list # List all KSail-managed clusters
ksail cluster connect # Open K9s for interactive management
ksail cluster stop # Stop the cluster
ksail cluster start # Start a stopped cluster
Your kubeconfig is automatically configured, so standard kubectl commands work too.
For the full command reference, see Cluster Commands.
Step 9: Deploying Workloads
KSail wraps kubectl and GitOps operations under the workload command. For cloud clusters like Hetzner, you have two main options for deploying workloads.
Option A: Direct kubectl Workflow
The simplest approach applies manifests directly to the cluster:
ksail workload apply -k ./k8s # Apply Kustomize manifests
ksail workload get pods # Check pod status
ksail workload logs deployment/my-app # View logs
This works well for quick iterations but doesn’t provide GitOps benefits like drift detection and automatic reconciliation.
Option B: GitOps with External Registry
For cloud clusters without a local Docker registry, you can use an external OCI registry like GitHub Container Registry (ghcr.io). This enables full GitOps workflows with Flux or ArgoCD.
Step 1: Create a GitHub Personal Access Token
- Go to GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)
- Create a token with
write:packagesandread:packagesscopes - Export the credentials:
export GITHUB_USER="your-username"
export GITHUB_TOKEN="ghp_your-token-here"
Step 2: Initialize with GitOps and External Registry
When scaffolding your cluster, specify the GitOps engine and external registry:
ksail cluster init \
--distribution Talos \
--provider Hetzner \
--cni Cilium \
--gitops-engine Flux \
--local-registry '${GITHUB_USER}:${GITHUB_TOKEN}@ghcr.io/your-org/your-cluster'
The --local-registry flag accepts the format [user:pass@]host[:port][/path]. Environment variable placeholders like ${GITHUB_TOKEN} are expanded at runtime, keeping credentials out of your config files.
Step 3: Create the Cluster
ksail cluster create
This installs Flux and configures it to sync from your external registry.
Step 4: Push and Reconcile Workloads
# Package manifests and push to registry
ksail workload push
# Trigger GitOps reconciliation
ksail workload reconcile
The push command packages your k8s/ directory as an OCI artifact and pushes it to ghcr.io. Flux then pulls and applies the manifests automatically.
Tip: You can also set the registry via environment variable:
KSAIL_REGISTRY='ghcr.io/org/repo' ksail workload push
For the full workload command reference, see Workload Commands.
Cleaning Up
When you’re done with the cluster:
ksail cluster delete
This removes:
- All Hetzner Cloud servers
- The private network
- Placement groups
- Local kubeconfig entries
- Local talosconfig entries
Warning: This is destructive and cannot be undone. All data in the cluster will be lost.
Cost Considerations
A minimal development setup (1 control plane) using a cx23 server costs under €4/month.
For a more robust setup (3 control planes + 2 workers) using cx23 servers:
| Component | Monthly Cost |
|---|---|
| 3x cx23 control planes | €11.22 |
| 2x cx23 workers | €7.48 |
| Private network | Free |
| Total | ~€18.70/month |
This is remarkably affordable for a Kubernetes development cluster.
What’s Next
Explore the KSail documentation for advanced topics including secret management with SOPS, mirror registries, and GitOps workflows.
Planned: Production-Grade Features
Integration with Hetzner Cloud Controller Manager and Hetzner Cloud CSI Driver is planned for future releases. This will enable:
- Cloud Load Balancers: Automatic provisioning of Hetzner Load Balancers for Kubernetes Services of type
LoadBalancer - Persistent Storage: Dynamic provisioning of Hetzner Cloud Volumes for PersistentVolumeClaims
These integrations will make KSail clusters on Hetzner production-grade, suitable for running real workloads beyond development.
Feedback Welcome
This is the first iteration of Hetzner Cloud support in KSail. If you encounter bugs or find missing features, please open an issue on GitHub. Your feedback helps improve the tool for everyone.
A Note on Cloud Provider Support
Testing and maintaining cloud provider integrations comes with ongoing infrastructure costs. Hetzner is supported because I use it for my own homelab and want to manage it via KSail. Additional cloud providers (AWS, GCP, Azure, etc.) will not be added without sponsorship to cover testing costs.
If you’d like to see your preferred cloud provider supported, consider sponsoring the project on GitHub.
This blog post was written with the assistance of GitHub Copilot and Claude Opus 4.5. The content is based on real-world experience running Talos development clusters on Hetzner Cloud.