iac/terraform
Sergei Poljanski e5322cbac2 terraform: never replace a running server
hcloud replaces a server when user_data, image or ssh_keys change, and
cloud-init only runs at first boot anyway. An edit to cloud-init, like
adding a user, would therefore plan the destruction of a production
machine. Ignore changes to those three attributes and set
prevent_destroy on both servers, so cloud-init describes a rebuild and
nothing else.

Add user zerrtika to cloud-init to match the servers; the user was
created on them by playbook 04.

Assisted-by: Claude:fable-5-2
2026-11-12 06:47:08 +04:00
..
cloud-init terraform: never replace a running server 2026-11-12 06:47:08 +04:00
.gitignore terraform 2025-11-01 13:43:31 +02:00
dns.tf ansible 2025-11-01 22:46:38 +02:00
firewall.tf terraform 2025-11-01 13:43:31 +02:00
keys.tf terraform 2025-11-01 13:43:31 +02:00
outputs.tf terraform 2025-11-01 13:43:31 +02:00
providers.tf terraform 2025-11-01 13:43:31 +02:00
README.md terraform: never replace a running server 2026-11-12 06:47:08 +04:00
s3.tf terraform 2025-11-01 13:43:31 +02:00
servers.tf terraform: never replace a running server 2026-11-12 06:47:08 +04:00
terraform.tfvars.example terraform 2025-11-01 13:43:31 +02:00
variables.tf terraform 2025-11-01 13:43:31 +02:00
vpc.tf terraform 2025-11-01 13:43:31 +02:00

ASXP.IO Infrastructure

Hetzner Cloud infrastructure managed via Terraform.

Servers

  • asxpio-ops (2 vCPU, 4GB) - Traefik, Forgejo, app stacks
  • asxpio-services (CX43: 8 vCPU, 16GB) - CI runner, game servers, SillyTavern

Both servers carry prevent_destroy and ignore changes to user_data, image and ssh_keys: cloud-init only runs at first boot, and hcloud would otherwise replace a running server when those change. Edits to cloud-init/*.yaml therefore describe a rebuild, not the live machine; day-to-day configuration is in ../ansible.

Storage (S3-compatible)

Terraform State:

  • asxpio-terraform-main (hel1)
  • asxpio-terraform-repl (fsn1)

Backups:

  • asxpio-backups-main (hel1)
  • asxpio-backups-repl (fsn1)

Immich (buckets kept, service not running):

  • asxpio-immich-main (hel1)
  • asxpio-immich-repl (fsn1)

Network

  • VPC: 10.10.0.0/20
  • WireGuard VPN: 10.20.0.0/24
  • IPv4 + IPv6 enabled

Cost

Item Monthly
ops €3.71
services CX43 €11.15
IPv4 (2x) €1.24
S3 (1TB) €6.19
S3 1TB Traffic €1.24
Total €22.29

Setup

1. Initialize

terraform init

2. Configure secrets

Edit terraform.tfvars:

hcloud_token = "your-token"
s3_access_key = "your-key"
s3_secret_key = "your-secret"
s3_endpoint_hel1 = "hel1.your-objectstorage.com"
s3_endpoint_fsn1 = "fsn1.your-objectstorage.com"

3. Deploy

terraform plan
terraform apply

4. Enable S3 backend (optional)

After buckets are created:

# Set credentials
export AWS_ACCESS_KEY_ID="your-key"
export AWS_SECRET_ACCESS_KEY="your-secret"

# Or use ~/.aws/credentials file
mkdir -p ~/.aws
cat > ~/.aws/credentials <<EOF
[default]
aws_access_key_id = your-key
aws_secret_access_key = your-secret
EOF

# Uncomment backend in providers.tf
# Then migrate state
terraform init -migrate-state

DNS Management

Current: Managed manually via hcloud CLI

Zones: asxp.io (61604), czsk.it (61606), childfr.ee (61605)

TODO: Migrate to Terraform-managed DNS when provider v1.54.0+ is available:

# Upgrade provider in providers.tf
hcloud = {
  source  = "hetznercloud/hcloud"
  version = "~> 1.54"
}

# Import existing zones
terraform import hcloud_zone.asxp_io 61604
terraform import hcloud_zone.czsk_it 61606
terraform import hcloud_zone.childfr_ee 61605

# Example DNS resource
resource "hcloud_zone" "asxp_io" {
  name = "asxp.io"
  mode = "primary"
  labels = {
    managed_by = "terraform"
  }
}

resource "hcloud_zone_rrset" "apex_a" {
  zone = hcloud_zone.asxp_io.name
  name = "@"
  type = "A"
  records = [
    { value = "95.217.19.240", comment = "ops-server" },
  ]
}

See: https://github.com/hetznercloud/terraform-provider-hcloud/releases/tag/v1.54.0

Files

  • servers.tf - Server definitions + cloud-init
  • s3.tf - S3 buckets (6 total)
  • vpc.tf - Private network
  • firewall.tf - Security rules
  • dns.tf - DNS docs (manual management)
  • keys.tf - SSH keys
  • cloud-init/*.yaml - Server provisioning