Post-Tyranny-Tech-Infrastru.../tofu/main.tf
Pieter 79635eeece feat: Add private network architecture with NAT gateway
Enable deployment of client servers without public IPs using private
network (10.0.0.0/16) with NAT gateway via edge server.

## Infrastructure Changes:

### Terraform (tofu/):
- **network.tf**: Define private network and subnet (10.0.0.0/24)
  - NAT gateway route through edge server
  - Firewall rules for client servers

- **main.tf**: Support private-only servers
  - Optional public_ip_enabled flag per client
  - Dynamic network block for private IP assignment
  - User-data templates for public vs private servers

- **user-data-*.yml**: Cloud-init templates
  - Private servers: Configure default route via NAT gateway
  - Public servers: Standard configuration

- **dns.tf**: Update DNS to support edge routing
  - Client domains point to edge server IP
  - Wildcard DNS for subdomains

- **variables.tf**: Add private_ip and public_ip_enabled options

### Ansible:
- **deploy.yml**: Add diun and kuma roles to deployment

## Benefits:
- Cost savings: No public IP needed for each client
- Scalability: No public IP exhaustion limits
- Security: Clients not directly exposed to internet
- Centralized SSL: All TLS termination at edge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-20 19:06:19 +01:00

94 lines
2.2 KiB
HCL

# Provider Configuration
provider "hcloud" {
token = var.hcloud_token
}
# hcloud provider handles both Cloud and DNS resources
# Per-Client SSH Keys
resource "hcloud_ssh_key" "client" {
for_each = var.clients
name = "client-${each.key}-deploy-key"
public_key = file("${path.module}/../keys/ssh/${each.key}.pub")
}
# Firewall Rules
resource "hcloud_firewall" "client_firewall" {
name = "client-default-firewall"
# SSH (restricted - add your management IPs here)
rule {
direction = "in"
protocol = "tcp"
port = "22"
source_ips = [
"0.0.0.0/0", # CHANGE THIS: Replace with your management IP
"::/0"
]
}
# HTTP (for Let's Encrypt challenge)
rule {
direction = "in"
protocol = "tcp"
port = "80"
source_ips = [
"0.0.0.0/0",
"::/0"
]
}
# HTTPS
rule {
direction = "in"
protocol = "tcp"
port = "443"
source_ips = [
"0.0.0.0/0",
"::/0"
]
}
}
# Client VPS Instances
resource "hcloud_server" "client" {
for_each = var.clients
name = each.key
server_type = each.value.server_type
image = "ubuntu-24.04"
location = each.value.location
ssh_keys = [hcloud_ssh_key.client[each.key].id]
firewall_ids = [hcloud_firewall.client_firewall.id]
labels = {
client = each.key
role = "app-server"
# Note: labels can't contain special chars, store apps list separately if needed
}
# Enable backups if requested
backups = var.enable_snapshots
# Public network configuration (can be disabled for private-only servers)
public_net {
ipv4_enabled = lookup(each.value, "public_ip_enabled", true)
ipv6_enabled = lookup(each.value, "public_ip_enabled", true)
}
# Private network (required for servers without public IP)
dynamic "network" {
for_each = lookup(each.value, "private_ip", null) != null ? [1] : []
content {
network_id = hcloud_network.private.id
ip = each.value.private_ip
}
}
# User data for initial setup
user_data = lookup(each.value, "public_ip_enabled", true) == false ? templatefile("${path.module}/user-data-private.yml", {
hostname = each.key
}) : templatefile("${path.module}/user-data-public.yml", {
hostname = each.key
})
}