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>
66 lines
2.7 KiB
Markdown
66 lines
2.7 KiB
Markdown
# 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)
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
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
|
|
```
|