iac/terraform/README.md
Sergei Poljanski 59415515a1 docs: restic backups, XMPP and Xray on services, Fossils retired
Describe the new roles, how to list and restore restic snapshots, and
that the restic password must be kept outside the servers.

Assisted-by: Claude:opus-5-5
2026-11-12 21:03:10 +04:00

149 lines
3.4 KiB
Markdown

# 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)
**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 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
```bash
terraform init
```
### 2. Configure secrets
Edit `terraform.tfvars`:
```hcl
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
```bash
terraform plan
terraform apply
```
### 4. Enable S3 backend (optional)
After buckets are created:
```bash
# 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:
```hcl
# 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