README.md

# homelab-compose

The docker-compose stack and support scripts that run on the single NUC
sitting under my desk. Media, photos, documents, DNS, git, metrics. One
Caddy in front doing TLS.

This repo is opinionated and not generic. Read it, copy what makes sense,
don't `git clone && up -d`.

## Layout

    docker-compose.yml     all the services
    Caddyfile              reverse proxy
    scripts/backup.sh      daily cron: rsync -> local snapshot -> B2
    scripts/restore.sh     pull one snapshot back from B2
    scripts/health-check.sh  curl each service, alert on non-200
    .env.example           copy to .env and fill in

## First run

    cp .env.example .env
    $EDITOR .env
    docker compose up -d

Caddy grabs TLS certs from your internal CA on start. I use step-ca with
a local root; adjust `tls` directives if you use ACME.

## Updating

I don't auto-update. Every Sunday morning I run:

    docker compose pull
    docker compose up -d

...and read the changelogs for anything that got a minor bump. Paperless
and Immich have been the noisy ones.

## Backups

`scripts/backup.sh` is wired into cron at 03:15 every night:

    15 3 * * * /srv/homelab/scripts/backup.sh >> /var/log/homelab-backup.log 2>&1

It snapshots `/srv/data` with rsync --link-dest, then rclones the newest
snapshot to Backblaze B2. Retention: 30 daily + 12 monthly local, same on
B2. Test restore quarterly with `scripts/restore.sh --dry-run`.

## Health check

`scripts/health-check.sh` runs from cron every 5 minutes and hits each
service's health endpoint. Exit 0 = all good, 1 = one service failed, 2 =
multiple. Cron mails me on non-zero.

## Services

- jellyfin   media server, hardware-transcode via /dev/dri
- immich     photos, needs a postgres and redis next to it
- paperless  OCR document archive
- gitea      git, for the stuff I don't put on mercemay.top/src/
- syncthing  laptop<->NUC folder sync
- pihole     DNS + blocklist
- prometheus scrapes node + blackbox exporters
- grafana    dashboards

## License

Unlicense. See `LICENSE`. The config is obvious once you see it.