4.8 KiB
Homelab
Prerequisites
- Docker and Docker Compose
- Host paths used by the stacks:
/srv/homelab/srv/media/backup
Setup
1. Media dirs
sudo mkdir -p /srv/media/{movies,shows,downloads,immich}
sudo chown -R 1000:1000 /srv/media
2. Monitoring permissions
sudo mkdir -p /srv/homelab/data/monitoring/{prometheus,loki,grafana,alloy}
sudo chown -R 65534:65534 /srv/homelab/data/monitoring/prometheus
sudo chown -R 10001:10001 /srv/homelab/data/monitoring/loki
sudo chown -R 472:472 /srv/homelab/data/monitoring/grafana
sudo chown -R 10001:10001 /srv/homelab/data/monitoring/alloy
3. Env
- Glance:
stacks/monitoring/glance.env - Immich:
stacks/media/immich.env
Deploying
From the repo root (/srv/homelab):
| Stack | Command |
|---|---|
| Media | docker compose -f stacks/media/compose.yaml up -d |
| Monitoring | docker compose -f stacks/monitoring/compose.yaml up -d |
| Storage | docker compose -f stacks/storage/compose.yaml up -d |
To update images:
docker compose -f stacks/media/compose.yaml pull
docker compose -f stacks/media/compose.yaml up -d
To stop a stack:
docker compose -f stacks/media/compose.yaml down
Ports
| Service | Port(s) | Stack |
|---|---|---|
| Media | ||
| Sonarr | 8989 | media |
| Radarr | 7878 | media |
| Lidarr | 8686 | media |
| Prowlarr | 9696 | media |
| qBittorrent | 8081, 6881 (tcp/udp) | media |
| Jellyfin | 8096 | media |
| Immich | 2283 | media |
| Navidrome | 4533 | media |
| Seer | 5055 | media |
| Monitoring | ||
| Grafana | 3034 | monitoring |
| Prometheus | 9094 | monitoring |
| Loki | 3100 | monitoring |
| Node Exporter | 9100 | monitoring |
| Alloy | 12345 | monitoring |
| cAdvisor | 8088 | monitoring |
| Glance | 9090 | monitoring |
| Portainer | 9443, 8000 | monitoring |
| Storage | ||
| Gitea | 3000, 222 | storage |
| Copyparty | 3923 | storage |
Backup
Backups use Restic. The script backs up /srv/homelab (including data/), /etc/caddy/Caddyfile, and /etc/unbound/unbound.conf. It stops all Docker stacks before backup for consistent data, then starts them again—run it manually when you can afford a few minutes of downtime.
One-time setup
-
Install restic (e.g.
pacman -S resticor from restic.net). -
Copy the env example and set repository and password:
cp scripts/restic-backup.env.example scripts/restic-backup.env # Edit scripts/restic-backup.env: set RESTIC_REPOSITORY and RESTIC_PASSWORDExamples for
RESTIC_REPOSITORY:- Local:
RESTIC_REPOSITORY=/backup/restic - SFTP:
RESTIC_REPOSITORY=sftp:user@backup-host:/restic - S3:
RESTIC_REPOSITORY=s3:s3.amazonaws.com/bucket-name
- Local:
-
Initialize the repo (once):
export RESTIC_PASSWORD='your-password' restic -r /backup/restic init # use your actual repo path
Create a backup
From the repo root, run:
sudo ./scripts/restic-backup.sh
Stacks are stopped, then the backup runs, then they are started again. A failed backup still triggers the start so the homelab comes back up.
Inspect backups
List snapshots (IDs and timestamps):
source scripts/restic-backup.env
sudo restic snapshots -r $RESTIC_REPOSITORY
List files in a snapshot (e.g. latest or by ID):
restic ls latest -r $RESTIC_REPOSITORY
restic ls -r $RESTIC_REPOSITORY <snapshot-id>
Browse a path inside a snapshot:
restic ls latest -r $RESTIC_REPOSITORY /srv/homelab/config
See diffs between backups
Compare two snapshots (added, changed, removed files and content diff):
restic diff <older-snapshot-id> <newer-snapshot-id> -r $RESTIC_REPOSITORY
Restore
Restore the latest snapshot into a directory (does not overwrite the repo; use a separate target dir):
restic restore latest --target /tmp/restore -r $RESTIC_REPOSITORY
Restore a specific snapshot or path:
restic restore <snapshot-id> --target /tmp/restore -r $RESTIC_REPOSITORY
restic restore latest --path /etc/caddy --target /tmp/restore -r $RESTIC_REPOSITORY
After restore, fix ownership on data/ if needed (see Monitoring permissions).