basement install.sh: preserve admin user + password hash across re-runs

Re-running install.sh was wiping BASEMENT_ADMIN_USER and _PASSWORD_HASH
back to empty in my-basement.xml — the user then had to re-enter them
in the Unraid UI every time. Annoying.

Template now declares those two fields as __PLACEHOLDER__ tokens.
install.sh, before fetching the new template, sed-extracts whatever's
currently in the existing my-basement.xml and feeds those values back
into the substitution. First-time installs sub to empty (user fills
via UI); subsequent runs preserve what's there.

Bcrypt's $-heavy chars survive sed because `|` is the delimiter and
sed only interprets $ in regex/match, not replacement.
This commit is contained in:
2026-05-19 08:35:11 -07:00
parent e9464bb3c5
commit 574376aa75
2 changed files with 22 additions and 3 deletions
+2 -2
View File
@@ -55,7 +55,7 @@ Publicly served at https://basement.pq.io via Caddy on classe (reverse proxy →
<Config Name="BASEMENT_DRIVER_GARAGE_ADMIN_TOKEN" Target="BASEMENT_DRIVER_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_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. install.sh preserves whatever you set here across re-runs." Type="Variable" Display="always" Required="true" Mask="false">__BASEMENT_ADMIN_USER__</Config>
<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: docker run --rm caddy:alpine caddy hash-password --plaintext 'yourpassword'. install.sh preserves whatever you set here across re-runs." Type="Variable" Display="always" Required="true" Mask="true">__BASEMENT_ADMIN_PASSWORD_HASH__</Config>
<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>
+20 -1
View File
@@ -102,11 +102,30 @@ fetch_template \
-e "s|__GARAGE_ADMIN_TOKEN__|$GARAGE_ADMIN_TOKEN|" \
-e "s|__GARAGE_METRICS_TOKEN__|$GARAGE_METRICS_TOKEN|"
# Preserve user-set fields (admin user + password hash) across re-runs:
# pull whatever's currently in the existing my-basement.xml so we can
# sub it back into the freshly-fetched template. First-time installs
# substitute to empty (placeholders disappear) and the user fills them
# in via the Unraid UI; subsequent re-runs keep what they set.
PREV_BASEMENT_USER=""
PREV_BASEMENT_HASH=""
if [ -f "$TEMPLATE_DIR/my-basement.xml" ]; then
PREV_BASEMENT_USER=$(sed -n 's|.*<Config Name="BASEMENT_ADMIN_USER"[^>]*>\([^<]*\)</Config>.*|\1|p' "$TEMPLATE_DIR/my-basement.xml" | head -1)
PREV_BASEMENT_HASH=$(sed -n 's|.*<Config Name="BASEMENT_ADMIN_PASSWORD_HASH"[^>]*>\([^<]*\)</Config>.*|\1|p' "$TEMPLATE_DIR/my-basement.xml" | head -1)
# Don't carry forward the literal placeholder from an early-run template
[ "$PREV_BASEMENT_USER" = "__BASEMENT_ADMIN_USER__" ] && PREV_BASEMENT_USER=""
[ "$PREV_BASEMENT_HASH" = "__BASEMENT_ADMIN_PASSWORD_HASH__" ] && PREV_BASEMENT_HASH=""
[ -n "$PREV_BASEMENT_USER" ] && say "preserving BASEMENT_ADMIN_USER from existing template"
[ -n "$PREV_BASEMENT_HASH" ] && say "preserving BASEMENT_ADMIN_PASSWORD_HASH from existing template"
fi
fetch_template \
"$BASE/basement.template.xml" \
"$TEMPLATE_DIR/my-basement.xml" \
-e "s|__GARAGE_ADMIN_TOKEN__|$GARAGE_ADMIN_TOKEN|" \
-e "s|__BASEMENT_JWT_SECRET__|$BASEMENT_JWT_SECRET|"
-e "s|__BASEMENT_JWT_SECRET__|$BASEMENT_JWT_SECRET|" \
-e "s|__BASEMENT_ADMIN_USER__|$PREV_BASEMENT_USER|" \
-e "s|__BASEMENT_ADMIN_PASSWORD_HASH__|$PREV_BASEMENT_HASH|"
fetch_template \
"$BASE/watchtower.template.xml" \