homelab-codex-ws/services/narty27/README.md
oskar 2e13a7d1bb feat(narty27): statyczny hosting viz.html na PIHA (nginx + named volume)
Nowy serwis services/narty27 — nginx:alpine serwujacy jeden self-contained
plik viz.html z named volume narty27_content (:ro). Port 8240 to nastepny
wolny w bloku 82x0 na PIHA (8210 paperless, 8220 nextcloud, 8230 kb-query).

Content jest personal: zyje wylacznie w volume narty27_narty27_content i w
zrodle na SOLARII (~/narty-2027/saalbach-kb/viz.html). Nigdy w repo, bez
backup joba, bez bindu pod /opt/homelab/data.

Procedura aktualizacji w README uzywa kontenera-pomocnika (alpine z volume
rw), NIE `docker cp` — przy mount :ro docker cp zwraca "mounted volume is
marked read-only", zarowno dla dzialajacego jak i zatrzymanego kontenera
(zweryfikowane empirycznie 2026-07-31). Zapisywane sa dwie kopie tego samego
pliku: viz.html (nazwa kanoniczna) + index.html (zeby golny root dzialal).

Walidacja: docker compose config OK (volume rozwija sie do
narty27_narty27_content), YAML parse OK, bash -n healthcheck.sh OK.
Bez zywego deployu.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 16:38:55 +02:00

2.7 KiB

narty27

Static hosting for a single self-contained viz.html (narty 2027 / Saalbach KB export) on PIHA. Plain nginx:alpine serving one Docker named volume — no build, no database, no dependencies.

  • URL: http://192.168.31.5:8240/viz.html (and / — same file, see below)
  • Exposure: private (LAN/Tailscale only; no npm vhost, no public ingress)
  • Volume: narty27_narty27_content/usr/share/nginx/html:ro

Content is personal and lives outside the repo

The visualisation is personal content. It is never committed — not to this repo, not to any other. It exists in exactly two places:

  1. the source on SOLARIA (~/narty-2027/saalbach-kb/viz.html), and
  2. the narty27_narty27_content Docker volume on PIHA.

There is no backup job and no bind mount under /opt/homelab/data/. If the volume is lost, re-run the update procedure below from SOLARIA.

Two copies of the same file are stored in the volume: viz.html (canonical name) and index.html (so the bare root http://192.168.31.5:8240/ works without a path). Both must be refreshed together on every update.

Updating the content (from SOLARIA)

# 1. Ship the file to PIHA
scp ~/narty-2027/saalbach-kb/viz.html piha:/tmp/viz.html

# 2. Write BOTH copies into the volume via a throwaway helper container
ssh piha 'docker run --rm \
    -v narty27_narty27_content:/content \
    -v /tmp:/src:ro \
    alpine sh -c "cp /src/viz.html /content/viz.html && cp /src/viz.html /content/index.html"'

# 3. Drop the staging copy
ssh piha 'rm -f /tmp/viz.html'

# 4. Verify (no container restart needed — nginx serves from disk per request)
curl -sf -o /dev/null -w '%{http_code}\n' http://192.168.31.5:8240/viz.html
curl -sf -o /dev/null -w '%{http_code}\n' http://192.168.31.5:8240/

Why a helper container and not docker cp: the volume is mounted :ro into the nginx container, and docker cp writes through the container's mount namespace — it fails with mounted volume is marked read-only, for both running and stopped containers (verified 2026-07-31). The helper container mounts the same volume read-write and bypasses nginx entirely.

First start

nginx:alpine seeds an empty named volume with its own default index.html and 50x.html on first run, so the root will show the nginx welcome page until step 2 above overwrites index.html. Until then /viz.html 404s and the container healthcheck reports unhealthy — this is expected, not a failure.

Operations

docker compose -f services/narty27/docker-compose.yml up -d   # on PIHA
./healthcheck.sh                                              # container + both paths
docker volume ls | grep narty27                               # narty27_narty27_content