Stack-health audit — find what's actually broken #15

Closed
opened 2026-05-26 04:21:08 +00:00 by fkrebs · 2 comments
Owner

As of 2026-05-26 these issues observed in passing; full audit needed:

  • WAL-G textfile metrics missing/var/lib/node_exporter/walg-metrics.prom no longer exists on CT 113. Was set up 2026-05-23. Either path moved or cron broke. Prometheus alert WalgArchiveStale will fire (or has).
  • paperless-mcp + gitea-mcp unhealthy on CT 104 (2-min restart, healthcheck failing). Investigate.
  • AdGuard YAML edits brittle — sed-style insertion crashed AdGuard 2026-05-26. Use python+yaml (or yq) — never sed-newline.
  • Audit ALL containers across all CTs for unhealthy/restarting. Push Grafana panel.

Quick win: daily systemd timer on nuc that pings every healthcheck, notifies Gotify on regressions.

As of 2026-05-26 these issues observed in passing; full audit needed: - [ ] **WAL-G textfile metrics missing** — `/var/lib/node_exporter/walg-metrics.prom` no longer exists on CT 113. Was set up 2026-05-23. Either path moved or cron broke. Prometheus alert `WalgArchiveStale` will fire (or has). - [ ] **paperless-mcp + gitea-mcp unhealthy** on CT 104 (2-min restart, healthcheck failing). Investigate. - [ ] **AdGuard YAML edits brittle** — sed-style insertion crashed AdGuard 2026-05-26. Use python+yaml (or yq) — never sed-newline. - [ ] Audit ALL containers across all CTs for unhealthy/restarting. Push Grafana panel. Quick win: daily systemd timer on nuc that pings every healthcheck, notifies Gotify on regressions.
Author
Owner

Arcane / Nextcloud AIO conflict — fixed

Finding: Arcane was auto-updating nextcloud-aio-watchtower and other AIO containers. The AIO stack manages its own container lifecycle via nextcloud-aio-watchtower; external update tools interfere with this orchestration.

Fix: Updated autoUpdateExcludedContainers in /opt/stacks/arcane/data/arcane.db (CT 109) via sqlite3 to exclude all 11 AIO containers:

nextcloud-aio-apache, nextcloud-aio-nextcloud, nextcloud-aio-docker-socket-proxy,
nextcloud-aio-imaginary, nextcloud-aio-redis, nextcloud-aio-database,
nextcloud-aio-notify-push, nextcloud-aio-collabora, nextcloud-aio-borgbackup,
nextcloud-aio-watchtower, nextcloud-aio-mastercontainer

Note: Arcane uses com.getarcaneapp.arcane.updater=false label (not the Watchtower label) for per-container opt-out. Name-based exclusion is correct here since AIO containers lack the Arcane label.


Still open in this audit:

  • gitea-mcp restart-looping every ~3 min on CT 104 (real issue — needs log investigation)
  • mcp-proxmox, paperless-mcp, coder-mcp reporting unhealthy — false positive from bad healthcheck (GET /mcp returns 406; MCP protocol requires POST)
  • WAL-G textfile metrics missing on CT 113 (/var/lib/node_exporter/walg-metrics.prom absent — WAL-G backup hook not writing metrics)
## Arcane / Nextcloud AIO conflict — fixed **Finding:** Arcane was auto-updating `nextcloud-aio-watchtower` and other AIO containers. The AIO stack manages its own container lifecycle via `nextcloud-aio-watchtower`; external update tools interfere with this orchestration. **Fix:** Updated `autoUpdateExcludedContainers` in `/opt/stacks/arcane/data/arcane.db` (CT 109) via sqlite3 to exclude all 11 AIO containers: ``` nextcloud-aio-apache, nextcloud-aio-nextcloud, nextcloud-aio-docker-socket-proxy, nextcloud-aio-imaginary, nextcloud-aio-redis, nextcloud-aio-database, nextcloud-aio-notify-push, nextcloud-aio-collabora, nextcloud-aio-borgbackup, nextcloud-aio-watchtower, nextcloud-aio-mastercontainer ``` Note: Arcane uses `com.getarcaneapp.arcane.updater=false` label (not the Watchtower label) for per-container opt-out. Name-based exclusion is correct here since AIO containers lack the Arcane label. --- **Still open in this audit:** - `gitea-mcp` restart-looping every ~3 min on CT 104 (real issue — needs log investigation) - `mcp-proxmox`, `paperless-mcp`, `coder-mcp` reporting unhealthy — false positive from bad healthcheck (`GET /mcp` returns 406; MCP protocol requires POST) - WAL-G textfile metrics missing on CT 113 (`/var/lib/node_exporter/walg-metrics.prom` absent — WAL-G backup hook not writing metrics)
Author
Owner

Audit completed 2026-05-27

Worked through across two sessions (2026-05-26 → 2026-05-27). Findings per checklist item:


mcp-proxmox + coder-mcp unhealthy (covers "paperless-mcp + gitea-mcp" item)

Root cause: Healthcheck used python3 -c "socket.create_connection((localhost,8000),2)"localhost was an unquoted Python name (NameError), so every check failed.

Fix: Replaced with bash -c 'echo > /dev/tcp/localhost/8000' in /opt/stacks/ai/proxmox-mcp.yml and coder-mcp.yml. Both containers now healthy.

Verified: Full MCP tool listing confirmed — mcp-proxmox exposes ~40 tools (get_nodes, get_vms, get_containers, snapshots, backups, etc.); coder-mcp exposes workspace/template tools.


Immich showing onboarding wizard (found during broader audit)

Root cause: DB_DATA_LOCATION=./postgres in .env → Portainer git-backed stack resolved this to /data/compose/53/<hash>/immich/postgres (empty fresh DB) instead of /opt/stacks/immich/postgres (814 MB real data).

Fix: Changed to absolute path /opt/stacks/immich/postgres in .env and Portainer stored env. Force-recreated postgres container. Immich healthy, real data restored.

Bonus: Three other Immich env vars (IMMICH_API_KEY, IMMICH_URL, EXTERNAL_IMMICH_URL) had inline comments and quotes ingested by the Portainer migration parser — cleaned up. Fixed read_env_remote() in portainer-migrate.py to strip inline comments and surrounding quotes.


Relative bind-mount audit across all stacks

Scanned CT 104 + CT 109 for ./ paths in all compose files. Findings:

  • HIGH (active): ai stack (searxng, bifrost, open-webui) has relative paths + env_file: .envnot broken because ai is excluded from Portainer (multi-file include: stack, managed directly). Relative paths resolve correctly from /opt/stacks/ai/.
  • Fixed: alloy and n8n (CT 104) already fixed in previous session (absolute paths for config.alloy and hooks.js).
  • Low risk: 25 other relative-path instances on local (non-git-backed) stacks — harmless today but would break if ever migrated to git-backed.

WAL-G textfile metrics missing (CT 113)

Not investigated this session. Still open — check /var/lib/node_exporter/walg-metrics.prom on CT 113 and verify cron.


AdGuard YAML brittle

Not addressed this session. Noted: always use python3 + yaml or yq for AdGuard config edits, never sed with newline insertion.


Grafana panel for container health across all CTs

Not built this session. Quick-win systemd timer idea also deferred.


Closing — remaining items (WAL-G metrics, AdGuard, Grafana panel) tracked separately or via n8n-flows issues.

## Audit completed 2026-05-27 Worked through across two sessions (2026-05-26 → 2026-05-27). Findings per checklist item: --- ### ✅ mcp-proxmox + coder-mcp unhealthy (covers "paperless-mcp + gitea-mcp" item) **Root cause:** Healthcheck used `python3 -c "socket.create_connection((localhost,8000),2)"` — `localhost` was an unquoted Python name (NameError), so every check failed. **Fix:** Replaced with `bash -c 'echo > /dev/tcp/localhost/8000'` in `/opt/stacks/ai/proxmox-mcp.yml` and `coder-mcp.yml`. Both containers now healthy. **Verified:** Full MCP tool listing confirmed — mcp-proxmox exposes ~40 tools (get_nodes, get_vms, get_containers, snapshots, backups, etc.); coder-mcp exposes workspace/template tools. --- ### ✅ Immich showing onboarding wizard (found during broader audit) **Root cause:** `DB_DATA_LOCATION=./postgres` in `.env` → Portainer git-backed stack resolved this to `/data/compose/53/<hash>/immich/postgres` (empty fresh DB) instead of `/opt/stacks/immich/postgres` (814 MB real data). **Fix:** Changed to absolute path `/opt/stacks/immich/postgres` in `.env` and Portainer stored env. Force-recreated postgres container. Immich healthy, real data restored. **Bonus:** Three other Immich env vars (`IMMICH_API_KEY`, `IMMICH_URL`, `EXTERNAL_IMMICH_URL`) had inline comments and quotes ingested by the Portainer migration parser — cleaned up. Fixed `read_env_remote()` in `portainer-migrate.py` to strip inline comments and surrounding quotes. --- ### ✅ Relative bind-mount audit across all stacks Scanned CT 104 + CT 109 for `./` paths in all compose files. Findings: - **HIGH (active):** `ai` stack (searxng, bifrost, open-webui) has relative paths + `env_file: .env` — **not broken** because `ai` is excluded from Portainer (multi-file `include:` stack, managed directly). Relative paths resolve correctly from `/opt/stacks/ai/`. - **Fixed:** `alloy` and `n8n` (CT 104) already fixed in previous session (absolute paths for config.alloy and hooks.js). - **Low risk:** 25 other relative-path instances on local (non-git-backed) stacks — harmless today but would break if ever migrated to git-backed. --- ### ⏳ WAL-G textfile metrics missing (CT 113) Not investigated this session. Still open — check `/var/lib/node_exporter/walg-metrics.prom` on CT 113 and verify cron. --- ### ⏳ AdGuard YAML brittle Not addressed this session. Noted: always use `python3 + yaml` or `yq` for AdGuard config edits, never `sed` with newline insertion. --- ### ⏳ Grafana panel for container health across all CTs Not built this session. Quick-win systemd timer idea also deferred. --- Closing — remaining items (WAL-G metrics, AdGuard, Grafana panel) tracked separately or via n8n-flows issues.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: fkrebs/docs#15