- Move PORTMAP, storage, volumes, docker-networks from stacks/ → infra/ - Remove stacks/todo.md (content migrated to CHANGELOG + ideas) - portmap: add new MCP servers (18005/07/09/10/11), fix s3.nuclide.systems entry, update Daytona OIDC row to DECOMMISSIONED, add Vaultwarden OIDC placeholder, add DevOps table row for MCP server Gitea repos - storage: add Garage S3 buckets subsection (lobe-files + chat-artifacts) - docker-networks: remove daytona-minimal_daytona-network row + daytona from "Stacks Keeping Own Networks" list - ct-inventory: add CT 112 (secrets/Infisical, planned) - CHANGELOG: prepend 2026-05-21 entry (docs, S3, MCP, dev env, Gitea repos, planned) - ideas/stack-ideas: add §11 Renovate Bot, §12 egress firewall, §13 local LLM - mkdocs.yml: replace nav — dissolve Stacks chapter, add infra/ entries
6.9 KiB
Storage layout
Verified state as of 2026-05-21. Source of truth for which service lives on which storage class. Earlier revisions of this doc were stale on multiple items (Garage, n8n, Arcane, Karakeep, Pocket-ID, arr-stack, Nextcloud's storage protocol, missing Coder/Gitea). Reconciled via live audit.
Storage classes
| Class | Substrate | Where | Typical use |
|---|---|---|---|
| Local zfs (rootfs) | NVMe in nuc | /opt/stacks/<stack>/ on each LXC |
Tier-1 hot state: databases, SQLite, secret stores, anything latency-sensitive |
| Local zfs (subvol) | NVMe in nuc | rpool/data/subvol-<NNN>-disk-0 per LXC |
Container rootfs, image cache |
| Docker named volume | NVMe in nuc | /var/lib/docker/volumes/... on each Docker CT |
Per-container persistent state managed by Docker |
| UNAS over NFSv3 | 192.168.1.31 |
/mnt/pve/unas on CTs 101, 103, 104, 111 |
Bulk media, workspace home dirs, document storage |
| UNAS over CIFS/SMB 3.1.1 | 192.168.1.31 |
/mnt/pve/unas on CT 105 (Nextcloud) |
Nextcloud-only path — earlier docs mis-labelled this as NFS |
What lives where (verified 2026-05-21)
UNAS NFS — /mnt/pve/unas/services/...
Bulk + media + non-latency-sensitive app data.
| Service | CT | Path on UNAS → in container | Backed up? | Notes |
|---|---|---|---|---|
| Immich (uploads, thumbs, derived) | 104 | services/immich/{encoded-video,profile,thumbs} + media/images + backup/immich |
Immich own pg_dump → media/images/db-dumps; no off-host copy |
|
| Paperless-ngx (documents) | 104 | media/documents/public/paperless-ngx/{consume,export,library} |
none | |
| Paperless-AI | 104 | services/paperless-ai → /app/data |
none | |
| Vaultwarden (attachments + SQLite DB) | 104 | services/vaultwarden → /data |
none | tier-1 DB on NFS — risky, plan to move local |
| Traccar (logs, config) | 104 | services/traccar/{logs,traccar.xml} |
none | data dir reverted to local /opt/stacks/traccar/data |
| Memos | 104 | services/memos → /var/opt/memos |
none | |
| Arr-stack (Audiobookshelf, Prowlarr, RDTClient, Shelfarr) + media | 104 | services/arr-stack/* + media/{audiobooks,ebooks,podcasts,Torrents} |
none | already migrated (older doc claimed "still local") |
| Gluetun (VPN) | 104 | services/gluetun/data → /gluetun |
none | |
| Gitea | 111 | services/gitea → /data |
none | new 2026-05-20 |
| Coder workspace home dirs | 111 | services/coder/<user>/<workspace> → /home/<user> |
none | new 2026-05-20 |
| Backrest's jottacloud-mirrored data | 103 | media/data-dir only |
rclone → jottacloud (Backrest) | only path with off-host backup |
Local zfs — /opt/stacks/...
Tier-1 state and anything that should NOT be NFS-backed.
| Service | CT | Local path → in container | Backed up? | Notes |
|---|---|---|---|---|
| Pocket-ID | 110 | /opt/stacks/pocketid/data → /app/data |
none | CT 110 has no NFS mount at all. Earlier doc said UNAS — incorrect. |
| Garage (S3 meta + data) | 104 | /opt/stacks/shared-db/garage/{data,meta} → /var/lib/garage/* |
none | moved off NFS 2026-05-19 after WAL-G outage. Stale copy may still exist on UNAS. |
| Shared Postgres (multi-stack) | 104 | docker named volume shared-db_shared-pgdata |
WAL-G → local Garage (configured; outage 2026-05-19 prompted move) | Garage itself is single-disk local — no off-host copy. |
| n8n | 104 | /opt/stacks/n8n/data → /home/node/.n8n |
none | back to local after PG migration attempt failed. Stale 408 MB database.sqlite left on UNAS (May 15) — clean up. n8n now uses shared-postgres as its actual DB. |
| Arcane | 104 | /opt/stacks/arcane/data → /app/data |
none | reverted from UNAS to local 2026-05-19 (undocumented before now) |
| Karakeep + Meilisearch | 104 | /opt/stacks/karakeep/localdata/{data,meili} |
none | reverted from UNAS to local |
| Immich Postgres (pgvector) | 104 | /opt/stacks/immich/postgres → /var/lib/postgresql/data |
Immich pg_dump → UNAS | tier-1; PG demands local disk |
| Homepage | 104 | /opt/stacks/homepage/{config,icons} |
none | |
| Dozzle | 104 | /opt/stacks/dozzle/dozzle_data |
none | |
| LiteLLM config | 104 | /opt/stacks/ai/litellm-config |
none | |
| SearXNG config | 104 | /opt/stacks/ai/searxng |
none | |
| Flaresolverr | 104 | /var/lib/flaresolver |
none | |
| AdGuard / Zoraxy / DNS / Shepard / Backrest binaries | 102/108/103/101 | local zfs only | none | Backrest itself has no self-backup |
| Nextcloud config + sidecars | 105 | local zfs (CT rootfs) | none | data path is CIFS — see below |
Garage S3 buckets (on local zfs, CT 104)
| Bucket | Access key | Use | Public URL |
|---|---|---|---|
lobe-files |
GK55210… (from .env) |
LobeHub file uploads + WAL-G PG backups | internal only |
chat-artifacts |
GK50bfc… | AI chat output artefacts (images, reports, SVG) | https://chat-artifacts.s3.nuclide.systems/<key> |
Docker named volumes
Local on /var/lib/docker/volumes/. Mostly databases and caches.
| Volume | Service / CT | Backed up? |
|---|---|---|
shared-db_shared-pgdata |
shared-postgres / 104 | WAL-G → local Garage |
paperless-ngx_pgdata, _redisdata, _data |
paperless-ngx / 104 | none |
lobe-postgres + lobe-redis |
lobehub / 104 | none |
nuc-ai-core_rustfs-data |
lobehub stack / 104 | none |
pgadmin-data |
pgadmin / 104 | none (regenerable) |
immich_model-cache |
immich-ml / 104 | regenerable |
coder-db + gitea-db (docker volume coder-db) |
/ 111 | none |
(orphaned) daytona-minimal_db_data + runner anon vol |
/ 104 | none — clean up post-decommission |
Nextcloud (CT 105) — the CIFS outlier
Nextcloud AIO mounts //192.168.1.31/storage over CIFS/SMB 3.1.1, not NFS like every other CT. Application data path is under that mount. The Postgres + Redis sidecars stay on local docker volumes.
Backup reality
There is effectively no off-host backup of service data. The only configured Backrest plan covers /mnt/pve/unas/media/data-dir → jottacloud — i.e., Backrest backs up one specific UNAS path, not the services that write to UNAS.
Coverage:
- Immich pg_dump → UNAS (same filer; survives container loss, not filer loss)
- shared-postgres WAL-G → Garage (same host; survives container loss, not disk loss)
- Everything else: zero
This is a known gap. Plans:
- Extend Backrest plans to snapshot tier-1 paths (Pocket-ID sqlite, Vaultwarden data, Gitea repos, Coder workspace homes) to jottacloud nightly.
- Once the second NVMe lands (see
infra/proxmox-state.md§6), mirrorrpoolso a single disk death doesn't take everything.
Drift cleanup TODO
- Remove stale
services/n8n/database.sqlite(408 MB, last write 2026-05-15) from UNAS. - Remove stale
services/shared-db/garage/copy from UNAS if present. - Remove orphaned
daytona-minimal_db_dataDocker volume on CT 104. - Vaultwarden
data/on UNAS — plan to migrate to local zfs (latency + tier-1). - Add a Backrest plan for Pocket-ID DB and Gitea data → jottacloud.