Restructure documentation as docs/ folder with working links
23
docs/Architecture-and-Hardware.md
Normal file
@@ -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](Network-Services.md) for details on Pi-hole and Portainer specifically.
|
||||
28
docs/Home.md
Normal file
@@ -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](Architecture-and-Hardware.md)
|
||||
- [Monitoring Stack](Monitoring-Stack.md)
|
||||
- [Network Services](Network-Services.md)
|
||||
- [Media Automation](Media-Automation.md)
|
||||
- [Workflow Automation](Workflow-Automation.md)
|
||||
- [Storage Health](Storage-Health.md)
|
||||
- [Lessons Learned](Lessons-Learned.md)
|
||||
|
||||
## 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.
|
||||
25
docs/Lessons-Learned.md
Normal file
@@ -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
|
||||
17
docs/Media-Automation.md
Normal file
@@ -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.
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
26
docs/Monitoring-Stack.md
Normal file
@@ -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:
|
||||
|
||||

|
||||
|
||||
## Grafana: Node Exporter Full dashboard
|
||||
|
||||
Host-level metrics — CPU, memory, swap, disk, and network — over a rolling 24-hour window:
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
17
docs/Network-Services.md
Normal file
@@ -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:
|
||||
|
||||

|
||||
|
||||
## 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:
|
||||
|
||||

|
||||
|
||||
## Samba
|
||||
|
||||
Provides LAN-accessible file shares from the server's storage — used for moving files between devices on the network without a cloud intermediary.
|
||||
13
docs/Storage-Health.md
Normal file
@@ -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.
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
11
docs/Workflow-Automation.md
Normal file
@@ -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.
|
||||
|
||||

|
||||
|
||||
> **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.
|
||||
BIN
docs/images/grafana-node-exporter.png
Normal file
|
After Width: | Height: | Size: 285 KiB |
BIN
docs/images/n8n-workflow.png
Normal file
|
After Width: | Height: | Size: 384 KiB |
BIN
docs/images/pihole-dashboard.png
Normal file
|
After Width: | Height: | Size: 385 KiB |
BIN
docs/images/plex-dashboard.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
docs/images/portainer-containers.png
Normal file
|
After Width: | Height: | Size: 232 KiB |
BIN
docs/images/prometheus-targets.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
docs/images/storage-health-hdsentinel.png
Normal file
|
After Width: | Height: | Size: 156 KiB |