docs: publish 2026-04-26

This commit is contained in:
lerko96
2026-04-26 22:26:14 -04:00
parent 6730781dd0
commit a061d37602
22 changed files with 388 additions and 2032 deletions
+48 -40
View File
@@ -1,55 +1,63 @@
# homelab
Personal homelab running 24/7 on production-grade hardware. Domain: `lerkolabs.com`. Single Proxmox host running 9 LXC containers + 2 VMs across 8 isolated VLANs with 20+ self-hosted services.
My homelab. Self-hosted, segmented, runs 24/7 on a single Proxmox host. Domain: `lerkolabs.com`.
## At a Glance
## Why I built this
| Component | Technology |
|-----------|-----------|
Started as a way to actually learn the stuff I was reading about for CompTIA — VLANs, firewall rules, segmentation. The plan was "I'll buy a small router, tag a few VLANs, run a couple of services." That was a few years ago. Now it's the platform I run my password manager on, my photos, my notes, my budget, and a Discord music bot for fun.
The reason it's still around is that documenting it forces me to think about it like a real system. Anything I haven't documented usually breaks at the worst time, so I started writing things down. This repo is what came out of that.
## What's running
| Layer | Tool |
|---|---|
| Hypervisor | Proxmox VE |
| Firewall | pfSense (Intel N100) |
| Firewall | pfSense (low-power x86) |
| Switching | TP-Link Omada (managed VLANs) |
| Reverse Proxy | Caddy + Cloudflare DNS-01 |
| Auth | Authentik SSO (OIDC + forward auth) |
| DNS | Pi-hole → pfSense Unbound → Cloudflare |
| VPN | WireGuard, UDP 51820 |
| Reverse proxy | Caddy (Cloudflare DNS-01) |
| Identity | Authentik (OIDC + forward auth) |
| DNS | Pi-hole → Unbound → Cloudflare |
| Remote access | WireGuard |
| Monitoring | Victoria Metrics + Grafana + Beszel |
| Backups | Proxmox Backup Server (PBS) |
| Backups | Proxmox Backup Server |
## Compute Layout
## Scope
| Container | IP | Cores | RAM | What Runs |
|-----------|-----|-------|-----|-----------|
| `pihole` | 10.2.0.11 | 1 | 512MB | Pi-hole DNS + ad blocking |
| `auth` | 10.2.0.25 | 1 | 512MB | Authentik SSO |
| `infra` | 10.2.0.20 | 2 | 1GB | Caddy reverse proxy, ntfy |
| `monitor` | 10.2.0.51 | 4 | 4GB | Victoria Metrics, Grafana, Beszel |
| `apps` | 10.2.0.60 | 4 | 6GB | 15+ productivity apps (Docker Compose) |
| `vault` | 10.2.0.X | 1 | 256MB | Vaultwarden (isolated) |
| `servarr` (VM) | — | 4 | 8GB | Plex, Jellyfin, *arr stack, qBittorrent |
| `haos` (VM) | — | 2 | 4GB | Home Assistant OS |
One Proxmox host. One firewall. One person operating it. About ten LXCs and a couple of VMs running roughly twenty services across seven VLANs.
## DMZ (Public-Facing)
There's no HA. I made that call on purpose — building real redundancy at this scale would mean buying hardware I don't need to keep idle, and the more useful skill to practice is "have a tested rebuild path." If something dies, I restore from PBS, follow the rebuild runbook, and I'm back in a few hours. That's good enough for a homelab and honestly closer to how a lot of small teams actually operate.
| Container | IP | Service |
|-----------|-----|---------|
| `caddy-dmz` | 10.99.0.20 | Public reverse proxy |
| `gitea` | 10.99.0.22 | gitea.lerkolabs.com |
| `portfolio` | 10.99.0.23 | lerkolabs.com |
## How I think about it
## Key Principles
- **VLANs by trust tier, not by purpose.** Management is its own thing because compromising it would be the worst outcome — not because it's "the network stuff." IoT is its own thing because I don't trust cloud-managed appliances, not because they're "smart home stuff."
- **No anonymous access to anything internal.** Authentik gates everything. If an app supports OIDC I use that; if it doesn't, Caddy does forward auth.
- **Public surface stays small.** Only a handful of services are reachable from the internet, and they all live behind a DMZ-isolated reverse proxy that's locked down at the firewall level — not just trusted to behave.
- **Admin is VPN-only.** No firewall GUI, hypervisor, backup server, switch, or AP is reachable from the internet. Ever. WireGuard first, everything else after.
- **Edge does TLS, internal hops are HTTP.** Less to maintain, and segmentation handles confidentiality on internal links.
- **Configs and secrets are not in this repo.** Secrets in a password manager; configs and version-state tracked in a private repo.
- All services require Authentik authentication — no anonymous access
- No management ports exposed to internet — all admin access via WireGuard first
- Caddy handles TLS termination; internal services run plain HTTP
- Secrets never committed — all referenced by Vaultwarden entry name
## Documented here
## Navigation
| Doc | About |
|---|---|
| [Services](docs/SERVICES.md) | What's deployed, grouped by what it does |
| [Network](docs/NETWORK.md) | Segmentation, firewall posture, DNS |
| [Security](docs/SECURITY.md) | Layered controls, threat model, limitations |
- [Services](docs/SERVICES.md) — full service registry with URLs and access matrix
- [Network](docs/NETWORK.md) — VLANs, firewall policy, DNS architecture, physical topology
- [Decisions](docs/DECISIONS.md) — architecture decision records (D001D010)
- [Security](docs/SECURITY.md) — security posture, auth layers, update cadence, known debt
- [Inventory](docs/INVENTORY.md) — hardware inventory
- [Rebuild](REBUILD.md) — disaster recovery sequence (8 phases)
- [Setup guides](setup/) — per-service installation and configuration
The operational stuff — exact IP plan, hardware inventory, ADRs, rebuild runbook, retention policies — is in a private repo. That separation is on purpose: this repo is for the reasoning; the private one is for actually running the thing.
## What I learned along the way
- Documenting *as I go* beats documenting *after*. I tried the second way first and the docs were lying within a month. Now I treat anything without a doc update as unfinished work.
- Defaults are decisions, even when you don't notice them. Caddy issuing per-hostname certs by default means every internal hostname I've ever used shows up in Certificate Transparency logs forever. That kind of thing gets caught only if you write down the *why* of each setup choice and revisit it.
- Segmentation pays for itself the first time something gets popped. I haven't been compromised, but designing as if I will be has made every other call easier.
- "It just works" is usually a sign I haven't looked hard enough yet. Most of the interesting stuff in this repo started with me trying to explain something I'd built and realizing I couldn't.
## Status
Stable. Reviewed quarterly.
---
*This is part of a portfolio. The private repo with the operational details is available on request.*