Homelab: Proxmox cluster
Self-built 3-node Proxmox cluster with HA, separate VLANs, a dedicated firewall, central backup and 30+ self-hosted services — fully documented as a Git repository.
ProxmoxOPNsenseDockerZFSPBS
IT infrastructure · Networking & security · Virtualization
I look after the IT infrastructure of a private bank in Munich — networking, firewalls, virtualization. At home I run a small datacenter of my own: three servers, a segmented network, everything documented as code. I came to IT as a career changer — no formal IT education, but all the more drive of my own. The fact that I spend my evenings voluntarily doing what I do for a living probably says more about me than any cover letter could.
robin@homelab
role: IT Service Specialist — Infra & Virtualization
employer: Merkur Privatbank, Munich
homelab: 3-node Proxmox cluster · 30+ services
stack: OPNsense · VMware · Ansible · Docker
focus: Infrastructure as Code
uptime: in IT since 2018 — enthusiastic for far longer
$ play · ·
Munich, Germany
pfSenseSophosLANCOMVMwareSANWindows ServerPRTGSIEM
Munich, Germany
VMwareDataCorePRTG
Memmingen, Germany
Windows ServerCitrix
Memmingen, Germany
My homelab is my laboratory: it's where I try technologies before I take them seriously, and where I host everything I can host myself. It runs in production for the whole family — so outages get noticed.
Self-built 3-node Proxmox cluster with HA, separate VLANs, a dedicated firewall, central backup and 30+ self-hosted services — fully documented as a Git repository.
ProxmoxOPNsenseDockerZFSPBS
Step-by-step migration of the homelab to declarative provisioning: OpenTofu creates the containers, Ansible configures them, Komodo deploys the Docker Compose stacks straight from the Git repo via GitOps — CI checks every change.
OpenTofuAnsibleDocker ComposeKomodoForgejo ActionsSOPS
Three short excerpts from my homelab repository — rewritten and anonymized for publication, but true to structure and style. Expand to read.
Ansible playbook (excerpt): all containers update in batches; after the upgrade a health check probes the Docker stack — failing hosts are held for review instead of rolling on.
- name: Update LXC containers in controlled batches
hosts: lxc_all
serial: 5
tasks:
- name: Apply pending upgrades
ansible.builtin.apt:
update_cache: true
upgrade: dist
- name: Health check — compose stack still running?
ansible.builtin.command: docker compose ps --status running -q
args:
chdir: /opt/{{ service_name }}
register: health
changed_when: false
failed_when: health.stdout == ""
- name: Hold host for manual review instead of rolling on
ansible.builtin.file:
path: /var/lib/updates/hold/{{ inventory_hostname }}
state: touch
when: health is failed How a new LXC comes to life: one OpenTofu module call. The conventions (template, unprivileged, backups, delete protection) are enforced by the module — not by caller discipline.
module "webapp01" {
source = "./modules/lxc-standard"
hostname = "webapp01"
vmid = 4210
ip_address = "192.0.2.10/24" # documentation range — real IPs stay private
gateway = "192.0.2.1"
target_node = "node01"
cores = 2
memory_mb = 2048
disk_gb = 16
# the module enforces the conventions, not the caller:
# Debian 12 template, unprivileged, onboot, firewall on,
# backups scheduled, prevent_destroy unless marked otherwise
tags = ["docker", "web"]
destroyable = false
} The Git repo is the truth: a timer compares the live cluster against the inventory and reports deviations via push notification.
#!/usr/bin/env bash
# Nightly: is the live cluster still what the Git repo says it is?
set -euo pipefail
repo=/opt/homelab
"$repo/scripts/collect/guests.sh" > "$repo/inventory/guests.yml"
cd "$repo"
if git diff --quiet -I '^# generated:' -- inventory/; then
exit 0 # no drift — stay silent
fi
git diff --stat -- inventory/ | tail -1 \
| curl -s -H "Title: inventory drift detected" -H "Priority: high" \
-d @- "https://ntfy.example.org/alerts" Keep the overview under pressure, prioritize in a structured way, communicate clearly — things get hectic on their own.
Patch, change and incident management with testing and release — changes to production systems need a way back.
Technical documentation and emergency procedures are written with the change — not someday after.
Every decision, every runbook, every inventory lives versioned in a Git repo. What isn't documented doesn't exist.
Hardened containers, minimal privileges, encrypted secrets, no direct access from outside.
Anything done manually twice becomes a script, a playbook or a pipeline the third time.
New technologies are evaluated in the lab, documented, and only then put into production.
E-mail is the fastest way to reach me.
game over —