fix(audiobookshelf): set the port with the env names the image actually reads #118

Merged
dank merged 1 commits from fix/audiobookshelf-image-env into main 2026-11-02 02:28:45 -08:00
Owner

The failure this fixes

The first deploy of #117 failed its own health gate: audiobookshelf.service came up
active (running), the engine logged a clean database init, and then — Listening on port :80 and Serving from base path "/audiobookshelf". Nothing on :8000, so
wait_for_health refused at 180 s. The unit was healthy-looking and deaf at the same
time, which is the worst shape a gate can catch.

Cause

ABS_PORT, ABS_CONFIG_DIR, ABS_METADATA_DIR, ABS_PUID/ABS_PGID are the npm
package's
environment names, printed by the server README. The container image never
reads them. Its own contract, taken off the pinned digest:

$ podman inspect --format '{{.Config.Env}}' <image>
PORT=80 CONFIG_PATH=/config METADATA_PATH=/metadata SOURCE=docker …

and the server source greps for exactly PORT, CONFIG_PATH, METADATA_PATH,
ROUTER_BASE_PATH, HOST, JWT_SECRET_KEY… So the port fell back to the image
default 80, the router kept its /audiobookshelf prefix, and the two path variables
were honoured only because the image already exports the same values I was trying to
set — a coincidence that made the inert lines look correct.

The fix

Speak the image's names:

Environment=PORT=8000
Environment=ROUTER_BASE_PATH=/
Environment=CONFIG_PATH=/config
Environment=METADATA_PATH=/metadata

ROUTER_BASE_PATH=/ also drops the prefix, so the service is the plain
http://192.168.0.235:8000 the docs and the homepage card already promise. The dead
ABS_* lines are deleted rather than kept as decoration.

Proven against the same digest before touching the unit — a throwaway container with
temp state dirs and a loopback-only port, removed afterwards:

[Server] Serving from base path "/"
Listening on port :8000
GET /healthcheck                 -> 200 OK
GET /audiobookshelf/healthcheck  -> 404

Guards and docs

  • One assertion in tests/dankserver_quadlet.bats: the unit sets PORT=8000 and
    ROUTER_BASE_PATH=/, and carries no Environment=ABS_* line. That is the
    regression, not a re-pinning of a constant.
  • The vault page gains the law — speak the image's env names, not the README's — with
    the failure signature (active (running) + probes refused) and the two-second
    podman inspect --format '{{.Config.Env}}' check that settles any such question.
    Its Shape table now names the env vars behind the port and the base path.

Deploy after merge

./scripts/deploy.sh dankserver --service audiobookshelf, then the homepage card on
Dankclaw. The database initialized correctly on the failed attempt (the image's own
path defaults matched the binds), so no state cleanup is involved — and no user data
exists yet: the owner account is still the first-run step, which only Frank can do,
from the LAN.


cwd: /home/blank/.omp/wt/wt-20261030-163847-6d1fc1f · session: 01a18f2e-18b1-7573-bcd5-ac99636f8bcb

## The failure this fixes The first deploy of #117 failed its own health gate: `audiobookshelf.service` came up `active (running)`, the engine logged a clean database init, and then — `Listening on port :80` and `Serving from base path "/audiobookshelf"`. Nothing on `:8000`, so `wait_for_health` refused at 180 s. The unit was healthy-looking and deaf at the same time, which is the worst shape a gate can catch. ## Cause `ABS_PORT`, `ABS_CONFIG_DIR`, `ABS_METADATA_DIR`, `ABS_PUID`/`ABS_PGID` are the **npm package's** environment names, printed by the server README. The container image never reads them. Its own contract, taken off the pinned digest: ``` $ podman inspect --format '{{.Config.Env}}' <image> PORT=80 CONFIG_PATH=/config METADATA_PATH=/metadata SOURCE=docker … ``` and the server source greps for exactly `PORT`, `CONFIG_PATH`, `METADATA_PATH`, `ROUTER_BASE_PATH`, `HOST`, `JWT_SECRET_KEY`… So the port fell back to the image default 80, the router kept its `/audiobookshelf` prefix, and the two path variables were honoured only because the image already exports the same values I was trying to set — a coincidence that made the inert lines look correct. ## The fix Speak the image's names: ``` Environment=PORT=8000 Environment=ROUTER_BASE_PATH=/ Environment=CONFIG_PATH=/config Environment=METADATA_PATH=/metadata ``` `ROUTER_BASE_PATH=/` also drops the prefix, so the service is the plain `http://192.168.0.235:8000` the docs and the homepage card already promise. The dead `ABS_*` lines are deleted rather than kept as decoration. Proven against the same digest before touching the unit — a throwaway container with temp state dirs and a loopback-only port, removed afterwards: ``` [Server] Serving from base path "/" Listening on port :8000 GET /healthcheck -> 200 OK GET /audiobookshelf/healthcheck -> 404 ``` ## Guards and docs + One assertion in `tests/dankserver_quadlet.bats`: the unit sets `PORT=8000` and `ROUTER_BASE_PATH=/`, and carries **no** `Environment=ABS_*` line. That is the regression, not a re-pinning of a constant. + The vault page gains the law — *speak the image's env names, not the README's* — with the failure signature (`active (running)` + probes refused) and the two-second `podman inspect --format '{{.Config.Env}}'` check that settles any such question. Its Shape table now names the env vars behind the port and the base path. ## Deploy after merge `./scripts/deploy.sh dankserver --service audiobookshelf`, then the homepage card on Dankclaw. The database initialized correctly on the failed attempt (the image's own path defaults matched the binds), so no state cleanup is involved — and no user data exists yet: the owner account is still the first-run step, which only Frank can do, from the LAN. --- cwd: /home/blank/.omp/wt/wt-20261030-163847-6d1fc1f · session: 01a18f2e-18b1-7573-bcd5-ac99636f8bcb
dank added 1 commit 2026-11-02 02:28:44 -08:00
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.
dank merged commit 7a8c6bd2e3 into main 2026-11-02 02:28:45 -08:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dank/serverAppConfigs#118