Back to blog
Armario rack del homelab: mini-PCs ThinkCentre rackeados, router y switch TP-Link y paneles Digitus.

Building a homelab from scratch: the big picture - Homelab (01/06)

Case studyHomelabProxmoxSelf-hosting

You want to build a homelab. Maybe you're tired of paying monthly subscriptions for services you could host yourself. Maybe you want to understand how infrastructure really works — not by reading a book, but by breaking things at 2 a.m. and learning how to fix them. Or maybe you simply like the idea of having your own corner of the internet.

Whatever the reason, in this series I'm going to explain how I built mine: a mix of home servers and VPS nodes in the cloud, connected by VPN, running everything from Kubernetes clusters to home automation. No prior infrastructure experience needed — every acronym is explained the first time it appears.

This first post covers the big picture. The hardware, the naming scheme (yes, there's a theme), what runs where, and how it all connects. The next five posts go deep on networking, Kubernetes and GitOps, security and operations, observability, and backups.

Let's get to it.

Why build a homelab?

Three reasons kept pushing me forward:

  1. Sovereignty. If you host the services yourself, the data is yours. No provider can change prices, kill a product, or lock your account. Your services run under your rules.
  1. Learning. There's no better way to understand networking, containers, orchestration, and operations than running them yourself. Debugging a broken DNS at home teaches you more than any certification course.
  1. Running your own projects. I run zetesis.xyz — a web portal with authentication, full-text search, and an MCP (Model Context Protocol) server — entirely on my own infrastructure. No cloud bills that scale with traffic. No dependency on any provider.

The hardware

The homelab is split across two physical locations connected over the internet, plus a few VPS (Virtual Private Server) instances in the cloud for edge services. Here's what's in it:

At home: 4 Proxmox nodes

Proxmox VE is a free, open-source hypervisor — basically, software that lets you run several virtual machines (VMs) and containers on a single physical server. I have four:

NodeNetworkRole
marco-aurelioAtenas (10.1.0.0/24)VMs: VyOS router, Docker host, home automation
socratesAtenas (10.1.0.0/24)Support VMs
pitagorasRoma (10.0.0.0/24)VMs: VyOS router, Docker host (reverse proxy, dashboard)
platonRoma (10.0.0.0/24)Kubernetes cluster (alejandro)

At home: a bare metal node

Clusters don't live only in VMs. escipion is a Lenovo ThinkCentre M920q running Talos directly on the metal — no hypervisor in between — and hosts the second Kubernetes cluster, on its own platform network inside Roma.

At home: TrueNAS storage

spinoza is a TrueNAS on the Atenas network (10.1.0.11). It runs MinIO, an S3-compatible object storage service. Every server in the homelab backs up to spinoza — it's the central storage layer.

Cloud: VPS servers

Some things make more sense in the cloud — services that need a public IP with low latency, or edge nodes that sit between Cloudflare and the homelab:

VPSRole
von-braunMain reverse proxy (Caddy), Cloudflare tunnel, backups
escohotadoWeb applications, forums, authentication, search, CMS
unamunoForums, Cloudflare tunnel, backups

The names

You'll have noticed a pattern. Every machine, VM, service, and cluster takes its name from history:

The Proxmox nodes are named after philosophers: marco-aurelio, socrates, pitagoras, platon. The VPS are named after thinkers and writers: von-braun (the rocket engineer), escohotado, unamuno. The Kubernetes clusters take the names of conquerors and generals: alejandro (Alexander the Great) and escipion (Scipio Africanus). Services follow the same pattern: ptolomeo for the CD agent, tolstoi for backups, cervantes for the S3 gateways, kepler for the dashboard, rothbard and mises for home automation. And the networks take their names from ancient cities: Atenas and Roma.

Is it too much? Maybe. But when you've been staring at a terminal at midnight for a while, it helps that every name tells you something. The philosophers host things, the conquerors win new territory, and the writers tell stories.

Overall architecture

This is how everything connects. The two local networks (Atenas and Roma) are joined by a WireGuard tunnel between their routers. The VPS nodes join the homelab through Tailscale, a mesh VPN. Internet traffic comes in through Cloudflare.

Loading diagram...

A few things to keep in mind:

Cloudflare sits in front of everything public. It handles DNS, DDoS protection, and caching. von-braun is the main entry point — it runs Caddy (a reverse proxy) with CrowdSec (an intrusion detection system) and routes traffic to the homelab over Tailscale. WireGuard connects the two physical networks: the VyOS routers (temistocles and constantino) maintain a permanent encrypted tunnel between Atenas and Roma. And Tailscale is a mesh VPN built on top of WireGuard; the VPS nodes use it to reach internal services without exposing ports to the internet. spinoza also advertises routes over Tailscale so remote servers can back up to it.

We'll cover all of this in detail in Post 2: Networking.

What runs where

A quick tour of what's in each part of the infrastructure.

Kubernetes: escipion (Roma)

The platform cluster: the services that hold everything else up. It runs on Talos Linux on the bare metal node — no hypervisor, a minimal, immutable operating system designed specifically for Kubernetes:

  • Infisical — Self-hosted secrets manager (like HashiCorp Vault, but simpler)
  • Harbor — Private registry for container images and charts
  • Observability — Prometheus, Grafana, Loki, and Tempo: telemetry from the entire fleet ends up here
  • ArgoCD — GitOps continuous deployment for Kubernetes
  • Traefik — Ingress controller (routes HTTP traffic to the pods)
  • K8up — Backup operator (snapshots to MinIO on spinoza)

Kubernetes: alejandro (Roma)

Dedicated to running zetesis.xyz. Separated from escipion so the user-facing application doesn't share resources with the platform:

  • Zetesis Portal — The web application (production)
  • Zetesis-Auth — Identity and access management (standalone Keycloak, login, SSO)
  • Typesense — Full-text search engine
  • CNPG PostgreSQL — Cloud-native PostgreSQL operator (manages the database)
  • MCP Server — Model Context Protocol server for AI integrations

Docker VMs: aristoteles (on both networks)

There's a VM called "aristoteles" on each network, running Docker services with Docker Compose:

aristoteles on pitagoras (Roma):

  • trajano — Caddy reverse proxy for the local network
  • kepler — Homepage dashboard (central status page)
  • marco-polo — Cloudflare DDNS + tunnel

aristoteles on marco-aurelio (Atenas):

  • rothbard — Zigbee2MQTT + Mosquitto (home automation bridge)
  • mises — Homebridge (Apple HomeKit integration)
  • dijkstra — Additional services

VPS servers

The cloud VPS nodes handle edge routing and host some web applications. von-braun runs Caddy (reverse proxy + CrowdSec), a Cloudflare tunnel, and backup agents. escohotado hosts web applications, Keycloak, PostgreSQL, Ghost CMS, Typesense, and forums. unamuno runs forums, a Cloudflare tunnel, and backup agents.

Backup: tolstoi (everywhere)

Every server runs a service called tolstoi — a Restic backup agent that sends data to MinIO on spinoza through a Tailscale gateway (called cervantes). The Kubernetes clusters use K8up instead, but the destination is the same: spinoza.

Loading diagram...

Two CD systems

The entire homelab is deployed from a single Git repository. Push to main and it's in production. But there are two different systems managing deployment, because Docker Compose and Kubernetes are very different animals:

ptolomeo (Docker Compose)

For the VPS hosts and the VMs, a lightweight agent called ptolomeo (based on doco-cd) polls the Git repository every 180 seconds. When it detects changes, it runs docker compose up in the corresponding directory. Each host has a .doco-cd.yaml that tells ptolomeo what to watch:

# Ejemplo: .doco-cd.yaml en vps-von-braun
name: trajano
reference: refs/heads/main
working_dir: vps-von-braun/trajano
external_secrets:
  CF_API_TOKEN: <project-id>:prod:/trajano/CF_API_TOKEN
  CROWDSEC_API_KEY: <project-id>:prod:/trajano/CROWDSEC_API_KEY

The external_secrets section fetches secrets from Infisical at deploy time — so no passwords are stored in Git.

ArgoCD (Kubernetes)

For the Kubernetes clusters, ArgoCD watches the same Git repository and syncs the Kubernetes manifests automatically. Each cluster has a bootstrap.yaml that uses the App-of-Apps pattern — a "parent" application that manages all the child applications:

# Ejemplo simplificado: talconfig.yaml (definición del clúster Talos)
clusterName: alejandro
talosVersion: v1.12.4
kubernetesVersion: v1.35.0
endpoint: https://10.0.0.110:6443
allowSchedulingOnControlPlanes: true

cniConfig:
  name: none  # Usamos Cilium en su lugar

nodes:
  - hostname: alejandro
    ipAddress: 10.0.0.110
    controlPlane: true
    installDisk: /dev/sda

This is a Talos Linux configuration — it defines the entire cluster declaratively. The operating system, the Kubernetes version, the network plugin, the node IPs — all in a YAML file inside Git.

We'll dive into both CD systems in Post 3: Kubernetes and GitOps.

Networking preview

Networking deserves its own post (it's the next one), but the short version is this: two physical networks (Atenas and Roma) connected by a site-to-site WireGuard tunnel. VyOS routers (temistocles and constantino) handling DHCP, DNS, BGP, firewall rules, and the tunnel. Tailscale as a mesh overlay VPN so the VPS nodes can reach internal services without opening ports. Cloudflare for public DNS and DDoS protection. And Caddy (on von-braun and the local reverse proxies) terminating TLS and routing traffic.

The journey of a public request to zetesis.xyz looks like this:

  1. User
  2. Cloudflare
  3. Caddyvon-braun
  4. Tailscale WireGuard
  5. Traefikalejandro
  6. Pod

No open ports on the home network. Everything goes through Tailscale tunnels.

What's next

That was the bird's-eye view. In the next five posts we go deep:

Post 2: Networking — How WireGuard, Tailscale, Cloudflare, and Caddy fit together. VyOS router configuration, BGP between the clusters and the edge, subnets, and DNS. Why no ports are forwarded. The complete traffic journey, from user to pod.

Post 3: Kubernetes and GitOps — Talos Linux, ArgoCD, the App-of-Apps pattern, ptolomeo for Docker hosts, and how a single Git push deploys to every server.

Post 4: Security and operations — Three layers of secrets management (Infisical, SOPS, ESO). Backup strategy with Restic and MinIO. Home automation with Zigbee2MQTT and HomeKit.

Post 5: Observability — Metrics, logs, and traces with Prometheus, Grafana, Loki, and Tempo: all telemetry converges on a central hub. Blackbox probes, actionable alerts, and AI spend measured in tokens and cents.

Post 6: Backups and restoration — What gets backed up and how: PostgreSQL with CNPG and barman, K8up per namespace, tolstoi for the Docker hosts. And the part almost nobody talks about: how to restore.

If you're thinking about building a homelab, I hope this gives you an idea of what's possible. You don't need all of this from day one — I certainly didn't start this way. Start with one server, one service, and grow from there.

See you in Post 2.


This series documents the architecture behind the infrastructure that powers zetesis.xyz. All the code lives in a single GitOps repository. No cloud providers were harmed in the making of this homelab.

The complete series