Production homelab: 50+ services on 3 nodes
Self-hosted infrastructure stack — Docker Compose, Caddy, monitoring, backups, and the orchestration glue that keeps it all running.
Production homelab: 50+ services on 3 nodes
Three Ubuntu boxes. One Caddy reverse proxy. Fifty-plus self-hosted services running the show — email, git, CI/CD, dashboards, password manager, photo backup, and a small Kubernetes cluster for the things that need it.
The stack
| Node | Role | Specs |
|---|---|---|
edge-01 | Reverse proxy + firewall | 2 vCPU, 4GB RAM, public IP |
app-01 | Application workloads | 8 vCPU, 32GB RAM, NVMe |
data-01 | Databases + storage | 8 vCPU, 32GB RAM, 2×4TB HDD (RAID1) |
What runs where
edge-01 (public-facing):
- Caddy with auto HTTPS via Cloudflare DNS-01
- Crowdsec + fail2ban for intrusion detection
- WireGuard for admin access
app-01 (workloads):
- Woodpecker CI
- Gitea (lightweight self-hosted Git)
- Drone runners (3 instances)
- Plausible Analytics
- Uptime Kuma
- Healthchecks.io (cron monitoring)
data-01 (stateful):
- PostgreSQL 16 (single primary, streaming replication to app-01)
- Redis 7
- MinIO (S3-compatible, for backups + media)
- Restic repo (nightly snapshots → B2 + local)
Orchestration
Single docker-compose.yml per service, kept in a private Gitea repo.
Deploys via a small bash script that:
- Pulls latest config from Gitea
- Runs
docker compose pull - Health-checks before stopping the old container
- Rolls back automatically if health check fails
Zero-downtime deploys for everything that’s stateless.
Monitoring
- Prometheus on data-01, scraping all 3 nodes via node-exporter
- Grafana dashboards for CPU, RAM, disk, network, Docker containers
- Uptime Kuma for external service health
- Alertmanager → Telegram when anything’s off
Backups
- Restic → Backblaze B2 (encrypted, deduplicated)
- Hourly snapshots of databases, daily of everything else
- 30-day retention + monthly archive
- Monthly restore drill (yes, I actually test)
What’s next
- Replace single PostgreSQL with Patroni + etcd (HA)
- Move stateless workloads to a small k3s cluster
- Add Ceph for proper distributed storage
Full config and dashboards: github.com/nuteo/homelab (placeholder)