basement: declare 4 required env vars + auto-generate JWT secret

basement-ui as of latest now requires BASEMENT_DRIVER /
BASEMENT_ADMIN_USER / BASEMENT_ADMIN_PASSWORD_HASH / BASEMENT_JWT_SECRET
and refuses to start without them — container was crash-looping.

Template now declares all four:
  - DRIVER: defaults to "garage" (this deployment's storage backend).
  - JWT_SECRET: install.sh generates a hex string into secrets.env
    next to the garage secrets, sed-substitutes into the template.
    Backfills existing secrets.env that predates this key.
  - ADMIN_USER / ADMIN_PASSWORD_HASH: left blank; user fills via
    Unraid UI. bcrypt hash recipe is in both the file header and the
    PASSWORD_HASH config description.
This commit is contained in:
2026-05-19 08:22:16 -07:00
parent 0c35a906ce
commit 2f3b324518
2 changed files with 27 additions and 4 deletions
+14 -3
View File
@@ -4,9 +4,15 @@
Source of truth: pq/scripts on Gitea (https://git.docker.pq.io/pq/scripts).
Served via gitea raw URL: https://git.docker.pq.io/pq/scripts/raw/branch/main/unraid-1/basement.template.xml
This file is NOT installed directly. install.sh fetches it, substitutes the
__GARAGE_ADMIN_TOKEN__ placeholder with the same secret used by the garage
container, and writes the result to /boot/config/plugins/dockerMan/templates-user/my-basement.xml.
This file is NOT installed directly. install.sh fetches it, substitutes
__GARAGE_ADMIN_TOKEN__ (shared with the garage container) and
__BASEMENT_JWT_SECRET__ (generated alongside the garage secrets), and
writes the result to /boot/config/plugins/dockerMan/templates-user/my-basement.xml.
BASEMENT_ADMIN_USER and BASEMENT_ADMIN_PASSWORD_HASH must be set by hand
in the Unraid UI before Apply — install.sh leaves them blank.
Generate a bcrypt hash with: `htpasswd -bnBC 12 "" yourpassword | tr -d ':\n'`
(or use any bcrypt tool; basement-ui expects the standard $2a$/$2b$ format).
Caddy on classe reverse-proxies https://basement.pq.io to this container's
port 8080. DNS for basement.pq.io and the Caddy vhost are managed on classe,
@@ -45,4 +51,9 @@ Publicly served at https://basement.pq.io via Caddy on classe (reverse proxy →
<Config Name="GARAGE_ADMIN_URL" Target="GARAGE_ADMIN_URL" Default="http://host.docker.internal:3903" Mode="" Description="Garage admin API base URL (reaches the sibling garage container via the host-gateway alias)." Type="Variable" Display="always" Required="true" Mask="false">http://host.docker.internal:3903</Config>
<Config Name="GARAGE_ADMIN_TOKEN" Target="GARAGE_ADMIN_TOKEN" Default="" Mode="" Description="Bearer token for Garage admin API. Pre-filled by install.sh (same value as the garage container's GARAGE_ADMIN_TOKEN)." Type="Variable" Display="always" Required="true" Mask="true">__GARAGE_ADMIN_TOKEN__</Config>
<Config Name="BASEMENT_DRIVER" Target="BASEMENT_DRIVER" Default="garage" Mode="" Description="Storage backend driver. 'garage' for this deployment." Type="Variable" Display="always" Required="true" Mask="false">garage</Config>
<Config Name="BASEMENT_ADMIN_USER" Target="BASEMENT_ADMIN_USER" Default="" Mode="" Description="Login username for the basement UI. Pick something; you'll log in with this + the password whose hash goes below." Type="Variable" Display="always" Required="true" Mask="false"/>
<Config Name="BASEMENT_ADMIN_PASSWORD_HASH" Target="BASEMENT_ADMIN_PASSWORD_HASH" Default="" Mode="" Description="Bcrypt hash of the admin password ($2a$/$2b$ format). Generate with: htpasswd -bnBC 12 '' yourpassword | tr -d ':\n'" Type="Variable" Display="always" Required="true" Mask="true"/>
<Config Name="BASEMENT_JWT_SECRET" Target="BASEMENT_JWT_SECRET" Default="" Mode="" Description="HMAC secret for signing UI session JWTs. Pre-filled by install.sh from secrets.env (auto-generated, persisted across re-runs)." Type="Variable" Display="always" Required="true" Mask="true">__BASEMENT_JWT_SECRET__</Config>
</Container>
+13 -1
View File
@@ -57,15 +57,26 @@ else
GARAGE_RPC_SECRET=$(openssl rand -hex 32)
GARAGE_ADMIN_TOKEN=$(openssl rand -hex 32)
GARAGE_METRICS_TOKEN=$(openssl rand -hex 32)
BASEMENT_JWT_SECRET=$(openssl rand -hex 32)
umask 077
cat > "$SECRETS" <<EOF
GARAGE_RPC_SECRET=$GARAGE_RPC_SECRET
GARAGE_ADMIN_TOKEN=$GARAGE_ADMIN_TOKEN
GARAGE_METRICS_TOKEN=$GARAGE_METRICS_TOKEN
BASEMENT_JWT_SECRET=$BASEMENT_JWT_SECRET
EOF
say "generated secrets → $SECRETS"
fi
# Existing deployments predate BASEMENT_JWT_SECRET; backfill if missing
# so the basement template sub'n doesn't leave a literal placeholder.
if [ -z "${BASEMENT_JWT_SECRET:-}" ]; then
BASEMENT_JWT_SECRET=$(openssl rand -hex 32)
umask 077
printf "BASEMENT_JWT_SECRET=%s\n" "$BASEMENT_JWT_SECRET" >> "$SECRETS"
say "backfilled BASEMENT_JWT_SECRET into $SECRETS"
fi
# ── Templates ──
# Fetch each, optionally sed-substitute __PLACEHOLDER__ secrets, write to
# templates-user/. Secrets are hex chars only — safe in sed delimiters.
@@ -94,7 +105,8 @@ fetch_template \
fetch_template \
"$BASE/basement.template.xml" \
"$TEMPLATE_DIR/my-basement.xml" \
-e "s|__GARAGE_ADMIN_TOKEN__|$GARAGE_ADMIN_TOKEN|"
-e "s|__GARAGE_ADMIN_TOKEN__|$GARAGE_ADMIN_TOKEN|" \
-e "s|__BASEMENT_JWT_SECRET__|$BASEMENT_JWT_SECRET|"
fetch_template \
"$BASE/watchtower.template.xml" \