Infrastructure-as-Code for provisioning and configuring cloud servers using Terraform & Ansible
This repository contains the complete Infrastructure-as-Code (IaC) setup for my personal cloud environment. Terraform provisions the servers and manages DNS, while Ansible handles the server configuration.
The workloads running on this cluster are managed via my Kubernetes-Flux repository.
Server-Infrastructure/
├── main.tf # Hetzner Cloud server resources (masters & nodes)
├── cloudflare.tf # Cloudflare DNS records
├── inventory.tf # Auto-generates Ansible inventory from provisioned IPs
├── provider.tf # Terraform provider config (hcloud + cloudflare)
├── variables.tf # Input variables (API keys, SSH key, zone IDs)
├── output.tf # Terraform outputs
├── templates/
│ └── hosts.tpl # Ansible inventory template
└── ansible/
├── ansible.cfg # Ansible configuration (inventory path, callbacks)
├── requirements.yml # Ansible Galaxy collection dependencies
├── site.yml # Main playbook
└── roles/ # configuration for master and worker k3s nodes
Terraform handles everything infrastructure-level: It provisions Hetzner Cloud VMs (control-plane masters and worker nodes), configures Cloudflare DNS records, and auto-generates the Ansible inventory file by rendering the hosts.tpl template with the real IP addresses of the freshly created servers.
Ansible takes the provisioned vms and uses the automaticaly generated inventory to setup k3s.
terraform apply
├── Provisions Hetzner Cloud VMs (masters + nodes)
├── Configures Cloudflare DNS records
└── Writes ansible/inventory/hosts.cfg ──► ansible-playbook ...
└── Configures servers
| Tool | Purpose |
|---|---|
| Terraform | Provisions cloud infrastructure declaratively |
| Hetzner Cloud | Cloud provider for VMs (masters & worker nodes) |
| Cloudflare | DNS management |
| Ansible | Server configuration management |
| K3s | Lightweight Kubernetes distribution deployed on the VMs |
- Terraform >= 0.14
- Ansible
- A Hetzner Cloud account & API token
- A Cloudflare account with a configured zone
Create a terraform.tfvars file (excluded from Git via .gitignore):
HCLOUD_KEY = "your-hetzner-api-token"
SSH_KEY = "your-ssh-key"
CLOUDFLARE_KEY = "your-cloudflare-api-token"
CLOUDFLARE_ZONE_ID = "your-cloudflare-zone-id"
CLOUDFLARE_ACCOUNT_ID = "your-cloudflare-account-id"# Initialize Terraform providers
terraform init
# Preview the planned changes
terraform plan
# Apply — provisions servers and DNS, generates Ansible inventory
terraform applyOnce terraform apply completes, the Ansible inventory at ansible/inventory/hosts.cfg is ready:
# Install required Ansible collections
ansible-galaxy collection install -r ansible/requirements.yml
# Run the playbook
ansible-playbook ansible/site.ymlThe kubeconfig for the new cluster is fetched to ~/.kube/k3s.yaml. To merge it into your existing config:
KUBECONFIG=~/.kube/config:~/.kube/k3s.yaml kubectl config view --flatten > ~/.kube/configAll sensitive values (API keys, SSH keys, zone IDs) are defined as sensitive Terraform variables and must be supplied via terraform.tfvars or environment variables. They are never committed to the repository.
- Kubernetes-Flux — GitOps configuration for the workloads running on this infrastructure