Files
ansible-pull-deploy/plans/06-data-and-persistence.md
Artemis (Iron Legion) d60bc96f1d Add homelab services stack PRD
Verifies 16 DockerHub images, assigns target nodes per locked policy,
defines 3-phase deployment order (Infra → Media → Polish),
and captures open questions for Bobby.

Services: Traefik, Technitium DNS, AdGuard Home, Prometheus, Grafana,
Beszel, Dozzle, Portainer, Homepage, Authelia, Vaultwarden, Jellyfin,
Sonarr, Radarr, Prowlarr, Nextcloud

Domain: *.ai.home
No public internet exposure.
2026-05-25 17:17:23 -04:00

47 lines
2.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Iron Legion Homelab Services Stack — Data & Persistence
## Volume Strategy
Every service with persistent state uses **bind mounts to on-node directories**. No named volumes, no NFS, no distributed storage.
## Directory Convention
```
/opt/iron-legion/
├── service-name/
│ ├── data/ # Application data (databases, config, state)
│ ├── config/ # Static config files mounted read-only where possible
│ └── logs/ # Log output (optional, if not sent to stdout)
```
## Per-Service Persistence
| Service | Data Path | Backup Target | Size Estimate |
|---------|-----------|---------------|---------------|
| **Traefik** | `/opt/iron-legion/traefik/config/` `/opt/iron-legion/traefik/certs/` | Bones (daily rsync) | < 50 MB |
| **Technitium DNS** | `/opt/iron-legion/technitium/config/` | Bones | < 10 MB |
| **Pi-hole** | `/opt/iron-legion/pihole/etc-pihole/` `/opt/iron-legion/pihole/etc-dnsmasq.d/` | Bones | < 500 MB |
| **Prometheus** | `/opt/iron-legion/prometheus/data/` | Bones (retention: 15d local, 90d backup) | 520 GB |
| **Grafana** | `/opt/iron-legion/grafana/data/` | Bones | < 500 MB |
| **Beszel** | `/opt/iron-legion/beszel/data/` | Bones | < 1 GB |
| **Portainer** | `/opt/iron-legion/portainer/data/` | Bones | < 100 MB |
| **Homepage** | `/opt/iron-legion/homepage/config/` | Bones | < 10 MB |
| **Vaultwarden** | `/opt/iron-legion/vaultwarden/data/` | Bones (encrypted) | < 500 MB |
| **Authelia** | `/opt/iron-legion/authelia/config/` | Bones | < 10 MB |
| **Jellyfin** | `/opt/iron-legion/jellyfin/config/` `/opt/iron-legion/jellyfin/media/` | **None** (media too large) | < 1 GB config; media drive separate |
| **Sonarr** | `/opt/iron-legion/sonarr/config/` | Bones | < 1 GB |
| **Radarr** | `/opt/iron-legion/radarr/config/` | Bones | < 1 GB |
| **Prowlarr** | `/opt/iron-legion/prowlarr/config/` | Bones | < 100 MB |
| **Nextcloud** | `/opt/iron-legion/nextcloud/data/` | Bones (snapshots) | 1050 GB |
## Media Storage Exception
- **Jellyfin media** lives on a separate mount (likely external USB/NVMe on Mark44). Not backed up via rsync.
- **Sonarr/Radarr** download staging to a shared `/downloads` bind mount, then hardlink/copy to Jellyfin media library.
## Backup Tooling
- **Primary:** `rsync -a --delete` to Bones secondary storage daily at 03:00 local.
- **Vaultwarden:** `rsqlite3` dump + `rsync` (encrypted at rest on Bones).
- **Prometheus:** `snapshot API` → rsync (not raw WAL files).
## Secret Management
- `.env` files live in `/opt/iron-legion/service-name/.env`, mode `0600`.
- Compose files use `${VAR_NAME}` syntax, never literal strings.
- Vaultwarden stores shared secrets (DB passwords, API keys). Artemis holds no secrets in memory.