Infrastructure Architecture¶
Everything below is defined in this repository's terraform/ and helm/ trees - nothing here is
aspirational. See Terraform for the full module reference.
Single-VM topology (staging + production)¶
Staging and production share one K3s VM (terraform/environments/platform), namespace-separated
at the Kubernetes layer (akshayabazaar-staging / akshayabazaar-production), not two physically
separate nodes. Everything else stays fully separate per environment:
| Layer | Shared? | How |
|---|---|---|
| K3s VM / Traefik | Yes - one node, one public IP | Hostname-based Traefik routing (staging.<domain> vs <domain>) |
| Private network | Yes - one Hetzner Network | Static IPs: .10 platform node, .20 staging data VM, .30 production data VM, .40 dev data VM |
| Kubernetes namespace | No | One Helm release per environment, --namespace at deploy time |
| Data VM (MySQL + Redis) | No | Separate Hetzner server, credentials, and firewall per environment |
| Kubernetes Secret | No | akshayabazaar-<env>-secrets - distinct names even though namespacing alone already isolates them |
| R2 bucket (media/backups) | No | akshayabazaar-media-<env> / akshayabazaar-backups-<env> |
| NetworkPolicy | No | Kubernetes' own semantics already scope every rule to its own namespace |
Full rationale for where this line was drawn: terraform/README.md "Single-VM topology".
Terraform module map¶
terraform/
├── bootstrap/ # one-time: creates the R2 bucket used as the Terraform remote-state backend
├── cloud-init/ # shared cloud-init templates (k3s-node-shared.yaml.tpl, data-vm.yaml.tpl)
├── modules/
│ ├── hetzner-network/ # private network + subnet
│ ├── hetzner-server/ # one Hetzner VM primitive - used for BOTH the K3s node and every data VM
│ ├── hetzner-firewall/ # Hetzner Cloud firewall rules
│ ├── cloudflare-dns/ # DNS A records
│ ├── cloudflare-security/ # zone-wide security settings (owned by production only)
│ └── cloudflare-r2/ # a single R2 bucket
└── environments/
├── platform/ # the shared K3s node + network - applied first, standalone
├── staging/ # staging's own data VM, DNS record, R2 buckets
├── production/ # production's own data VM, DNS record, R2 buckets, owns zone-wide Cloudflare settings
├── dev/ # structural scaffold, modeled on staging - not yet applied
└── shared/ # cross-environment concerns
There is no dedicated kubernetes or database Terraform module - K3s is installed via
cloud-init/k3s-node-shared.yaml.tpl at VM boot time on a hetzner-server instance, and
MySQL/Redis run as software installed via cloud-init/data-vm.yaml.tpl on another
hetzner-server instance. Hetzner Cloud has no native managed Kubernetes or managed
MySQL/Redis product; provision_data_vm=false plus external_mysql_host/external_redis_host
is the escape hatch to a real managed database provider if one is adopted later.
What runs where¶
Hetzner Cloud
├── K3s node (environments/platform)
│ ├── Traefik (bundled with K3s)
│ ├── namespace: staging → akshaya-local/akshayabazaar Helm release → frontend + backend pods
│ └── namespace: production → akshayabazaar Helm release → frontend + backend pods
├── staging data VM (environments/staging)
│ └── MySQL 8.2 + Redis 7.2 (cloud-init installed)
└── production data VM (environments/production)
└── MySQL 8.2 + Redis 7.2 (cloud-init installed)
Cloudflare
├── DNS (cloudflare-dns module) - A records per environment, pointing at the K3s node's public IP
├── Security (cloudflare-security module) - zone-wide WAF/SSL settings, owned by production
└── R2 (cloudflare-r2 module) - one media bucket + one backup bucket per environment
Local development infrastructure (not Terraform-managed)¶
The local environment (a developer's own machine) uses Docker Desktop's built-in k3d/K3s -
entirely separate from the Terraform-provisioned infrastructure above, with its own
namespace-local MySQL/Redis pods (mysql-local/redis-local, hand-written manifests, not part of
the Helm chart) standing in for the real data VM. See
Kubernetes → k3d and Local Development.
Related pages¶
- Terraform & Infrastructure - execution commands, state handling
- Environments - what config backs each environment tier
- Kubernetes & Helm - what actually runs on top of this infrastructure