Files
todo-hetzner/infra/main.tf
T
cole-maxwell1 1382c42803 feat: add Hetzner-hosted todo application stack
Implement the server-rendered Go todo application with PostgreSQL persistence, Tailwind styling, health checks, and test coverage.

Provision production and staging infrastructure with OpenTofu, including private networking, static IPs, Object Storage backups, and load balancing.

Configure Rocky Linux hosts with Ansible, rootless Podman, PostgreSQL, WAL-G backup automation, staging restores, and generated inventory.
2026-08-06 21:34:56 -05:00

141 lines
3.1 KiB
Terraform

provider "hcloud" {
token = var.hcloud_token
}
provider "aws" {
access_key = var.s3_access_key
secret_key = var.s3_secret_key
region = var.s3_region
skip_credentials_validation = true
skip_metadata_api_check = true
skip_region_validation = true
skip_requesting_account_id = true
s3_use_path_style = true
endpoints {
s3 = var.s3_endpoint
}
}
resource "hcloud_network" "main" {
name = "${var.project_name}-network"
ip_range = "10.0.0.0/16"
}
resource "hcloud_network_subnet" "main" {
network_id = hcloud_network.main.id
type = "cloud"
network_zone = var.network_zone
ip_range = "10.0.1.0/24"
}
resource "hcloud_firewall" "nodes" {
name = "${var.project_name}-nodes"
rule {
direction = "in"
protocol = "tcp"
port = "22"
source_ips = var.ssh_source_cidrs
}
rule {
direction = "in"
protocol = "tcp"
port = "8080"
source_ips = [hcloud_network.main.ip_range]
}
rule {
direction = "in"
protocol = "icmp"
source_ips = [
"0.0.0.0/0",
"::/0",
]
}
}
module "prod" {
source = "./modules/compute"
name = "${var.project_name}-prod"
server_type = var.server_type
location = var.server_location
ssh_key_ids = var.ssh_key_ids
firewall_ids = [hcloud_firewall.nodes.id]
network_id = hcloud_network.main.id
private_ip = var.prod_private_ip
environment = "prod"
depends_on = [hcloud_network_subnet.main]
}
module "staging" {
source = "./modules/compute"
name = "${var.project_name}-staging"
server_type = var.server_type
location = var.server_location
ssh_key_ids = var.ssh_key_ids
firewall_ids = [hcloud_firewall.nodes.id]
network_id = hcloud_network.main.id
private_ip = var.staging_private_ip
environment = "staging"
depends_on = [hcloud_network_subnet.main]
}
module "storage" {
source = "./modules/storage"
bucket_name = var.bucket_name
}
resource "hcloud_load_balancer" "app" {
name = "${var.project_name}-lb"
load_balancer_type = "lb11"
location = var.server_location
algorithm {
type = "round_robin"
}
}
resource "hcloud_load_balancer_network" "app" {
load_balancer_id = hcloud_load_balancer.app.id
network_id = hcloud_network.main.id
depends_on = [hcloud_network_subnet.main]
}
resource "hcloud_load_balancer_target" "prod" {
type = "server"
load_balancer_id = hcloud_load_balancer.app.id
server_id = module.prod.server_id
use_private_ip = true
depends_on = [
hcloud_load_balancer_network.app,
module.prod,
]
}
resource "hcloud_load_balancer_service" "http" {
load_balancer_id = hcloud_load_balancer.app.id
protocol = "http"
listen_port = 80
destination_port = 8080
http {
sticky_sessions = false
}
health_check {
protocol = "http"
port = 8080
interval = 15
timeout = 10
retries = 3
http {
path = "/healthz"
status_codes = ["200"]
}
}
}