Homelabs
4-node k3s cluster on Vagrant/VirtualBox with complete observability stack (Prometheus, Grafana, Loki). Terraform IaC for multi-domain static sites with NFS shared storage and Cloudflare Tunnel. Production-grade homelab for Kubernetes learning and testing.
Install / Use
/learn @luismr/HomelabsREADME
Homelabs 4-Node Debian Cluster
A Vagrant-managed 4-node Debian Bookworm cluster with bridged networking on a /22 subnet.
Cluster Configuration
| Node | IP Address | CPU | RAM | SSH Port | |---------|-----------------|-----|------|----------| | master | 192.168.5.200 | 2 | 4GB | 22 | | worker1 | 192.168.5.201 | 2 | 4GB | 22 | | worker2 | 192.168.5.202 | 2 | 4GB | 22 | | worker3 | 192.168.5.203 | 2 | 4GB | 22 |
Network: 192.168.4.0/22 (255.255.252.0)
Gateway: 192.168.4.1
DNS: 8.8.8.8, 8.8.4.4
Bridge Interface: en2: Wi-Fi (AirPort)
Architecture Overview
┌─────────────────────────────────────────────────────────────────────┐
│ INTERNET │
│ ↓ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Cloudflare Network (Global CDN) │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ pudim.dev │ │luismachado │ │ carimbo.vip │ │ │
│ │ │ (DNS) │ │ reis.dev │ │ (DNS) │ │ │
│ │ │ CNAME ──────────▶ CNAME ────────────▶ CNAME │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ │ │ │ │ │ │
│ │ └─────────────────┼─────────────────┘ │ │
│ │ ▼ │ │
│ │ ┌──────────────────────────┐ │ │
│ │ │ Cloudflare Tunnel │ │ │
│ │ │ (Encrypted Connection) │ │ │
│ │ └──────────────┬───────────┘ │ │
│ └─────────────────────────────┼──────────────────────────────┘ │
└────────────────────────────────┼──────────────────────────────────┘
│ Token Auth
│ HTTPS/QUIC
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Kubernetes Cluster (k3s) │
│ 192.168.5.200-203 (/22 subnet) │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Namespace: cloudflare-tunnel │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │
│ │ │ cloudflared pods (x2 replicas) │ │ │
│ │ │ Routes traffic based on hostname │ │ │
│ │ └─────┬──────────────┬──────────────┬───────────────── │ │
│ └────────┼──────────────┼──────────────┼────────────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │Namespace: │ │Namespace: │ │Namespace: │ │
│ │pudim-dev │ │luismachado │ │carimbo-vip │ │
│ │ │ │ reis-dev │ │ │ │
│ │ ┌────────┐ │ │ ┌────────┐ │ │ ┌────────┐ │ │
│ │ │Service │ │ │ │Service │ │ │ │Service │ │ │
│ │ │ static │ │ │ │ static │ │ │ │ static │ │ │
│ │ │ -site │ │ │ │ -site │ │ │ │ -site │ │ │
│ │ │ClusterIP│ │ │ │ClusterIP│ │ │ │ClusterIP│ │ │
│ │ └───┬────┘ │ │ └───┬────┘ │ │ └───┬────┘ │ │
│ │ │ │ │ │ │ │ │ │ │
│ │ ┌───▼────┐ │ │ ┌───▼────┐ │ │ ┌───▼────┐ │ │
│ │ │Nginx │ │ │ │Nginx │ │ │ │Nginx │ │ │
│ │ │Pods x3 │ │ │ │Pods x3 │ │ │ │Pods x3 │ │ │
│ │ └───┬────┘ │ │ └───┬────┘ │ │ └───┬────┘ │ │
│ │ │ │ │ │ │ │ │ │ │
│ │ ┌───▼────┐ │ │ ┌───▼────┐ │ │ ┌───▼────┐ │ │
│ │ │PVC │ │ │ │PVC │ │ │ │PVC │ │ │
│ │ │(NFS) │ │ │ │(NFS) │ │ │ │(NFS) │ │ │
│ │ │1Gi │ │ │ │1Gi │ │ │ │1Gi │ │ │
│ │ └───┬────┘ │ │ └───┬────┘ │ │ └───┬────┘ │ │
│ └─────┼──────┘ └─────┼──────┘ └─────┼──────┘ │
│ │ │ │ │
│ └────────────────┼────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ NFS Server (Master Node: 192.168.5.200) │ │
│ │ Shared Storage: /nfs/shared/ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Namespace: monitoring │ │
│ │ Prometheus | Grafana | Loki | Alertmanager | Promtail │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
Legend:
→ HTTP/HTTPS Traffic Flow
┌─ Kubernetes Namespace Boundary
│ Service/Pod/Resource
Traffic Flow:
- User requests
pudim.dev,luismachadoreis.dev, orcarimbo.vip - DNS resolves to Cloudflare's network (CNAME → tunnel UUID)
- Cloudflare routes to your Cloudflare Tunnel (encrypted, token-authenticated)
- Tunnel pods inspect hostname and route to appropriate namespace service
- Service load-balances across 3 nginx pod replicas
- Nginx serves static content from NFS-backed persistent storage
Project Structure
homelabs/
├── README.md ← You are here
├── Vagrantfile ← VM configuration
├── docs/ ← Documentation
│ ├── CLUSTER-INFO.md ← Quick reference & access info
│ ├── SETUP-GUIDE.md ← Complete setup tutorial
│ ├── LOKI-GUIDE.md ← Log collection guide
│ ├── NFS-STORAGE-GUIDE.md ← NFS shared storage guide
│ ├── GIT-QUICK-REFERENCE.md ← Git commands reference
│ └── .gitignore-README.md ← .gitignore guide
├── scripts/ ← Installation & helper scripts
│ ├── setup-cluster.sh ← Automated cluster setup
│ ├── install-k3s-master.sh ← Master node installation
│ ├── install-k3s-worker.sh ← Worker node installation
│ ├── install-observability.sh ← Monitoring stack installation
│ ├── setup-nfs-complete.sh ← Complete NFS setup
│ ├── setup-nfs-server.sh ← NFS server setup
│ ├── setup-nfs-clients.sh ← NFS client setup
│ ├── deploy-nfs-provisioner.sh ← NFS CSI provisioner
│ ├── verify-cluster.sh ← Cluster health check
│ └── ssh-nodes.sh ← SSH helper
└── examples/ ← Example manifests
├── nfs-test-deployment.yaml ← NFS test example
├── nfs-nginx-deployment.yaml ← Nginx with NFS
└── nfs-statefulset.yaml ← StatefulSet with NFS
Quick Start
Vagrant Commands
# Start all nodes
vagrant up
# Stop all nodes
vagrant halt
# Restart all nodes
vagrant reload
# Check status
vagrant status
# Destroy cluster
vagrant destroy -f
# Re-provision (apply configuration changes)
vagrant provision
SSH Access
Your SSH public key has been installed on all nodes for both vagrant and root users.
Direct SSH Access
# SSH as vagrant user
ssh vagrant@192.168.5.200 # master
ssh vagrant@192.168.5.201 # worker1
ssh vagrant@192.168.5.202 # worker2
ssh vagrant@192.168.5.203 # worker3
# SSH as root
ssh root@192.168.5.200 # master (root)
ssh root@192.168.5.201 # worker1 (root)
Using the Helper Script
# Quick access using the helper script
./scripts/ssh-nodes.sh master # or: ./scripts/ssh-nodes.sh m
./scripts/ssh-nodes.sh worker1 # or: ./scripts/ssh-nodes.sh w1
./scripts/ssh-nodes.sh worker2 # or: ./scripts/ssh-nodes.sh w2
./scripts/ssh-nodes.sh worker3 # or: ./scripts/ssh-nodes.sh w3
Via Vagrant
vagrant ssh master
vagrant ssh worker1
vagrant ssh worker2
vagrant ssh worker3
Features
- ✅ Debian Bookworm 64-bit
- ✅ Bridged networking with static IPs
- ✅ Kubernetes-ready configuration:
- Swap disabled
- IP forwarding enabled
- Bridge netfilter enabled
- br_netfilter module loaded
- ✅ SSH key authentication enabled
- ✅ Essential tools installed: curl, jq, net-tools, gnupg
- ✅ Custom DNS configuration
- ✅ Promiscuous mode enabled for networking
- ✅ NFS shared storage (master node as NFS server)
- Dynamic volume provisioning
- ReadWriteMany support
- Persistent storage for applications
Documentation
- SETUP-GUIDE.md - Complete step-by-step setup tutorial (1,446 lines)
- CLUSTER-INFO.md - Quick reference and access information
- LOKI-GUIDE.md - Log collection and querying guide
- NFS-STORAGE-GUIDE.md - Shared persistent storage guide
- CLOUDFLARE-TUNNEL-SETUP.md - Cloudflare Tunnel configuration guide
- GIT-QUICK-REFERENCE.md - Git commands reference
- .gitignore-README.md - .gitignore guide and best practices
- terraform/README.md - Terraform infrastructure documentation
Testing Connectivity
# Ping all nodes
for ip in 192.168.5.{200..203}; do ping -c 1 $ip; done
# Run command on all nodes
for ip in 192.168.5.{200..203}; do
ssh vagrant@$ip "hostname && uptime"
done
