xmpp.asxp.io and conference.asxp.io point at services, so the Let's Encrypt HTTP challenge for the XMPP certificate arrives there. Only /.well-known/acme-challenge/ is answered (forwarded to Traefik on ops); everything else gets a 404. Assisted-by: Claude:opus-5-5 |
||
|---|---|---|
| .. | ||
| cloud-init | ||
| .gitignore | ||
| dns.tf | ||
| firewall.tf | ||
| keys.tf | ||
| outputs.tf | ||
| providers.tf | ||
| README.md | ||
| s3.tf | ||
| servers.tf | ||
| terraform.tfvars.example | ||
| variables.tf | ||
| vpc.tf | ||
ASXP.IO Infrastructure
Hetzner Cloud infrastructure managed via Terraform.
Servers
- asxpio-ops (CX23: 2 vCPU, 4GB) - Traefik, Forgejo, app stacks
- asxpio-services (CX43: 8 vCPU, 16GB) - CI runner, game servers, SillyTavern
Both have delete and rebuild protection. Hetzner's server backups are off; restic backs up the data instead (see ../README.md).
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)
DNS
dns.tf holds the zones asxp.io and czsk.it (Hetzner DNS, this project)
and every record set except SOA and NS. Our servers' records reference
hcloud_server, so moving a service is one edit.
All record sets are change-protected except the test XMPP servers'
(prosody, ejabberd, anotherim); both zones are delete-protected.
To change a protected record set, apply twice: first with the set
excluded from protection, then with the new value. Hand edits in the
console show up as drift in terraform plan.
Network
- VPC: 10.10.0.0/20
- WireGuard VPN: 10.20.0.0/24
- IPv4 + IPv6 enabled
Cost
| Item | Monthly |
|---|---|
| ops CX23 | €3.99 |
| services CX43 | €11.99 |
| IPv4 (2x) | €1.00 |
| S3 (1TB) | €6.49 |
| S3 1TB Traffic | €1.00 |
| Total | €24.47 |
Prices are net, as billed in November 2026 (0% VAT).
Both servers are billed below the current list price (€5.49 and €15.99).
A deleted and recreated server gets the list price, so reinstall or
rebuild in place and never recreate. prevent_destroy and Hetzner's
delete protection guard against it.
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-inits3.tf- S3 buckets (6 total)vpc.tf- Private networkfirewall.tf- Security rulesdns.tf- DNS docs (manual management)keys.tf- SSH keyscloud-init/*.yaml- Server provisioning