krustyplanet.org/terraform/main.tf

142 lines
3.8 KiB
HCL

###############################################################################
# main.tf — KrustyPlanet VPS on Hetzner Cloud
# Stack: Hetzner Cloud + Ubuntu 24.04 + nginx + contact-api + SSL
###############################################################################
terraform {
required_version = ">= 1.6.0"
required_providers {
hcloud = {
source = "hetznercloud/hcloud"
version = "~> 1.47"
}
}
}
provider "hcloud" {
token = var.hcloud_token
}
###############################################################################
# SSH Key
###############################################################################
resource "hcloud_ssh_key" "krustyplanet" {
name = "${var.project_name}-key"
public_key = var.ssh_public_key
}
###############################################################################
# Network (private)
###############################################################################
resource "hcloud_network" "krustyplanet" {
name = "${var.project_name}-network"
ip_range = "10.0.0.0/16"
}
resource "hcloud_network_subnet" "krustyplanet" {
network_id = hcloud_network.krustyplanet.id
type = "cloud"
network_zone = var.network_zone
ip_range = "10.0.1.0/24"
}
###############################################################################
# Firewall
###############################################################################
resource "hcloud_firewall" "krustyplanet" {
name = "${var.project_name}-firewall"
# SSH admin — always restricted to your IPs
rule {
direction = "in"
protocol = "tcp"
port = "22"
source_ips = var.ssh_allowed_ips
}
# HTTP
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"]
}
# Apply to the server
apply_to {
server = hcloud_server.krustyplanet.id
}
}
###############################################################################
# Server
###############################################################################
resource "hcloud_server" "krustyplanet" {
name = "${var.project_name}-server"
server_type = var.server_type
image = "ubuntu-24.04"
location = var.location
ssh_keys = [hcloud_ssh_key.krustyplanet.id]
network {
network_id = hcloud_network.krustyplanet.id
ip = "10.0.1.10"
}
user_data = templatefile("${path.module}/cloud-init.yaml.tpl", {
project_name = var.project_name
node_version = var.node_version
})
labels = {
project = var.project_name
role = "web"
}
depends_on = [hcloud_network_subnet.krustyplanet]
}
###############################################################################
# Floating IP (stable public IP across rebuilds)
###############################################################################
resource "hcloud_floating_ip" "krustyplanet" {
type = "ipv4"
home_location = var.location
description = "${var.project_name} floating IP"
}
resource "hcloud_floating_ip_assignment" "krustyplanet" {
floating_ip_id = hcloud_floating_ip.krustyplanet.id
server_id = hcloud_server.krustyplanet.id
}
###############################################################################
# Volume (persistent data — survives server rebuilds)
###############################################################################
resource "hcloud_volume" "krustyplanet_data" {
name = "${var.project_name}-data"
size = var.volume_size_gb
location = var.location
format = "ext4"
}
resource "hcloud_volume_attachment" "krustyplanet_data" {
volume_id = hcloud_volume.krustyplanet_data.id
server_id = hcloud_server.krustyplanet.id
automount = true
}