Most homelab builds you're shown run past two thousand euros before the first container starts — a rack, 10-gigabit switching, redundant everything. Genuinely more reliable than this, and out of reach for most of the people it would help. This runs on two second-hand laptops and the electricity they draw. Less bulletproof; far more realistic — and anyone can rebuild it without a budget.
internet ──── x.x.x.x ──────────────────────────────────────────────────────┐ │ ┌───────────────────────────────────────────────────────────────────────┐ │ │ Router · NAT · forward 80/tcp 443/tcp 51820/udp │────┘ └──────────────────────────────────┬────────────────────────────────────┘ │ LAN 192.168.2.0/24 │ VIP 192.168.2.100 · keepalived VRRP ┌───────────────────────────────┐ │ │ ┌──────────────────┴──────────────┐ ┌────────────┴─────────────────────────┐ │ primary · 192.168.2.230 │ │ secondary · 192.168.2.225 │ │ 10-year-old legion laptop │ │ thinkpad · rescued from a friend │ │ 32 GB RAM · 512 GB SSD · GPU │ │ 16 GB RAM · 2 TB SSD │ │ VRRP MASTER (priority 101) │ │ VRRP BACKUP (priority 100) │ │ │ │ │ │ ufw → traefik (TLS · DNS-01) │ │ traefik (TLS · independent cert) │ │ ↳ secondary via file provider │ │ │ │ wireguard · wg0 │ │ dnsmasq │ │ dnsmasq · postgres · redis │ │ │ │ │ │ immich jellyfin rustfs │ │ freshrss n8n postiz grafana │ │ paperless downloads open-data │ │ prometheus loki ollama │ │ │ │ │ │ kopia · peer ↔ primary (SFTP) │ │ 5 CI runners (4 low · 1 high) │ │ 2 TB storage snapshots │ │ kopia · peer ↔ sec. (SFTP) │ │ │ │ 512 GB snapshots │ │ 7 CI runners (6 low · 1 high) │ └─────────────────────────────────┘ └──────────────────────────────────────┘
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ L0 · internet ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ any IP · any port · any request ↓ reject on port mismatch ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ L1 · ufw ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ pass: 80/tcp 443/tcp 51820/udp drop: everything else — silently, at the kernel ↓ 80 → permanent redirect 443 ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ L2 · traefik ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ TLS terminated · wildcard cert validated · SNI routed to service certificate: *.bensoussan.de · Let's Encrypt · 89 d remaining ↓ allowlist middleware checked ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ L3 · middleware ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ public → pass (no source restriction) vpn-only → source ∈ 10.200.200.0/24 ∪ 192.168.2.0/24 else 403 internal → source = 127.0.0.1 else 403 ↓ forward to container port ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ L4 · container ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ service handles request · no plaintext socket ever externally reachable all layers nominal · no anomalies in the last 7 d
| service | purpose | exposure | host | backend |
|---|
Every pipeline here shares the same engineering foundation: dependencies baked into the container image so no tooling is installed at job runtime; rootless Podman with layer caching for fast incremental rebuilds without a registry round-trip; Trivy security scans between build and push, failing hard on any HIGH or CRITICAL CVE; Renovate automatically opening PRs to update every version pin; and RustFS (S3-compatible) for all artifact storage — GitHub's free-tier cap is never touched.
The most complex pipeline in the repo. A single YAML recipe source fans out into PDFs (4 languages × 2 formats via Gotenberg), a Flutter mobile app, a Tailwind website, and a Flutter asset bundle — all assembled through RustFS artifact handoffs and published to the homelab registry and Google Play.
Cross-platform pipeline for the Stolpersteine offline memorial app: builds the Flutter Android APK (on a high-memory runner), runs widget tests, and publishes to both the self-hosted downloads server and Google Play on master merges.
Builds and deploys the ci-metrics GitHub Actions run poller: lints and tests the async Python poller, builds and pushes the container, then deploys to the primary host via Ansible on master merges.
Gatekeeper pipeline that runs before any code lands: secret scanning with Gitleaks, Trivy filesystem vulnerability scan, and the full pre-commit suite (ruff, shellcheck, shfmt, hadolint, codespell) inside a dedicated CI image — so no tooling is installed at job runtime.
Builds and deploys the wall-mounted homescreen kiosk app: lints and unit-tests the Next.js codebase, builds and pushes the container image, then on master rolls the new image out to the container the kiosk actually displays (running on the secondary host).
Builds the Stolpersteine Rust/Axum backend: runs cargo tests, then builds and pushes the container image using sccache with a Podman bind-mount cargo cache for fast incremental Rust compilation.
Provisions both homelab hosts via Ansible: validates playbook syntax and runs a check-mode dry-run on PRs, then applies the full site.yml against the live two-node cluster on master merges — all inside an immutable container image with vault access baked in.
Lean two-job pipeline for the matchmaker API: builds the Node.js/Fastify container, then runs the full test suite inside it — no npm ci at test time because node_modules is baked into the image.
CI/CD pipeline for the HTMX recipe platform: builds the FastAPI/Python container, runs backend tests and linting inside it, then deploys to the primary host via Ansible on master merges.
Generates the resume PDF via Gotenberg (a containerised Chrome renderer) and publishes both the PDF and open-data exports to the homelab static server, storing intermediate artifacts in RustFS.
Post-deploy smoke test that runs the verify-cluster.yml Ansible playbook against the live homelab after every master merge, confirming all services are up and reachable from outside the internal network.
| tool | what it does |
|---|