Building a Practical Self-Hosted DevOps Stack in a Homelab

Building a Practical Self-Hosted DevOps Stack in a Homelab

If you’re paying for cloud while your home lab sits idle, you’re losing a golden opportunity. A practical homelab isn’t about hoarding tech toys; it’s about making your daily development and deployment workflows faster, cheaper, and more transparent. This guide isn’t a manifesto to recreate every cloud service on prem; it’s a pragmatic blueprint to build and run a lean, self-hosted DevOps stack that actually solves real problems: versioned infrastructure, automated deployments, centralized logging, and a safe path to experimentation without blowing up your budget or your sleep schedule.

Hook: The cloud bill monster is real. My home lab doesn’t erase that fear, but it compresses the learning curve, shortens feedback loops, and makes you understand every penny you spend in the cloud by letting you replicate and test locally first.

Part I: What you actually need in a homelab, without the plumbing disaster

Hardware baseline

  • CPU: a multi-core modern CPU (Ryzen 5/7 or Xeon equivalent). You’ll be running virtualization and multiple containers, so you want 8–16 cores at minimum if you’re serious; 4 cores can suffice for a lean test cluster, but you’ll hit limits quickly.
  • RAM: 32 GB is comfortable for a small cluster with several services; 64 GB is nicer if you plan to host more workloads or run heavier VMs.
  • Storage: an SSD boot drive plus 2–4 TB of HDD/SSD storage for data. Separate pools for VMs and for object storage or backups reduce I/O contention.
  • Networking: a solid gigabit NIC (preferably 2x or a 2.5/10Gb option if your budget allows). A dedicated management NIC and a separate data VLAN are worth it.
  • Power: a reliable UPS and a modest power budget. Homelabs drift into “on all the time” territory; plan for 50–200W steady-state depending on load.

Virtualization and OS

  • Use Proxmox VE or similar hypervisor to host VMs and Linux containers. Proxmox makes it easy to separate concerns (networking, storage, backups) and simplify backups and migrations.
  • Containers: rely on LXC for lightweight services (Gitea, Harbor, Prometheus, Loki, VPN, DNS) and VMs for heavier workloads (K3s control plane, CI agents, a small file server).
  • OS choices: Proxmox for the hypervisor; Debian/Ubuntu for containers; you can also run a separate RHEL-based or Debian-based image if you prefer.

Networking and security basics

  • Plan a small but robust network layout: VLANs for management, front-end services, and workloads; a central DNS server; and a VPN or remote access gateway for off-site access.
  • DNS and firewall: run a local DNS resolver (Pi-hole or Unbound) for ad-blocking and faster lookups, and couple it with a firewall appliance (pfSense/OPNsense) or a simple Linux-based firewall on the edge.
  • Remote access: WireGuard VPN for admin access; two-factor authentication for any exposed web consoles.
  • Backups: a simple, reliable backup strategy that targets off-host storage (NAS, second disk, or S3-compatible object storage) with versioning.

Part II: Our pragmatic stack and why it matters

Core stack choices

  • Git hosting: Gitea or GitLab CE. If you want a lightweight and fast self-hosted experience, Gitea is your friend; if you need a more complete suite (issues, CI, wikis), GitLab CE may be worth the extra footprint.
  • Container registry: Harbor or the built-in container registry in GitLab. Harbor gives you role-based access control, image scanning, and robust replication across environments.
  • CI/CD runner: GitLab Runner, or a Jenkins setup if you prefer. A small, dedicated runner node (or a few in a k3s cluster) makes pipelines predictable and isolated from your development workstation.
  • IaC and config management: Terraform for infrastructure provisioning, Ansible or Salt for configuration management. The ideal world is “write once, deploy anywhere” and have the same tooling across dev, test, and prod.

Container orchestration

  • Kubernetes lightweight alternative: k3s. It’s simpler to operate in a homelab and plays well with a handful of nodes. It provides a familiar control plane, namespace isolation, and easy deployment via Helm.
  • Edge/service mesh: keep it simple at first; you can add Istio or Notary later if your workloads demand stricter policies or advanced traffic control.

Monitoring, logging, and tracing

  • Monitoring: Prometheus + Grafana. Use node exporters on each host and application exporters for your stack.
  • Logging: Loki + Promtail or Fluent Bit + Loki; keep logs centralized but don’t drown in volume.
  • Alerting: Alertmanager with sensible routing to your phone or email; keep rules tight to avoid alert fatigue.

Backups and disaster recovery

  • Backups: use Restic or Borg to back up important data (Git repos, databases, VM images). Schedule backups to external storage on a different power path or to a cloud storage bucket if you’re comfortable with egress costs.
  • DR plan: test restores every quarter; automate restore playbooks for critical components (Git, registry, cluster state) to ensure you can recover quickly.

Security hygiene

  • SSH hardening: disable password login, force key-based login, limit root access, and use non-standard ports only if you’ve got a solid reason and a strict firewall.
  • MFA: enable MFA wherever possible (Git hosting, VPN portals, cloud-like dashboards).
  • Secrets management: avoid plaintext credentials in repos. Use a lightweight secrets store or environment encryption (e.g., SOPS with KMS, or Vault for more advanced needs).
  • Regular updates: automation for patch management across hosts; don’t let the lab drift.

Part III: A concrete, runnable path to get started

Step 1: Get Proxmox up and running

  • Install Proxmox on a dedicated hardware box or a small cluster. Create two or three VMs or LXC containers:
  • A management node (DNS, VPN, monitoring)
  • A CI/CD runner node
  • A Kubernetes master (k3s) node and one worker if you’re feeling ambitious
  • Set up VLANs and a basic firewall; enable fail2ban or similar to reduce brute-force risk.

Step 2: Build the core services in containers

  • Gitea: host on an LXC container or a small VM; enable backups and TLS with Let’s Encrypt.
  • Harbor: run as a container in its own namespace; configure TLS and authentication, set up replication to a secondary storage if you wish.
  • Prometheus/Grafana/Loki: deploy as a small stack in Kubernetes or as containers on a dedicated node; configure persistent storage.

Step 3: Add CI/CD and IaC

  • GitLab Runner: install on a dedicated VM or as a Kubernetes deployment; register runners to your Git hosting server; configure shared runners for simple pipelines and specific runners for multi-branch or heavy builds.
  • Terraform: manage your home-lab infrastructure as code. Create a small module for VM provisioning, network rules, and Kubernetes cluster initialization.
  • Ansible: create playbooks to configure nodes, deploy apps, and apply security baselines. Use Ansible Vault for sensitive data.

Step 4: Deploy a tiny application with a full pipeline

  • Example app: a static site or a simple API.
  • Git repo with code; pipeline steps:
  • Lint and test locally
  • Build a container image
  • Push to Harbor
  • Deploy to k3s via Helm or kubectl
  • Validate deployment with a basic smoke test
  • Notify via Slack or a webhook
  • This gives you a repeatable, auditable path from code to running service, all inside your own network.

Step 5: Observability and daily use

  • Set up dashboards: Grafana for service health and Prometheus metrics; Loki for logs. A simple “heartbeat” dashboard helps you spot outages quickly.
  • Alerts: define a few high-signal alerts (service down, high error rate, high CPU on CI runner) and route them to your phone or email. Don’t over-alert—your sanity matters.
  • Documentation: maintain a small internal wiki (e.g., a Gitea wiki or a Confluence-like space) with runbooks, recovery steps, and a prominent “first 15 minutes of failure” guide.

Step 6: Harden, then automate

  • Automate daily maintenance tasks: backups, certificate renewals, and health checks. Use cron jobs or a small automation runner in your cluster.
  • Runbooks: create minimal, repeatable procedures for common incidents (node failure, registry outage, TLS renewal problems). The key is speed and clarity under pressure.

Part IV: A practical pattern you can steal today

  • Single source of truth: store your infrastructure and pipelines in code. If it’s not versioned, it’s not real.
  • Small, composable services: don’t try to recreate every cloud service. Start with a few critical components (