Homelab In-Depth

Design considerations and trade-offs #

Key Architecture Decisions & Trade-offs

  • Cost Efficiency:
    • The Cloud cluster utilizes x2 2GB hosts for cost efficiency. Additional regions for redundancy were skipped in favor of a fast, and cost-effective GitOps recovery model.
    • UpCloud was chosen over other public cloud providers (AWS/GCP/Azure) for simplicity and low operating costs.
  • LXC over VMs:
    • LXC containers were selected for homelab workloads due to minimal resource usage, fast startup times, and efficiency on local secondhand hardware (Lenovo Mini PC & Raspberry Pis).
  • Runner Design:
    • Split across environments: a self-hosted runner in the homelab cluster and a public runner for cloud workloads. A future iteration will see the public runner replaced with run-once scaling agents.

Global Topology #

flowchart LR USERS(["Visitors & engineer"]) GITHUB["GitHub
Source · Actions · GHCR"] CF["Cloudflare
Edge · Access · Tunnels"] subgraph CLOUD["UpCloud K8s"] ARGO["Argo CD"] SITE["Public site"] ARGO --> SITE end subgraph HOME["Homelab"] K3S["K3s
Open WebUI · LiteLLM · MCP · observability"] LXCS["Dedicated LXCs
n8n · self-hosted runner"] end USERS --> CF CF --> SITE CF --> K3S GITHUB --> ARGO GITHUB --> LXCS classDef entry fill:#e0f2fe,stroke:#0284c7,color:#0f172a,stroke-width:1.5px; classDef edge fill:#fef3c7,stroke:#d97706,color:#0f172a,stroke-width:1.5px; classDef runtime fill:#ecfdf5,stroke:#059669,color:#0f172a,stroke-width:1.5px; classDef delivery fill:#ede9fe,stroke:#7c3aed,color:#0f172a,stroke-width:1.5px; class USERS,GITHUB entry; class CF edge; class K3S,LXCS,SITE runtime; class ARGO delivery;

Figure 1: End-to-end hybrid topology and delivery flow.

Network VLANs

  • VLAN 1: Default Management
  • VLAN 3: Isolated Applications
  • VLAN 4: Homelab & IoT

UniFi Hardware

  • Cloud Gateway Max
  • USW Ultra (1)
  • USW Ultra (2)
  • USW Ultra (3)

UniFi and Proxmox #

flowchart LR GATEWAY["Cloud Gateway Max
VLAN routing & firewall policy"] SWITCHES["USW Ultra switches
Access & PoE"] subgraph NETWORKS["Networks"] MGMT["VLAN 1
Management"] APPS["VLAN 3
Isolated applications"] LAB["VLAN 4
Homelab & IoT"] end subgraph PROXMOX["Proxmox"] RUNNER["GitHub runner"] PRIVATE["n8n LXC"] CONTROL["K3s control plane"] WORKER["K3s worker"] end GATEWAY --> SWITCHES SWITCHES --> MGMT SWITCHES --> APPS SWITCHES --> LAB APPS --> RUNNER APPS --> PRIVATE LAB --> CONTROL LAB --> WORKER CONTROL <--> WORKER classDef network fill:#fef3c7,stroke:#d97706,color:#0f172a,stroke-width:1.5px; classDef compute fill:#e0f2fe,stroke:#0284c7,color:#0f172a,stroke-width:1.5px; classDef service fill:#ecfdf5,stroke:#059669,color:#0f172a,stroke-width:1.5px; class GATEWAY,SWITCHES,MGMT,APPS,LAB network; class CONTROL,WORKER,RUNNER compute; class PRIVATE service;

Figure 2: Network segmentation and local compute boundaries.

IoT, SBC, and Proxmox compute hosts are isolated across separate VLANs.

Cloud K8s and GitOps #

flowchart TB CHANGE["Reviewed change"] --> REPO["GitHub repository
Code & manifests"] REPO --> CI["GitHub Actions
Build · test · publish"] CI --> GHCR["GHCR
Versioned image"] REPO -.-> ARGO["Argo CD
Reconcile"] GHCR --> WORKLOAD["UpCloud Kubernetes
Public site workload"] ARGO --> WORKLOAD classDef source fill:#e0f2fe,stroke:#0284c7,color:#0f172a,stroke-width:1.5px; classDef delivery fill:#ede9fe,stroke:#7c3aed,color:#0f172a,stroke-width:1.5px; classDef runtime fill:#ecfdf5,stroke:#059669,color:#0f172a,stroke-width:1.5px; class CHANGE,REPO source; class CI,GHCR,ARGO delivery; class WORKLOAD runtime;

Figure 3: Reviewed source through build, registry, and declarative deployment.

Build > Push > Deploy #

  • Continuous Integration: GitHub Actions builds and pushes container images to GitHub Container Registry (GHCR).
  • GitOps Reconciliation: Argo CD automatically detects new manifest updates and image tags in the repository and reconciles the desired state against the cluster.

Edge Security and Ingress #

flowchart TB PUBLIC(["Public visitor"]) ENGINEER(["Engineer"]) EDGE["Cloudflare Edge
DNS · WAF · TLS"] ACCESS["Cloudflare Access
Identity & service tokens"] TUNNEL["Cloudflare Tunnel
Outbound-only"] PUBLIC_APP["Public site"] PRIVATE_APPS["Private services
Grafana · Open WebUI · LiteLLM"] PUBLIC --> EDGE --> PUBLIC_APP ENGINEER --> ACCESS --> TUNNEL --> PRIVATE_APPS classDef entry fill:#e0f2fe,stroke:#0284c7,color:#0f172a,stroke-width:1.5px; classDef security fill:#fef3c7,stroke:#d97706,color:#0f172a,stroke-width:1.5px; classDef app fill:#ecfdf5,stroke:#059669,color:#0f172a,stroke-width:1.5px; class PUBLIC,ENGINEER entry; class EDGE,ACCESS,TUNNEL security; class PUBLIC_APP,PRIVATE_APPS app;

Figure 4: Separate public and identity-aware private access paths.

Zero Trust Tunnel Architecture #

  • Zero Inbound Ports: Cloudflare Zero Trust tunnels allow secure access to cluster services without exposing public IP addresses on nodes.
  • RBAC & Isolation: Argo CD AppProjects enforce granular RBAC policies and resource whitelisting for each application.
  • Identity-Aware Access: All traffic is authenticated and authorized via Cloudflare Zero Trust.
  • Declarative Setup: Access and app configs are managed through code and git rather than manual dashboard clicking.

Network Topology #

[ Client / Admin ] ──► [ Cloudflare Edge (WAF & Access) ] ──► [ Cloudflare Tunnel ] ──► [ UpCloud K8s / Homelab ]

Cross-Cluster Telemetry #

flowchart LR subgraph CLOUD["UpCloud K8s"] SITE["Public site"] CLOUD_PROM["Cloud Prometheus"] SITE --> CLOUD_PROM end TOKEN["Cloudflare Access
Service-token protected path"] subgraph LOCAL["Homelab"] SERVICES["K3s services & LXCs"] PROM["Prometheus"] LOKI["Loki"] GRAFANA["Grafana"] SERVICES --> PROM SERVICES --> LOKI PROM --> GRAFANA LOKI --> GRAFANA end CLOUD_PROM --> TOKEN --> GRAFANA classDef telemetry fill:#e0f2fe,stroke:#0284c7,color:#0f172a,stroke-width:1.5px; classDef edge fill:#fef3c7,stroke:#d97706,color:#0f172a,stroke-width:1.5px; classDef workload fill:#ecfdf5,stroke:#059669,color:#0f172a,stroke-width:1.5px; class SERVICES,SITE workload; class PROM,LOKI,GRAFANA,CLOUD_PROM telemetry; class TOKEN edge;

Figure 5: Local observability with protected cloud telemetry.

Skills & Tools #

A quick look at the tech and skills used throughout:

  • IaC: OpenTofu / Terraform to manage UniFi network rules, Proxmox LXCs, and cloud infrastructure.
  • Kubernetes & Containers: K3s inside LXC containers, managed UpCloud K8s, and Argo CD for GitOps deploys.
  • Networking & Security: VLAN segmentation, Cloudflare Zero Trust tunnels (no port forwarding), and SSO.
  • Observability: Prometheus, Loki, and Grafana for metrics and logs across clusters.
  • Tooling: Nix shells for reproducible local CLI environments.

Summary #

Layer / HostTechnologyIP / SubnetManagement / AccessRole
UniFi NetworkCloud Gateway Max + USW Ultra (x3)VLAN 1, 3, 4OpenTofu infra/networkL2/L3 Routing & PoE switching
OmicronProxmox VE 9.x (Lenovo Mini-PC)VLAN 4Proxmox Web GUI / SSHHypervisor host
k8s-node-01 / 02K3s in Debian 12 LXCVLAN 4OpenTofu infra/proxmoxHomelab Kubernetes compute
showcase-clusterUpCloud Managed K8sCloud VPCOpenTofu infra/cloudProduction public cloud cluster
Edge IngressCloudflare Tunnels & Access*.conordot.comZero Trust SSO & Service TokensIngress with 0 inbound open ports
ObservabilityPrometheus, Loki & Grafanagrafana.conordot.comCloudflare Access + Service TokensHybrid cross-cluster monitoring
Private AI & automationOpen WebUI, LiteLLM, n8nPrivate K3s / LXC boundariesScoped keys and application accessAI workspace, model routing, workflows