diff --git a/wiki/Architecture-and-Hardware.md b/wiki/Architecture-and-Hardware.md new file mode 100644 index 0000000..de7f6ff --- /dev/null +++ b/wiki/Architecture-and-Hardware.md @@ -0,0 +1,23 @@ +# Architecture and Hardware + +## Hardware + +The homelab runs on a repurposed always-on Ubuntu Server box — modest specs by design, which shaped a lot of the decisions documented across this wiki (lightweight images, careful resource limits, monitoring everything so problems show up before they cause outages). + +| Component | Spec | +|---|---| +| OS | Ubuntu Server | +| Orchestration | Docker + Docker Compose | +| Management UI | Portainer | +| Storage | Mixed SSD + HDD, monitored via Hard Disk Sentinel | + +## Design principles + +1. **One Compose stack per service.** Each service lives in its own folder with its own `docker-compose.yml`, instead of one giant file. Easier to update, restart, or debug a single service without touching the rest. +2. **Monitor everything.** Prometheus + Grafana + cAdvisor + node-exporter run from day one, not bolted on later — resource pressure on modest hardware shows up fast, and having metrics from the start made it possible to catch it. +3. **Secrets stay out of git.** Every service that needs credentials uses a `.env` file (gitignored) with a matching `.env.example` committed as a template. +4. **DNS-level filtering at the network edge.** Pi-hole sits in front of all DNS traffic rather than relying on per-device ad blockers. + +## Network + +All services communicate over Docker's internal bridge networks, with only the ports that need external access published to the host. See [[Network Services]] for details on Pi-hole and Portainer specifically. diff --git a/wiki/Home.md b/wiki/Home.md new file mode 100644 index 0000000..d4efcf1 --- /dev/null +++ b/wiki/Home.md @@ -0,0 +1,28 @@ +# Homelab Wiki + +Documentation for a self-hosted homelab running entirely on Docker Compose. This wiki covers the *why* behind each service, how they're configured, and what I learned running them — the repo itself has the raw `docker-compose.yml` files. + +## Contents + +- [[Architecture and Hardware]] +- [[Monitoring Stack]] +- [[Network Services]] +- [[Media Automation]] +- [[Workflow Automation]] +- [[Storage Health]] +- [[Lessons Learned]] + +## At a glance + +| | | +|---|---| +| **Host** | Ubuntu Server | +| **Orchestration** | Docker Compose, one stack per service | +| **Management** | Portainer | +| **Monitoring** | Prometheus + Grafana + cAdvisor + node-exporter | +| **Network** | Pi-hole (DNS filtering), Samba (file sharing) | +| **Automation** | n8n | +| **Media** | Plex + Sonarr/Radarr/Prowlarr + qBittorrent | +| **Disk health** | Hard Disk Sentinel | + +This is a running system, not a demo — screenshots throughout this wiki are from the live dashboards. diff --git a/wiki/Lessons-Learned.md b/wiki/Lessons-Learned.md new file mode 100644 index 0000000..795c8b9 --- /dev/null +++ b/wiki/Lessons-Learned.md @@ -0,0 +1,25 @@ +# Lessons Learned + +Things that weren't obvious until running this in practice. + +## Secrets hide in more places than `.env` files + +The first pass at redacting this repo before publishing only grepped for text patterns like `password` and `token`. That missed real secrets sitting in `config/` directories — a JWT signing key in Filebrowser's `settings.json`, API keys in the *arr apps' `config.xml` files. The fix was to gitignore entire `config/` and `data/` directories by convention, rather than trying to catch every secret individually with a text search. + +## Splitting Compose stacks per service pays off + +One Compose file per service (instead of one big file for everything) made it possible to update, restart, or debug a single service without touching the rest of the stack — and made the git history for this repo readable, since each commit maps to one logical piece of infrastructure. + +## Monitoring from day one, not after something breaks + +Standing up Prometheus + Grafana + cAdvisor + node-exporter early, before anything went wrong, meant resource pressure showed up on a dashboard instead of as an unexplained outage. On modest hardware this matters more, not less. + +## Disk health monitoring is cheap insurance + +Hard Disk Sentinel running continuously catches degrading drives via S.M.A.R.T. data well before failure — reallocated sectors and rising temperatures are visible weeks or months ahead of an actual crash. + +## What's next + +- Self-hosted Gitea for private repos and CI runners +- Automated deployment via Watchtower on new image pushes +- Alerting rules on top of the existing Prometheus/Grafana setup, not just dashboards diff --git a/wiki/Media-Automation.md b/wiki/Media-Automation.md new file mode 100644 index 0000000..310a7ed --- /dev/null +++ b/wiki/Media-Automation.md @@ -0,0 +1,17 @@ +# Media Automation + +A self-hosted media stack: Plex serves the library, while Sonarr, Radarr, and Prowlarr handle automated indexing and library management, backed by qBittorrent as the download client. + +![Plex dashboard](images/plex-dashboard.png) + +## Stack + +| Service | Role | +|---|---| +| Plex | Media server and streaming frontend | +| Sonarr | TV library automation | +| Radarr | Movie library automation | +| Prowlarr | Indexer management, shared across the *arr apps | +| qBittorrent | Download client | + +Each runs as its own Compose stack under `mediastack/`, so any one service can be updated or restarted independently. diff --git a/wiki/Monitoring-Stack.md b/wiki/Monitoring-Stack.md new file mode 100644 index 0000000..d331ffa --- /dev/null +++ b/wiki/Monitoring-Stack.md @@ -0,0 +1,26 @@ +# Monitoring Stack + +Prometheus, Grafana, cAdvisor, and node-exporter running together give full visibility into both the host and every container on it — essential on modest hardware where knowing what's consuming resources matters. + +## Components + +- **Prometheus** — scrapes and stores time-series metrics from every target below +- **node-exporter** — exposes host-level metrics (CPU, memory, disk, network) +- **cAdvisor** — exposes per-container resource usage +- **Grafana** — dashboards on top of Prometheus data + +## Prometheus targets + +All scrape targets healthy and reporting: + +![Prometheus targets](images/prometheus-targets.png) + +## Grafana: Node Exporter Full dashboard + +Host-level metrics — CPU, memory, swap, disk, and network — over a rolling 24-hour window: + +![Grafana Node Exporter dashboard](images/grafana-node-exporter.png) + +## Why this matters + +On a lower-spec host, resource headroom is limited. Having per-container and host-level metrics from day one means a runaway container or a creeping memory leak shows up on a dashboard before it takes the box down — instead of finding out from an outage. diff --git a/wiki/Network-Services.md b/wiki/Network-Services.md new file mode 100644 index 0000000..bfa00ae --- /dev/null +++ b/wiki/Network-Services.md @@ -0,0 +1,17 @@ +# Network Services + +## Pi-hole — network-wide DNS filtering + +Pi-hole intercepts DNS for every device on the network, blocking ads and trackers at the DNS level instead of relying on per-browser extensions. Currently filtering roughly 20% of all queries against an active blocklist: + +![Pi-hole dashboard](images/pihole-dashboard.png) + +## Portainer — container management + +A web UI for the full Docker environment: all containers, their health status, images, and published ports in one place. Useful both for day-to-day management and as a quick way to eyeball the state of the whole stack: + +![Portainer container list](images/portainer-containers.png) + +## Samba + +Provides LAN-accessible file shares from the server's storage — used for moving files between devices on the network without a cloud intermediary. diff --git a/wiki/Storage-Health.md b/wiki/Storage-Health.md new file mode 100644 index 0000000..95b9829 --- /dev/null +++ b/wiki/Storage-Health.md @@ -0,0 +1,13 @@ +# Storage Health + +Disks fail silently until they don't. Hard Disk Sentinel runs continuously to surface S.M.A.R.T. data — temperature, reallocated sectors, estimated remaining lifetime — before a drive fails outright rather than after. + +![Hard Disk Sentinel report](images/storage-health-hdsentinel.png) + +## What this catches + +- Bad sector counts and whether they've been reallocated to spare area +- Temperature trends over the drive's lifetime +- An estimated health percentage and remaining lifetime, so a degrading drive can be replaced proactively instead of discovered after data loss + +Identifying details (hostname, MAC address, disk serial number) are redacted from the screenshot above before publishing. diff --git a/wiki/Workflow-Automation.md b/wiki/Workflow-Automation.md new file mode 100644 index 0000000..e4949b4 --- /dev/null +++ b/wiki/Workflow-Automation.md @@ -0,0 +1,11 @@ +# Workflow Automation + +n8n runs self-hosted (backed by its own Postgres instance) for building automated workflows — connecting APIs, scheduling tasks, and chaining actions without needing separate scripts for each one. + +![n8n workflow editor](images/n8n-workflow.png) + +> **Note:** the workflow shown above is a community template being explored in the editor. _Replace this section with a description of a workflow you've actually built or customized — what it automates, what triggers it, and why you built it. A specific, real example is far more convincing here than a generic one._ + +## Why self-hosted n8n + +Cloud automation platforms usually cap free usage or require a subscription for private workflows. Running n8n on the homelab keeps workflows private, removes execution limits, and integrates naturally with the rest of the self-hosted stack. diff --git a/wiki/_Sidebar.md b/wiki/_Sidebar.md new file mode 100644 index 0000000..8a2999d --- /dev/null +++ b/wiki/_Sidebar.md @@ -0,0 +1,10 @@ +**Homelab Wiki** + +- [Home](Home) +- [Architecture and Hardware](Architecture-and-Hardware) +- [Monitoring Stack](Monitoring-Stack) +- [Network Services](Network-Services) +- [Media Automation](Media-Automation) +- [Workflow Automation](Workflow-Automation) +- [Storage Health](Storage-Health) +- [Lessons Learned](Lessons-Learned) diff --git a/wiki/images/grafana-node-exporter.png b/wiki/images/grafana-node-exporter.png new file mode 100644 index 0000000..b4b80dd Binary files /dev/null and b/wiki/images/grafana-node-exporter.png differ diff --git a/wiki/images/n8n-workflow.png b/wiki/images/n8n-workflow.png new file mode 100644 index 0000000..0f79d3f Binary files /dev/null and b/wiki/images/n8n-workflow.png differ diff --git a/wiki/images/pihole-dashboard.png b/wiki/images/pihole-dashboard.png new file mode 100644 index 0000000..3da95f9 Binary files /dev/null and b/wiki/images/pihole-dashboard.png differ diff --git a/wiki/images/plex-dashboard.png b/wiki/images/plex-dashboard.png new file mode 100644 index 0000000..77632f5 Binary files /dev/null and b/wiki/images/plex-dashboard.png differ diff --git a/wiki/images/portainer-containers.png b/wiki/images/portainer-containers.png new file mode 100644 index 0000000..a5cadbf Binary files /dev/null and b/wiki/images/portainer-containers.png differ diff --git a/wiki/images/prometheus-targets.png b/wiki/images/prometheus-targets.png new file mode 100644 index 0000000..45161c3 Binary files /dev/null and b/wiki/images/prometheus-targets.png differ diff --git a/wiki/images/storage-health-hdsentinel.png b/wiki/images/storage-health-hdsentinel.png new file mode 100644 index 0000000..6a278d0 Binary files /dev/null and b/wiki/images/storage-health-hdsentinel.png differ