Files
public/README.md
T
thesabear c1ab267a00 README: remove redundant table, refocus Systems on capability not gotchas
The 'Every system, at a glance' table and the Systems section covered
the same 16 things in the same order - removed the table, kept the
narrative section since that's where the actual selling has to happen.
Rewrote every paragraph to lead with what the system does and its
real scope (what an employer needs to see) instead of a debugging
edge case or failure-mode trivia standing in for the description.
2026-08-22 22:18:18 +03:00

11 KiB

thesabear's Homelab

Most homelabs are a media server with some extra apps bolted on. This one is a platform: the same categories of systems a company's platform/security team owns — secrets management, zero-trust network segmentation, self-hosted CI/CD, human-gated fleet orchestration, a self-built SOC — run at homelab scale, for real, 24/7, by one person.

11
fleet hosts
55
compose stacks
16
documented systems
4
trust boundaries
13
automated maintenance flows

The decision that shows the most

Most self-hosted setups have one trust boundary: "you're on the LAN, you're trusted." That's the easy answer, and it's wrong — a single compromised container can reach everything else with no further resistance. The other easy answer, mutual TLS on every single connection with no exceptions, is also wrong: real overhead, real certificate-lifecycle burden, on traffic that doesn't need it — exactly the kind of complexity that gets quietly disabled under pressure, which is worse than never building it.

This fleet runs four trust boundaries, each calibrated to who's actually on the other end — public internet traffic, human browsers on personal devices, machine-provisioned containers, and non-HTTP infra traffic each get a different control, matched to their real risk, not a blanket policy applied everywhere or nowhere. Enforced by three independent routing authorities instead of one central router, specifically so a failure or misconfiguration in any single one only ever takes out its own third of the traffic — never all of it at once. It didn't start this way, either: the public proxy used to be its own VM, and the internal service-to-service model used to be a flat, unauthenticated mesh with no boundary at all. Both got replaced deliberately, trading operational simplicity for a smaller blast radius.

Full breakdown — the boundary-by-boundary reasoning, the routing-authority failure table, all 8 traffic laws: docs/architecture-overview.md.

This repo is a sanitized showcase of the systems behind that platform — the actual engineering decisions and tradeoffs, not just a list of installed apps. Every real IP, hostname, and internal domain has been stripped or genericized throughout.

Architecture at a glance

flowchart LR
    Internet(["Internet"]) --> Edge["Edge Firewall"]
    Edge --> LAN["LAN"]

    LAN --> DNS["Internal DNS<br/>two zones"]
    LAN --> Vault["Vault<br/>PKI + secrets"]
    DNS --> Vault

    Vault --> Apps["App Host<br/>41 stacks"]
    Vault --> Automation["Automation VM<br/>Git + orchestration"]
    LAN --> FileServer["File Server"]
    DNS --> FileServer
    LAN --> Automation

    Apps --> InternalProxy["Internal Proxy Zone"]
    Apps --> SSO["SSO"]

    Vault --> EdgeProxy["User-Facing Proxy<br/>mTLS"]
    DNS --> EdgeProxy
    Apps -.proxied.-> EdgeProxy
    SSO -.auth.-> EdgeProxy

    Apps -.-> Monitoring["Monitoring"]
    Automation -.-> Monitoring
    FileServer -.-> Monitoring
    EdgeProxy -.-> Monitoring

    Apps -.-> SecMon["Security Monitoring"]
    Automation -.-> SecMon
    FileServer -.-> SecMon
    EdgeProxy -.-> SecMon

    classDef edge fill:#f8cecc,stroke:#b85450,color:#333
    classDef core fill:#dae8fc,stroke:#6c8ebf,color:#333
    classDef obs fill:#fff2cc,stroke:#d6b656,color:#333
    class Internet,Edge edge
    class LAN,DNS,Vault,Apps,Automation,FileServer,InternalProxy,SSO,EdgeProxy core
    class Monitoring,SecMon obs

Solid arrows are real dependencies; dotted arrows are asynchronous telemetry reporting, not a blocking dependency. Full breakdown of all 8 traffic laws (ingress, east-west, secrets, DNS, observability, notifications, CI/CD, management) with the actual trust-boundary reasoning: docs/architecture-overview.md.

Systems

🔐 Secrets & PKI

A self-hosted Vault cluster is both the certificate authority and the secret store for every host in the fleet — every TLS certificate, every database password, every API key traces back to this one system. Nothing reaches Vault directly; a local agent on each host authenticates itself and renders what that host needs to disk. Replaced an earlier setup where secrets sat in plaintext inside git. → docs/secrets-and-pki.md

🔑 Secret Distribution Model

Four separate delivery paths move material out of Vault, purpose-built for what's actually being delivered — a short-lived certificate, an application secret, a full config file, or an admin-only credential — each with its own contract for what the rest of the fleet does if that specific path fails. → docs/secret-distribution.md

🪪 SSO & Identity

Authentik, self-hosted, fronts single sign-on fleet-wide — native OIDC where an app supports it, proxy-based forward-auth in front of everything else, so apps that were never built with SSO in mind still get it. Every OIDC login crosses reverse-proxy zones mid-handshake, and Git automation runs on a scoped bot account rather than an admin identity. → docs/sso-and-identity.md

🧱 Firewall & Network Segmentation

No blanket internal trust anywhere on the network — every real service-to-service flow gets its own explicit rule, and everything not explicitly allowed is logged and dropped by default. Enforced at two layers: a firewall at the network edge, and firewalld locally on every host, each opening only what that specific host actually needs. → docs/firewall-and-network.md

🌐 DNS

Two internal DNS zones split browser-facing traffic from service-to-service traffic — which zone a hostname resolves in is what decides which trust boundary a request enters, not just where it's found. Technitium runs both zones, self-hosted, with direct DNS bypass blocked at the firewall so the split is actually enforced, not just a naming convention. → docs/dns-naming.md

📈 Observability

Every fleet host runs a native metrics-and-logs agent that pushes outward to a central Loki/Prometheus stack, rather than waiting to be scraped — chosen specifically so monitoring never needs inbound access opened through the firewall model to every host it watches. Logs, container output, and DNS query history all land in one searchable place. → docs/observability.md

🛡️ Security Monitoring

A Wazuh agent runs on every host in the fleet, continuously watching file integrity, rootkit behavior, and compliance drift against a CIS-based benchmark. A curated runbook root-causes routine alerts once so they're never re-triaged from scratch, and hardening controls apply fleet-wide with specific, reasoned exceptions rather than uniform enforcement regardless of fit. → docs/security-monitoring.md

🔁 Orchestration

Kestra runs thirteen scheduled flows that handle fleet maintenance end to end — OS patching, container rebuilds, app updates, disk cleanup — every one of them built around a check → pause → human approval → apply pattern, so nothing changes on the fleet without someone actually saying go. → docs/orchestration.md

🔔 Notifications

Every alert in the fleet — from apps, from hosts, from security events — funnels through one Node-RED instance and one shared formatter before reaching Slack, so a notification reads the same regardless of which of a dozen-plus sources triggered it. A dedicated role puts every host onto the same pipeline for OS-level health, independent of any single application. → docs/notifications.md

📦 Self-Hosted Registry & Build Pipeline

Docker images get built and hosted entirely in-fleet on the Git server's own built-in registry — no runtime dependency on Docker Hub or ghcr for the stacks that have opted in. A weekly scheduled pass checks upstream image digests before committing to a full rebuild, so nothing gets rebuilt unless something upstream actually changed. → docs/registry-and-build.md

🖥️ Dashy SOC Board

One custom-built dashboard aggregates fourteen different data sources — security alerts, logs, metrics, CI health, secrets state, DNS, backups, firewall stats — into a single glanceable board, replacing what used to be fourteen separate tabs to check. Acknowledgement state lives entirely in the browser, no backend to host or secure. → docs/dashy-soc-board.md

⏱️ Cron Scheduler

Every scheduled job across the fleet — orchestration flows, system timers, app-internal schedules — lives in one inventory, visualized as a load heatmap weighted by actual resource impact, so a new job's time slot can be picked without colliding with existing load. → docs/cron-scheduler.md

📝 Content Pipeline

A structured content tracker, an automation layer, and a self-hosted blog already work together end to end to take an idea from draft to published post. The one piece still being built is automatic fan-out to social platforms — included here in progress, not hidden until finished. → docs/content-pipeline.md

🏗️ Infrastructure as Code

Packer builds a hardened base image, Terraform provisions each VM from it, and Ansible configures and continuously re-hardens every host after that — three tools, three separate responsibilities, connected by one tag that threads through all three stages instead of one tool trying to do every job. → docs/iac-pipeline.md

🧯 Disaster Recovery & Upgrades

Three independent recovery layers cover three different kinds of loss — a lost host rebuilds from code, VM-level backups cover full-host snapshots, and a separate volume-level backup covers application data specifically. OS-level and application-level upgrades run on entirely separate, deliberately decoupled schedules and safety checks. → docs/disaster-recovery.md

What's running

~55 Docker Compose stacks, grouped by purpose rather than by which host happens to run them — see stacks/: identity & security, platform/infra, media, productivity, and dev tools.


About me

Self-taught, building toward a career in IT/DevOps — everything in this repo is something I learned by doing, from reading docs to breaking my own lab and fixing it again.

LinkedIn

Website