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