feat: backup and restore

This commit is contained in:
2026-07-20 22:45:43 +01:00
parent c12a507fc1
commit 1aa340f7ce
37 changed files with 524 additions and 207 deletions
+3 -5
View File
@@ -1,6 +1,8 @@
# Root module: wires together the shared network and the three host modules
# (one per server in docs/architecture.md). Each host module owns its own
# firewall (and volume, where applicable) - see modules/<host>/main.tf.
# firewall - see modules/<host>/main.tf. Persistent data lives in named Docker
# volumes backed up to S3 (see services/<host>/backup-docker-compose.yml), not
# on Hetzner volumes.
locals {
# SSH to dev/prod is only permitted from the vpn server's public IP: admins must
@@ -28,8 +30,6 @@ locals {
{ zone = "luke-else.co.uk", name = "traefik.cicd", value = module.dev.ipv4 },
{ zone = "luke-else.co.uk", name = "vpn", value = module.vpn.ipv4 },
{ zone = "luke-else.co.uk", name = "traefik.vpn", value = module.vpn.ipv4 },
{ zone = "divine-couture.co.uk", name = "www", value = module.prod.ipv4 },
{ zone = "snexo.co.uk", name = "@", value = module.prod.ipv4 },
]
}
@@ -50,7 +50,6 @@ module "dev" {
ssh_key_ids = local.ssh_key_ids
network_id = module.network.id
private_ip = var.dev_private_ip
volume_size = var.dev_volume_size
allowed_ssh_source_ips = local.vpn_ssh_source_ips
network_ip_range = var.network_ip_range
@@ -68,7 +67,6 @@ module "prod" {
ssh_key_ids = local.ssh_key_ids
network_id = module.network.id
private_ip = var.prod_private_ip
volume_size = var.prod_volume_size
allowed_ssh_source_ips = local.vpn_ssh_source_ips
network_ip_range = var.network_ip_range
-21
View File
@@ -64,24 +64,3 @@ resource "hcloud_server" "this" {
}
}
resource "hcloud_volume" "storage" {
name = "dev-storage"
size = var.volume_size
server_id = hcloud_server.this.id
automount = true
format = "ext4"
lifecycle {
prevent_destroy = true
}
}
locals {
# Hetzner's automount convention (hc-utils' 99-hc-volume-automount.rules) is
# always /mnt/HC_Volume_<id> - deterministic once the volume exists, since the
# id is stable for the volume's lifetime regardless of which server it's
# attached to. Kept here only as a human-readable output (see outputs.tf) -
# ansible/roles/deploy looks this up itself from the Hetzner API, it doesn't
# read this value.
data_dir = "/mnt/HC_Volume_${hcloud_volume.storage.id}"
}
-5
View File
@@ -5,8 +5,3 @@ output "ipv4" {
output "private_ipv4" {
value = var.private_ip
}
output "data_dir" {
description = "Deterministic host path of the auto-mounted volume - see local.data_dir."
value = local.data_dir
}
-5
View File
@@ -28,11 +28,6 @@ variable "private_ip" {
type = string
}
variable "volume_size" {
description = "Size in GB of the volume attached to dev (disk2 in docs/architecture.md)."
type = number
}
variable "allowed_ssh_source_ips" {
description = "CIDRs allowed to reach port 22 on dev. Set by the root module to the vpn server's public IP."
type = list(string)
-21
View File
@@ -91,24 +91,3 @@ resource "hcloud_server" "this" {
}
}
resource "hcloud_volume" "storage" {
name = "prod-storage"
size = var.volume_size
server_id = hcloud_server.this.id
automount = true
format = "ext4"
lifecycle {
prevent_destroy = true
}
}
locals {
# Hetzner's automount convention (hc-utils' 99-hc-volume-automount.rules) is
# always /mnt/HC_Volume_<id> - deterministic once the volume exists, since the
# id is stable for the volume's lifetime regardless of which server it's
# attached to. Kept here only as a human-readable output (see outputs.tf) -
# ansible/roles/deploy looks this up itself from the Hetzner API, it doesn't
# read this value.
data_dir = "/mnt/HC_Volume_${hcloud_volume.storage.id}"
}
-5
View File
@@ -5,8 +5,3 @@ output "ipv4" {
output "private_ipv4" {
value = var.private_ip
}
output "data_dir" {
description = "Deterministic host path of the auto-mounted volume - see local.data_dir."
value = local.data_dir
}
-5
View File
@@ -28,11 +28,6 @@ variable "private_ip" {
type = string
}
variable "volume_size" {
description = "Size in GB of the volume attached to prod (disk1 in docs/architecture.md)."
type = number
}
variable "allowed_ssh_source_ips" {
description = "CIDRs allowed to reach port 22 on prod. Set by the root module to the vpn server's public IP."
type = list(string)
-10
View File
@@ -14,16 +14,6 @@ output "prod_private_ipv4" {
value = module.prod.private_ipv4
}
output "dev_data_dir" {
description = "Deterministic host path of dev's auto-mounted volume - also written to services/dev/.env as DATA_DIR."
value = module.dev.data_dir
}
output "prod_data_dir" {
description = "Deterministic host path of prod's auto-mounted volume - also written to services/prod/.env as DATA_DIR."
value = module.prod.data_dir
}
output "vpn_ipv4" {
value = module.vpn.ipv4
}
-2
View File
@@ -14,7 +14,5 @@ ssh_key_names = ["your-key-name", "laptop", "phone"]
# dev_server_type = "cx22"
# prod_server_type = "cx22"
# vpn_server_type = "cx22"
# dev_volume_size = 20
# prod_volume_size = 20
# allowed_ssh_source_ips = ["203.0.113.4/32"]
# dns_zones = ["luke-else.co.uk", "divine-couture.co.uk", "snexo.co.uk"]
+2 -14
View File
@@ -1,5 +1,5 @@
variable "location" {
description = "Hetzner Cloud datacenter location for all servers and volumes."
description = "Hetzner Cloud datacenter location for all servers."
type = string
default = "nbg1"
}
@@ -34,18 +34,6 @@ variable "vpn_server_type" {
default = "cx22"
}
variable "dev_volume_size" {
description = "Size in GB of the volume attached to dev"
type = number
default = 20
}
variable "prod_volume_size" {
description = "Size in GB of the volume attached to prod (disk1 in docs/architecture.md)."
type = number
default = 20
}
variable "network_ip_range" {
description = "IP range of the private network shared by dev and prod."
type = string
@@ -84,5 +72,5 @@ variable "allowed_ssh_source_ips" {
variable "dns_zones" {
description = "Domains to manage as Hetzner DNS zones. Point each domain's registrar NS records at tofu output dns_nameservers for Hetzner to actually become authoritative."
type = list(string)
default = ["luke-else.co.uk", "divine-couture.co.uk", "snexo.co.uk"]
default = ["luke-else.co.uk"]
}