Files
2026-05-10 22:05:12 -05:00

64 lines
2.3 KiB
Markdown

# Watchtower Observability Stack
GDPR-compliant, multi-tenant observability stack (metrics, logs, traces) running on a
single Hetzner CPX42 in Nuremberg (nbg1). Built with Mimir, Loki, Tempo, and Grafana.
- **Infrastructure:** OpenTofu (state in Cloudflare R2)
- **Server config:** Ansible
- **Container runtime:** Podman Quadlets on AlmaLinux 10
- **Object storage:** Hetzner Object Storage (S3-compatible, EU-resident)
- **Access:** WireGuard VPN only — no public service ports
## Quick start
```bash
# 1. Provision infrastructure
cd tofu
cp backend.hcl.example backend.hcl # set your Cloudflare Account ID
cp terraform.tfvars.example terraform.tfvars # set Hetzner tokens + SSH key
set -a && source .env && set +a # load R2 credentials into env
tofu init -backend-config=backend.hcl
tofu apply
# 2. Configure server
cd ../ansible
cp inventory/hosts.yml.example inventory/hosts.yml # set host from tofu output
ansible-playbook -i inventory/hosts.yml playbooks/site.yml --ask-vault-pass
# 3. Onboard your first tenant
ansible-playbook playbooks/onboard-tenant.yml -e tenant_slug=team-alpha
```
## Repository layout
| Path | Purpose |
|------|---------|
| `tofu/` | OpenTofu infrastructure (Hetzner Cloud + Object Storage, Cloudflare R2 state) |
| `ansible/` | Server provisioning roles and playbooks |
| `quadlets/` | Podman Quadlet unit files (deployed by Ansible) |
| `config/` | Mimir, Loki, Tempo, Grafana configuration templates |
| `wireguard/` | WireGuard server template (peers vaulted in Ansible) |
| `scripts/` | Operational scripts (gdpr-purge, onboard-tenant, etc.) |
| `docs/` | Architecture, GDPR, multi-tenancy, runbook |
## Documentation
- [Architecture](docs/architecture.md)
- [GDPR compliance](docs/gdpr-compliance.md)
- [Multi-tenancy](docs/multi-tenancy.md)
- [Runbook](docs/runbook.md)
## Required secrets
| Secret | Where | Stored as |
|--------|-------|-----------|
| Hetzner Cloud API token | OpenTofu | `terraform.tfvars` (gitignored) |
| Hetzner Object Storage S3 keys | OpenTofu + Ansible | `terraform.tfvars` + Ansible vault |
| Cloudflare R2 access key/secret | OpenTofu backend | env vars `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` |
| WireGuard server private key | Ansible | Ansible vault |
| Grafana admin password | Ansible | Ansible vault |
## License
See [LICENSE](LICENSE).