From 3c035ccef3414c29dbe62a6ef53c366d6b7affbb Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 2 Nov 2026 02:28:37 -0800 Subject: [PATCH] fix(audiobookshelf): set the port with the env names the image actually reads The first deploy of the unit failed its own health gate in the worst possible shape: systemd said active (running), the engine logged a clean database init, and the server then listened on :80 under base path /audiobookshelf - so every probe of :8000 was refused and wait_for_health timed out at 180s beside a container that looked healthy. Cause: ABS_PORT / ABS_CONFIG_DIR / ABS_METADATA_DIR / ABS_PUID are the npm package's names, printed by the server README; this image never reads them. Its own contract, read off the pinned digest with podman inspect, is PORT=80 CONFIG_PATH=/config METADATA_PATH=/metadata, and the server greps for exactly PORT, CONFIG_PATH, METADATA_PATH, ROUTER_BASE_PATH. The two path variables appeared to work only because the image already exports the same values - the coincidence that made the inert lines look correct. The unit now speaks the image's names, adds ROUTER_BASE_PATH=/ so the service is the plain host:port the docs and the homepage card promise, and the dead ABS_* lines are deleted instead of kept as decoration. Proven against the same digest in a throwaway container (temp state dirs, loopback-only mapping, removed after): base path "/", listening on :8000, GET /healthcheck -> 200, and the old prefixed path -> 404. Guards: the quadlet seam now refuses an Environment=ABS_* line and requires PORT/ROUTER_BASE_PATH; the vault page gains the law with its failure signature and the two-second image-inspect check. Suite: ALL TESTS PASSED, 812 ok. --- .../quadlet/audiobookshelf.container | 17 ++++++++++++----- .../Dankserver/Audiobookshelf.md | 11 ++++++++++- tests/dankserver_quadlet.bats | 12 ++++++++++++ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/dankserver/audiobookshelf/quadlet/audiobookshelf.container b/dankserver/audiobookshelf/quadlet/audiobookshelf.container index 8a0ddce..e694cbd 100644 --- a/dankserver/audiobookshelf/quadlet/audiobookshelf.container +++ b/dankserver/audiobookshelf/quadlet/audiobookshelf.container @@ -26,11 +26,18 @@ After=network.target ContainerName=audiobookshelf Image=ghcr.io/advplyr/audiobookshelf:latest@sha256:37c2057e150694970442579815c646fe6bdc01c95b9d1547c4c9068be8844ef3 Network=pasta -Environment=ABS_CONFIG_DIR=/config -Environment=ABS_METADATA_DIR=/metadata -Environment=ABS_PGID=1000 -Environment=ABS_PORT=8000 -Environment=ABS_PUID=1000 +# The names are the image's own: the server reads PORT, CONFIG_PATH, METADATA_PATH +# and ROUTER_BASE_PATH (measured against the digest below — `podman inspect` shows +# PORT=80 CONFIG_PATH=/config METADATA_PATH=/metadata in the image ENV, and the +# server's source greps for exactly these). The ABS_* family printed by the server +# README is the npm package's naming and is INERT here: with ABS_PORT=8000 the +# server listened on :80 under base path /audiobookshelf, so the unit sat +# `active (running)` while every probe to :8000 was refused (measured 2026-11-02, +# first deploy). ROUTER_BASE_PATH=/ is what makes the URL the plain host:port. +Environment=PORT=8000 +Environment=ROUTER_BASE_PATH=/ +Environment=CONFIG_PATH=/config +Environment=METADATA_PATH=/metadata Environment=TZ=America/Vancouver PublishPort=8000:8000 Volume=/home/dank/Containers/audiobookshelf/config:/config diff --git a/serverAppConfigs-docs/Dankserver/Audiobookshelf.md b/serverAppConfigs-docs/Dankserver/Audiobookshelf.md index c7eaab0..e856ca0 100644 --- a/serverAppConfigs-docs/Dankserver/Audiobookshelf.md +++ b/serverAppConfigs-docs/Dankserver/Audiobookshelf.md @@ -25,7 +25,8 @@ manager) — **Internal-only:** LAN address, no vhost, no DNS name. |------|-------| | Unit file | `dankserver/audiobookshelf/quadlet/audiobookshelf.container` (the authority for every number here) | | Image | `ghcr.io/advplyr/audiobookshelf` pinned by **amd64 manifest digest** — see Laws | -| Port | `PublishPort=8000:8000` — web UI and API on the same port | +| Port | `Environment=PORT=8000` + `PublishPort=8000:8000` — web UI and API on one port | +| Base path | `Environment=ROUTER_BASE_PATH=/` — the URL is the plain `host:port`, no `/audiobookshelf` prefix | | Network | `pasta` (standalone; publishes nothing to other containers) | | Audio bind | `/mnt/entropy/Audiobooks:/audiobooks:ro` — read-only, by design | | State | `/home/dank/Containers/audiobookshelf/config` → `/config`, `…/metadata` → `/metadata` (both NVMe) | @@ -52,6 +53,14 @@ browser and lives in the `config` bind on the SSD. ## Laws +- **Speak the image's env names, not the README's.** The server reads `PORT`, + `CONFIG_PATH`, `METADATA_PATH` and `ROUTER_BASE_PATH`; the `ABS_*` family printed + by the server's own README is the npm package's naming and is **inert** in this + image. Measured 2026-11-02 on the first deploy: with `ABS_PORT=8000` the server + listened on `:80` under base path `/audiobookshelf`, so `systemctl` said + `active (running)` while every probe of `:8000` was refused and the deploy gate + failed at 180 s. Two seconds with the pinned digest settles it: + `podman inspect --format '{{.Config.Env}}' `. - **The audio bind stays `:ro`.** ABS writes nothing that belongs beside the audio: its library, covers, progress and sidecar metadata all land in `/metadata` on the SSD. A writable bind would put stray writes on the spindle diff --git a/tests/dankserver_quadlet.bats b/tests/dankserver_quadlet.bats index b316055..ae4b34e 100755 --- a/tests/dankserver_quadlet.bats +++ b/tests/dankserver_quadlet.bats @@ -175,3 +175,15 @@ load helpers printf '%s\n' "$body" | grep -q 'audiobookshelf/metadata' || return 1 printf '%s\n' "$body" | grep -q 'wait_for_health audiobookshelf' || return 1 } + +@test "audiobookshelf sets its port and base path with the names the image reads" { + # Measured 2026-11-02 on the first deploy: ABS_PORT / ABS_CONFIG_DIR are the npm + # package's names and this image ignores them, so the server came up on :80 + # under base path /audiobookshelf and the deploy gate timed out beside a unit + # that was active (running). PORT and ROUTER_BASE_PATH are what the image's own + # ENV block and the server source actually use. + unit="$REPO_ROOT/dankserver/audiobookshelf/quadlet/audiobookshelf.container" + grep -q '^Environment=PORT=8000$' "$unit" || return 1 + grep -q '^Environment=ROUTER_BASE_PATH=/$' "$unit" || return 1 + ! grep -qE '^Environment=ABS_' "$unit" || return 1 +}