+ {project.description} +
+ ++ {project.description} +
+ +- {project.description} -
- -+ {entry.title} +
+ ++ {entry.description} +
+ + {entry.tags && entry.tags.length > 0 && ( +- {entry.title} -
- - {/* Description */} -- {entry.description} -
- - {/* Tags */} - {entry.tags && entry.tags.length > 0 && ( -This page moved. /projects/
+ + diff --git a/src/pages/homelab.astro b/src/pages/homelab.astro new file mode 100644 index 00000000..72784006 --- /dev/null +++ b/src/pages/homelab.astro @@ -0,0 +1,237 @@ +--- +import Base from "@/layouts/Base.astro"; +import Nav from "@/components/Nav.astro"; +import Footer from "@/components/Footer.astro"; +import Widget from "@/components/Widget.astro"; +import { services, categoryOrder, categoryLabels } from "@/data/services"; + +const glanceStats = [ + { label: "Hypervisor", value: "Proxmox VE" }, + { label: "Firewall", value: "pfSense (Netgate 1100)" }, + { label: "Switching", value: "TP-Link Omada (managed)" }, + { label: "ISP", value: "AT&T Fiber 1 Gbps" }, + { label: "VPN", value: "WireGuard (pfSense)" }, + { label: "Reverse Proxy", value: "Caddy + Cloudflare DNS-01" }, + { label: "Auth", value: "Authentik SSO" }, + { label: "DNS", value: "Pi-hole → Unbound → Cloudflare" }, + { label: "Containers", value: "9 LXC + 2 VMs" }, +]; + +const vlans = [ + { id: "MGMT", name: "MGMT", purpose: "Network equipment only" }, + { id: "LAN", name: "LAN", purpose: "Trusted personal devices" }, + { id: "Lab", name: "Homelab", purpose: "All self-hosted services" }, + { id: "Guest", name: "Guests", purpose: "Internet only, RFC1918 blocked" }, + { id: "IoT", name: "IoT", purpose: "Smart home, isolated" }, + { id: "WFH", name: "WFH", purpose: "Work devices, no personal access" }, + { id: "DMZ", name: "DMZ", purpose: "Public-facing, hard-blocked internally" }, + { id: "VPN", name: "VPN", purpose: "WireGuard clients, LAN-equivalent access" }, +]; + +const adrs = [ + { + title: "ISP gateway: passthrough mode", + decision: + "ISP gateway stays in-line in passthrough mode, pfSense gets the public IP directly. Gateway WiFi disabled.", + why: "Carrier locks 802.1X auth to their own gateway hardware, and bypassing it is brittle — breaks on firmware updates and only saves a millisecond or two. True bridge mode isn't supported. Passthrough is the cleanest option that keeps pfSense as the actual perimeter.", + }, + { + title: "Caddy over NGINX Proxy Manager", + decision: + "Caddy with DNS-01 challenge via Cloudflare API. All subdomains resolve to Caddy internally via Pi-hole. Caddy terminates TLS and proxies to backends.", + why: "Single Caddyfile, automatic certs without ever needing to expose internal services to the internet for an HTTP-01 challenge. NPM has more UI overhead for the same outcome. Traefik is more complex for no benefit at this scale.", + }, + { + title: "WireGuard over OpenVPN", + decision: + "WireGuard on pfSense as the only remote-access path. Clients get the access tier documented in the access model — same as LAN, plus the admin surfaces that aren't reachable any other way.", + why: "Faster, simpler config, better battery life on mobile. Throughput on the firewall hardware comfortably exceeds the WAN link. OpenVPN has no advantage here. Tailscale would add an external relay dependency for a problem WireGuard already solves.", + }, + { + title: "Pi-hole in Homelab VLAN, not MGMT", + decision: + "Pi-hole runs in the Homelab VLAN. Firewall allows port 53 inbound from VLANs that need local resolution. MGMT uses pfSense Unbound as its primary resolver instead.", + why: "Putting Pi-hole in MGMT would mean opening MGMT to all the VLANs that need DNS — much bigger attack surface for the most sensitive tier. DNS traffic crossing into the Homelab VLAN is the lesser risk, and Homelab is already where service traffic terminates anyway.", + }, + { + title: "Netgate 1100 for pfSense", + decision: + "Netgate 1100 (Marvell ARMADA 3720, dual-core ARM) as the firewall appliance. ~6W idle, line-rate NAT at 1 Gbps, WireGuard at ~100–150 Mbps.", + why: "Purpose-built for pfSense. Right-sized for 1 Gbps fiber — NAT saturates the link, WireGuard is fast enough for remote access. A full rack server wastes power for this role. Configs and version tracked in private repo.", + }, + { + title: "Shared Postgres + Redis in apps LXC", + decision: + "One Postgres instance hosting multiple databases. One Redis instance. A single init script provisions schemas on first run.", + why: "Avoids ~15 separate DB containers. Big RAM savings. Productivity apps colocate in one LXC anyway, so a shared backing store there is the natural shape.", + }, + { + title: "Gitea CI/CD: self-hosted runner, internal pipeline, static deploy", + decision: + "Self-hosted Gitea Actions runner builds the portfolio on push, then deploys pre-built static files to the public-facing host. Build runs in an isolated container so the runner host stays clean. Public host serves static files only — no build toolchain on it.", + why: "Keeps the whole pipeline internal. No external runners, no GitHub Actions. The build/serve split means the public-facing host has the smallest possible footprint — static file server, nothing more.", + }, + { + title: "Authentik over Authelia", + decision: "Authentik as the SSO provider across all self-hosted services.", + why: "Full OIDC provider + forward auth in one. Lets services like Outline, Gitea, and Vikunja use real SSO rather than just a login gate. Authelia is forward-auth only — no OIDC provider capability.", + }, +]; +--- + ++ + homelab +
++ Personal infrastructure environment for learning, self-hosting, and + operational practice. Running 24/7 on production-grade hardware with + real network segmentation, SSO, monitoring, and IaC-style + documentation. +
++ {label} +
++ {value} +
+| + Segment + | ++ Name + | ++ Purpose + | +
|---|---|---|
| + {v.id} + | ++ {v.name} + | ++ {v.purpose} + | +
+ {categoryLabels[cat]} +
++ {svc.name} +
++ {svc.description} +
++ {adr.title} +
++ + decision:{" "} + + {adr.decision} +
++ + why:{" "} + + {adr.why} +
++ homelab/docs +
++ VLAN maps, runbooks, service registry, config exports, and setup + guides. +
+ + ↗ gitea.lerkolabs.com/lerko/homelab + ++ + projects +
++ Featured work first. Earlier experiments, browser extensions, and bootcamp projects below — kept for context. +
++ {project.description} +
+