[{"data":1,"prerenderedAt":242},["ShallowReactive",2],{"\u002Fblog\u002Fk8s-on-hcloud":3,"\u002Fblog\u002Fk8s-on-hcloud-surround":240},{"id":4,"title":5,"authors":6,"badge":12,"body":14,"date":228,"description":229,"extension":230,"image":231,"meta":234,"navigation":235,"path":236,"seo":237,"stem":238,"__hash__":239},"posts\u002F1.blog\u002F1.k8s-on-hcloud\u002Findex.md","Kubernetes on a Hetzner Private Network",[7],{"name":8,"to":9,"avatar":10},"Tessellative Solutions","https:\u002F\u002Ftessellative.com",{"src":11},"\u002Ficons\u002Ftessellative_icon_round.svg",{"label":13},"IaC, Kubernetes, Hetzner Cloud, Cloud Native, Terraform, OpenTofu, Kubespray",{"type":15,"value":16,"toc":214},"minimark",[17,22,26,30,52,56,59,62,76,79,90,93,101,105,119,123,132,135,140,143,165,169,172,204,208,211],[18,19,21],"h2",{"id":20},"secure-kubernetes-on-hetzner-cloud","Secure Kubernetes on Hetzner Cloud",[23,24,25],"p",{},"Running Kubernetes in the cloud is powerful — but exposing control-plane and worker nodes directly to the internet is risky. This full IaC (Infrastructure as Code) shows a clean, maintainable way to deploy a Kubernetes cluster on Hetzner Cloud where all nodes live exclusively on a private network. sEvery infrastructure element is defined as code using Terraform (OpenTofu) and Kubespray config.",[18,27,29],{"id":28},"why-this-setup-matters","Why This Setup Matters",[31,32,33,37,40,43,46,49],"ul",{},[34,35,36],"li",{},"Security first: No public IPs on Kubernetes nodes → reduced attack surface",[34,38,39],{},"Clean separation: administrator access via dedicated jumphost, outbound internet via gateway, inbound traffic via load balancer",[34,41,42],{},"Fully automated: Infrastructure as Code + Configuration as Code",[34,44,45],{},"Clean and Maintainable repository structure",[34,47,48],{},"Cost-effective: Leverages Hetzner’s affordable cloud resources",[34,50,51],{},"Repeatable: Clone, re-configure, deploy N+1",[18,53,55],{"id":54},"architecture-overview","Architecture Overview",[23,57,58],{},"The setup consists of three layers:",[23,60,61],{},"Infrastructure (1-infra)",[31,63,64,67,70,73],{},[34,65,66],{},"Private Hetzner Cloud network",[34,68,69],{},"Jumphost (public IP + SSH access)",[34,71,72],{},"NAT Network gateway (public IP for NAT\u002Foutbound traffic)",[34,74,75],{},"Hetzner Load Balancer (public IP, DNS, TLS termination)",[23,77,78],{},"Platform (2-platform)",[31,80,81,84,87],{},[34,82,83],{},"3-node Kubernetes cluster (all nodes on private IPs only)",[34,85,86],{},"Deployed automatically with Kubespray",[34,88,89],{},"Cilium as CNI",[23,91,92],{},"Applications (3-apps)",[31,94,95,98],{},[34,96,97],{},"HAProxy ingress controller",[34,99,100],{},"Example deployment  (e.g., a simple example.com app) routed through the load balancer",[18,102,104],{"id":103},"prerequisites","Prerequisites",[31,106,107,110,113,116],{},[34,108,109],{},"A Hetzner Cloud account and project",[34,111,112],{},"Terraform \u002F OpenTofu installed",[34,114,115],{},"Hetzner API token with read & write permissions",[34,117,118],{},"Basic familiarity with SSH, Kubernetes, ansible, Kubespray",[18,120,122],{"id":121},"setup-overview","Setup Overview",[23,124,125,126],{},"Clone the repo: ",[127,128,129],"a",{"href":129,"rel":130},"https:\u002F\u002Fcodeberg.org\u002Ftessellative\u002Fk8s-hetzner-private-net.git",[131],"nofollow",[23,133,134],{},"Follow the setup commands in staging order in the README.md files, starting at the root level.",[136,137,139],"h3",{"id":138},"setup-order","Setup Order",[23,141,142],{},"The repo is nicely split:",[31,144,145,148,151,154,157],{},[34,146,147],{},".\u002F1-infra\u002Fterraform\u002F → Run Terraform to create the network, jumphost, gateway, load balancer and the k8s node VMs.",[34,149,150],{},".\u002F2-platform\u002F → Deploy the 3-node Kubernetes cluster using Kubespray. Access the cluster via sshuttle over the jumphost.",[34,152,153],{},".\u002F3-apps\u002F → Deploy the ingress controller and the sample application",[34,155,156],{},"Update your \u002Fetc\u002Fhosts file with the loadbalancer public IP and the DNS: test.example.com",[34,158,159,160,164],{},"Open the ",[127,161,162],{"href":162,"rel":163},"http:\u002F\u002Ftest.example.com",[131]," in the browser (This)",[136,166,168],{"id":167},"custom-dns-with-tls-certificate","Custom DNS with TLS Certificate",[23,170,171],{},"This demo can be run behind a proper non-reserved domain with TLS certificates set up!\nChange and configure the following with your domain",[31,173,174,193],{},[34,175,176,177],{},".\u002F1-infra\u002Fterraform\u002F5-load-balancer.tf\n",[31,178,179,182,190],{},[34,180,181],{},"Change the LB to serve TLS on port 443 -> resource \"hcloud_load_balancer_service\" \"example-k8s01-lb-service\"",[34,183,184,185,189],{},"Configure the ",[186,187,188],"strong",{},"http.certificates"," section -> resource \"hcloud_load_balancer_service\" \"example-k8s01-lb-service\"",[34,191,192],{},"Set the proper DNS name at -> resource \"hcloud_managed_certificate\" \"custom-domain-com\"",[34,194,195,196],{},"1-infra\u002Fterraform\u002F6-dns-example.com.tf\n",[31,197,198,201],{},[34,199,200],{},"Add the new DNS Zone -> resource \"hcloud_zone\" \"custom-domain-com\"",[34,202,203],{},"Add your DNS record to the zone -> resource \"hcloud_zone_rrset\" \"A-custom-domain-com\"",[18,205,207],{"id":206},"final-thoughts","Final Thoughts",[23,209,210],{},"This project is a great starting template for anyone who wants to run Kubernetes on Hetzner without exposing nodes publicly. It demonstrates good practices: separation of concerns, private networking and full automation.",[23,212,213],{},"Happy deploying! 🚀",{"title":215,"searchDepth":216,"depth":216,"links":217},"",2,[218,219,220,221,222,227],{"id":20,"depth":216,"text":21},{"id":28,"depth":216,"text":29},{"id":54,"depth":216,"text":55},{"id":103,"depth":216,"text":104},{"id":121,"depth":216,"text":122,"children":223},[224,226],{"id":138,"depth":225,"text":139},3,{"id":167,"depth":225,"text":168},{"id":206,"depth":216,"text":207},"2026-04-03T00:00:00.000Z","Proof of Concept IaC for managing a Kubernetes cluster on Hetzner Cloud","md",{"src":232,"headerClass":233},"\u002Fblog\u002Fk8s-on-hcloud\u002Fcover.webp","aspect-[16\u002F10]",{},true,"\u002Fblog\u002Fk8s-on-hcloud",{"title":5,"description":229},"1.blog\u002F1.k8s-on-hcloud\u002Findex","wnU2nwjjhGCFQ4YogQhc8ngsVyYkvAJNcG711IiwpUw",[241,241],null,1775246535512]