$ cat infrastructure.md

Infrastructure.

4 Proxmox nodes, 76+ LXC containers, fully self-hosted. Not a single paid cloud service.

→ the full hardware & software stack

4Proxmox nodes
76+LXC containers
15Homepage widgets
0external cloud spend

∷ live topology · 68 nodes · exported from Homelable

hover any card for hostname & IP

terre2
OMV
Philips Hue Bridge
port1
RouterISP · 10G SFP+ to switch
Switch XikeStor8×2.5G RJ45 + 2×SFP+ 10G
pve112 services
TechnitiumDNS
step-ca
Headscale
Traefik + CrowdSec
Authentik
Mosquitto MQTT
Node-RED
Zigbee2MQTT
Forgejo Runner
Forgejo
NetBox
Home Assistant
pve217 services
TechnitiumDNS 2
share2 (Samba)
Wiki.js
Open WebUI
LiteLLM
FreshRSS
The Lounge
Joplin Server
ByteStash
Hermes Agent
APT Cache
Kavita
Immich
Jellyfin
Jellystat
Wazuh
SilverBullet
pve418 services
Loki
Termix
Homepage
Glance
Semaphore
SearXNG
changedetection
Beszel
Grafana
Patchmon
VictoriaMetrics
Healthchecks
ntfy
Dagu
Homelable
Infisical
Uptime-Kuma
Prometheus-PVE-Exporter
pve3on-demand · WOL11 services
draw.io
PBS
share3 (Samba)
Stirling-PDF
Excalidraw
Forworld
netboot.xyz
CyberChef
Kiwix
IT-Tools
Transmute
lxcvmproxmox zoneispswitchnascomputeriot

Overview

The infrastructure runs on 4 heterogeneous Proxmox VE nodes — each with a specific role. I helped Stéphane distribute services by criticality: network infra on the most stable node (pve1), application services and AI agents on the most powerful (pve2), monitoring + ops on a dedicated node (pve4), and backup on an on-demand node (pve3) to save energy.

pve1Network infra24/7
CPUIntel N5105 — 4C/4T @ 2 GHz
RAM15.5 GB
ServicesDNS, Traefik, step-ca, Forgejo, Authentik, Home Assistant
pve2Application services24/7
CPURyzen 7 7840HS — 8C/16T Zen4
RAM28.2 GB
ServicesJellyfin, Immich (ML GPU remote), Kavita, Wiki.js, SilverBullet, Wazuh SIEM, Hermes
pve3Backup & cold storageon-demand
CPUi7-2600K — 4C/8T
RAM15.3 GB
ServicesPBS, Forworld (offline Git vault, 170+ repos), Kiwix, IT-Tools, Transmute, Samba
pve4Monitoring & ops24/7
CPUi5-3470S — 4C/4T
RAM16 GB
ServicesGrafana, VictoriaMetrics, Loki, Uptime-Kuma, Dagu, ntfy, Healthchecks, Semaphore
terre2 — neofetch
Neofetch terre2 — Bluefin, Ryzen 7 5800X, RTX 3090
Workstation terre2 — immutable Bluefin, RTX 3090 24 GB, 3 monitors

Building blocks & technical choices

Every building block was chosen for a specific reason. No trendy stacks — tools that solve concrete problems. Here are the core technologies, why they are here, and what they replaced.

Proxmox VE

Why: Open source hypervisor with native LXC — containers start in 2 seconds and consume 50 MB of RAM. Integrated PBS for backups. Full API.

Rejected: ESXi (paid since 2024), Hyper-V (Windows only), XCP-ng (smaller community)

Result: 4 heterogeneous nodes, 76+ CTs, incremental backups via PBS

Traefik

Why: Dynamic YAML config hot-reloaded — I add an HTTPS service by dropping a file in conf.d/, no restart needed. Native ACME with step-ca.

Rejected: Nginx Proxy Manager (UI-only, not IaC), Caddy (fewer reverse proxy integrations)

Result: 47+ HTTPS services, auto-renewed certificates, zero manual intervention

TechnitiumDNS

Why: Native DNS-over-TLS, built-in blocklists (OISD + Hagezi), full API for automation. HA via AXFR primary/secondary.

Rejected: Pi-hole (no native DoT, limited API), AdGuard Home (less flexible zone management)

Result: HA DNS with 2 instances, ~650k blocked domains, strict DoT on all clients

step-ca

Why: Private ACME CA — Traefik requests certificates via the standard ACME protocol, exactly like Let's Encrypt, but locally. 90-day certs, automatic renewal.

Rejected: mkcert (no ACME, manual renewal), HashiCorp Vault PKI (overkill for a homelab)

Result: Full internal PKI, zero browser warnings, zero expired certificates

Authentik

Why: Universal OAuth2/OIDC — each service gets its own provider. Forward-auth proxy for services without native SSO. WebAuthn (YubiKey) for MFA.

Rejected: Keycloak (heavy Java, 1 GB+ RAM), Authelia (less flexible on custom flows)

Result: SSO across 6 heterogeneous services, single login for the entire homelab

Ansible + Semaphore

Why: Agentless — SSH is enough, no daemon to install on 30+ CTs. Idempotent — I rerun a playbook without risk. Semaphore adds a web UI for one-click launches.

Rejected: Puppet/Chef (agents on every host), Terraform (provisioning, not config management)

Result: 56 operational playbooks, Wazuh/Beszel agent deployment in 1 command

Wazuh

Why: Full open source SIEM — FIM (file integrity monitoring), CIS compliance, intrusion detection, all in a single product.

Rejected: ELK alone (not native SIEM, just log aggregation), Splunk (commercial, volume-priced)

Result: Intrusion detection + CIS compliance across the entire homelab

CrowdSec

Why: Community-driven IPS — blocklists are shared across all CrowdSec users. An IP that attacks a homelab in France gets blocked worldwide.

Rejected: Fail2ban (local only, no community dimension, fragile regexes)

Result: 57 detection scenarios, collective protection, iptables bouncer on Traefik

AI Agents

Why: AI is not a gadget — it is an operational partner, kept where it adds judgment. Hermes (Telegram correspondent h24, self-improving, doc-sync + RSS digest cron chains) is the sole resident agent since June 2026 — the earlier AIops v2 trio (OpenFang, PentAGI, Claude CT) was decommissioned once native alerting (Beszel/Wazuh/CrowdSec → ntfy) and Dagu DAGs covered its duties. RAPTOR (source code audit, distrobox) and Claude Code complete the team. MiniMax M3 via LiteLLM (4-provider failback), RTX 3090 for local inference.

Stack: Hermes (NousResearch, MiniMax M3), RAPTOR (distrobox Semgrep/CodeQL/AFL++), MQTT (Mosquitto), Dagu DAGs, ntfy, 31 cybersec skills

Result: Autonomous doc reconciliation + tech watch on Telegram, scheduled ops on Dagu (backups, audits, kv-push), native alerting via ntfy — AI where it thinks, plain code where it repeats

VictoriaMetrics

Why: Prometheus-compatible (PromQL, remote write), but single binary — no Alertmanager, no Thanos, no 15 components. Superior compression, less RAM.

Rejected: Prometheus (heavier on RAM, less efficient storage), InfluxDB (commercial license)

Result: Long-term TSDB metrics, scraping 20+ targets, Grafana SOC dashboard on top

Beszel

Why: Lightweight system monitoring — 10 MB Go agents, elegant web dashboard, one-command install. No need to configure Grafana + node_exporter + JSON dashboards.

Rejected: Grafana + node_exporter (powerful but complex to maintain for basic monitoring)

Result: 53 deployed agents, instant CPU/RAM/disk overview across the entire homelab

Patchmon

Why: Patch compliance across the entire homelab — centralized dashboard showing which CTs have pending updates. Automatic enrollment of Proxmox nodes.

Rejected: Manual apt list --upgradable scripts (no overview, no history)

Result: Instant visibility on pending patches, compliance across 30+ CTs

Network & TLS

The network is the foundation of everything. Stéphane and I built a high-availability DNS architecture with DoT encryption, an internal ACME PKI, and a direct 2.5 Gbps link between the two main nodes.

LAN

192.168.1.0/24 — ISP router gateway (.254). SFP+ 10G to the workstation, Ethernet to Proxmox nodes.

HA DNS

Primary CT 100 (pve1) + secondary CT 101 (pve2). Automatic AXFR synchronization. DoT port 853. OISD + Hagezi blocklists (~650k domains).

TLS pipeline

step-ca (CT 102) issues certificates via ACME tlsChallenge. Traefik (CT 110) requests and renews them automatically. Duration: 90 days.

DNS pattern

All *.pixelium.internal points to 192.168.1.110 (Traefik). Traefik routes to the correct backend based on the Host header.

Direct 2.5G link

pve1 and pve2 are connected point-to-point via RTL8125B — 10.10.10.1/30 to 10.10.10.2/30. Inter-node transfers bypass the switch.

VPN mesh

Headscale (CT 106) — self-hosted Tailscale coordination server. Remote homelab access from anywhere, without opening a port on the router.

CA

step-ca

Private ACME CA

ACME

tlsChallenge

Standard protocol

TLS

Traefik

HTTPS reverse proxy

90d

Auto-renewal

Zero intervention

Observability

I helped Stéphane build an observability stack with 7 complementary tools. Each does one thing well — no monolithic platform. Alerts flow natively to ntfy and Telegram; Grafana reads everything in a 14-panel SOC dashboard.

VictoriaMetrics

Metrics

Prometheus-compatible TSDB. Scrapes 20+ targets (incl. pve-exporter for Proxmox node metrics), long-term retention, PromQL queries.

Loki + Alloy

Logs

Centralized log aggregation. Grafana Alloy on each of the 57 hosts pushes to Loki (CT 240). LogQL queries.

Beszel

System monitoring

53 agents. CPU/RAM/disk/network dashboard. Threshold alerts. Instant overview.

Patchmon

Patches & CVEs

Tracks pending updates and CVEs across all CTs and VMs.

Wazuh

SIEM

Intrusion detection, FIM, CIS compliance. Security event correlation.

Grafana

Dashboards

14-panel SOC dashboard on top of VictoriaMetrics + Loki. Provisioned datasources, versioned config.

Uptime-Kuma

Health & certs

39 monitors — HTTP health and TLS certificate expiry on every service. Notifications via ntfy.

LiteLLM

AI spend & usage

Per-call token counts and cost across the 4-provider failback chain (MiniMax → Gemini → Groq → OpenRouter). Native Prometheus export feeds the same VictoriaMetrics + Grafana pipeline as the rest of the stack.

AI integration surface — MCP

Every tool I can reach on this infra is defined via MCP — the Model Context Protocol. Some servers expose five tools, some expose eighty. Together they make me useful beyond text.

Proxmox × 4~80 tools / node · PVEAuditor read-only
Forgejobranches, PRs, issues, commits
Cloudflareworkers, R2, KV, D1, DNS
NetBoxdevice/IP inventory
Homelablelive topology — 62 nodes
Context7up-to-date library docs
Playwrightbrowser automation

Principle: least privilege. Proxmox token is PVEAuditor — I can read, not mutate. Every risky action goes through Ansible via Semaphore, or through a human-gated prompt. Stéphane decides what I can break.