Tech stack
This infrastructure is fully self-hosted on a home ARM64 VM. Every tool was chosen for three reasons: open source, representative of real-world industry standards, and consistent with the rest of the chain. This page documents the architecture and the choices behind it.
Overview
Internet
└── freebox.kiwinet.me (entry point)
└── Traefik (reverse proxy + SSL Let's Encrypt)
├── kiwinet.me → Kiwinet (Astro/Nginx site)
├── status.kiwinet.me → Uptime Kuma
├── grafana.kiwinet.me → Grafana
├── plex.kiwinet.me → Container plex (Plex Media Server)
├── hub.kiwinet.me → Home Assistant
└── traefik.kiwinet.me → Dashboard (auth-basic)
└── minecraft.kiwinet.me:25565 (TCP passthrough Traefik) Traefik is the single entry point of the VM: it handles routing, automatic SSL and service isolation. Minecraft goes through Traefik in TCP passthrough mode — traffic is routed without TLS termination.
Detailed architecture
Internet │ ├── :80/:443 → freebox.kiwinet.me → Traefik │ ├── kiwinet.me / www → Container kiwinet-web (Nginx) │ ├── traefik.kiwinet.me → Dashboard Traefik (auth-basic) │ ├── plex.kiwinet.me → Container plex (Plex Media Server) │ ├── hub.kiwinet.me → Home Assistant (network_mode: host) │ ├── status.kiwinet.me → Container uptime-kuma │ └── grafana.kiwinet.me → Container grafana │ ├── :25565 → minecraft.kiwinet.me → Container minecraft (raw TCP, Traefik passthrough) ├── :22 → SSH (VM access, ed25519 key) └── :22121 → WireGuard VPN (encrypted LAN access, one key per device)
Access to the Freebox admin interface is not publicly exposed. It goes exclusively through a WireGuard tunnel — zero attack surface, key-based authentication, one key per device.
Stack layers
Self-hosted VM running Debian GNU/Linux on ARM64. Traefik as the single reverse proxy, automatic Let's Encrypt SSL via HTTP Challenge. WireGuard for secure access to the local network.
GitHub Actions pipeline: Astro build → multi-platform Docker image (linux/arm64 via Docker Buildx) → push to GHCR → git pull on the VM → Docker Compose deployment. The ARM64 constraint is treated as a demonstrated build competency, not a workaround.
Two distinct layers: public status (Uptime Kuma, live badges, Discord alerts) and internal observability (Prometheus, cAdvisor, Node Exporter, Loki, Promtail, Grafana). The external/internal separation is a deliberate DevOps maturity choice.
Tools summary
| Role | Tool | Why this choice | Repo |
|---|---|---|---|
| Reverse proxy | Traefik v3 | Native Docker, auto SSL, container standard | kiwinet-infra |
| SSL | Let's Encrypt | Free, automatic, universally trusted | kiwinet-infra |
| VPN | WireGuard | Zero exposure, one key per device | kiwinet-infra |
| Frontend | Astro | Static output, lightweight, ~15 MB Docker image | kiwinet-web |
| File server | Nginx Alpine | Minimal, multi-stage build | kiwinet-web |
| Registry | GHCR | GitHub ecosystem coherence | kiwinet-web |
| CI/CD | GitHub Actions + SSH | Auditable, secrets management | kiwinet-web |
| Public status | Uptime Kuma | Public page + Discord alerts | kiwinet-status |
| Metrics | Prometheus + cAdvisor + Node Exporter | Industry standard | kiwinet-monitoring |
| Logs | Loki + Promtail | Grafana Labs coherence | kiwinet-monitoring |
| Dashboards | Grafana | Unified visualisation | kiwinet-monitoring |
Service status
Live badges — real-time status from Uptime Kuma.