Finishes the installApp refactor started in d941f59 (Wave A). Every app
whose <app>.sh was either pure boilerplate (Wave B) or boilerplate +
small custom logic (Wave C) now routes through the generic driver in
scripts/app/install/app_install.sh; bespoke logic moved to declarative
hooks in containers/<app>/scripts/<app>_install_hooks.sh.
Net: ~4,000 lines of duplicated 10-step sequence gone. From 31 per-app
.sh files (pre-Wave-A) down to 2 intentional keepers.
DELETED outright (pure boilerplate — driver replaces them identically):
jellyfin, mastodon, focalboard, ipinfo, speedtest, dashy, invidious,
nextcloud, ollama, vaultwarden, pihole
DELETED + hook-extracted (small bespoke step preserved in a hook):
bookstack, moneyapp, owncloud, trilium, searxng, gitea, headscale,
unbound, prometheus, grafana, gluetun, wireguard, jitsimeet, authelia,
traefik, adguard, onlyoffice
KEPT (intentional special cases):
crowdsec — host-app pattern (no docker compose, runs as apt+
systemd via installCrowdsecHost; uninstall/stop/
restart hooks already live in this file and are
invoked by dockerUninstall/Stop/RestartApp directly).
libreportal — WebUI bootstrap. Pre-compose image build + post-install
webuiLibrePortalUpdate + bootstrap-time suppression of
menuShowFinalMessages don't fit the generic flow.
Driver change — scripts/app/install/app_install.sh:
Moved monitoringToggleAppConfig "$app_name" "docker-compose.yml" from
the post-start integrations block into the install body at post-compose
(right after dockerComposeSetupFile, before docker-compose up). The
toggle edits the compose file on disk — running it after start meant
the container had already been brought up with the unmodified compose,
so the metrics endpoint wouldn't reflect CFG_<APP>_MONITORING until
the next restart. Matches the original ordering in every per-app .sh
that used to call it inline.
Hook surface (declare-f-gated, silent no-op when absent):
<slug>_install_pre before any install work
<slug>_install_post_setup after dockerConfigSetupToContainer
<slug>_install_post_compose after dockerComposeSetupFile (+ the
shared monitoring toggle on the compose)
<slug>_install_post_start after dockerComposeUpdateAndStartApp
<slug>_install_message_data echoes extra argv for menuShowFinalMessages
<slug>_install_post very last thing, after the final message
+ the existing _uninstall_pre/_post, _stop_post, _restart_post
Notable extractions:
bookstack — _install_post_start: probe :PORT_1/login until 200/302,
then `bookstack:create-admin` inside the container with
CFG_BOOKSTACK_ADMIN_{EMAIL,PASSWORD}; falls back to the
seeded admin@admin.com on timeout.
adguard — _install_post_start drives the wizard's HTTP API
(POST /control/install/configure) so the admin doesn't
click through five pages, then pins the admin bind back
to 0.0.0.0:3000 (matches the compose mapping) and health
checks. _install_message_data echoes user/password to
menuShowFinalMessages.
authelia — _install_pre requirements; _install_post_compose copies
configuration.yml + users_database.yml, substitutes
theme/domain/host, generates JWT/session/storage secrets,
toggles monitoring on configuration.yml; _install_post_start
argon2-hashes the admin password via the container, writes
users_database.yml, restarts; _install_post echoes creds.
traefik — _install_pre prompts for the LE email if CFG_TRAEFIK_EMAIL
is unset; _install_post_compose copies static + dynamic
configs, wires CFG_TRAEFIK_DASHBOARD_ACCESS (local-only /
domain-only / public), toggles monitoring on traefik.yml,
then traefikUpdateWhitelist + traefikSetupLoginCredentials.
wireguard — _install_pre host-conflict guard (/etc/wireguard/params);
_install_post_compose persists CFG_WIREGUARD_SUBNET,
resolves WG_HOST (domain+traefik → host_setup, else IP),
runs runAppCfg wireguard-ip-forward; _install_post_start
restarts after wg-easy installs its iptables rules.
jitsimeet — _install_post_setup downloads the tagged release zip from
GitHub; _install_post_compose mass-edits the .env and runs
gen-passwords.sh; _install_post_start rewrites nginx
default site to usedport1/2 + restart.
prometheus — _install_post_compose seeds prometheus.yml under
$containers_dir/prometheus/prometheus/; _install_post_start
sets 0777 on storage dirs so the container TSDB can write
regardless of host UID mapping.
grafana — _install_pre requirements; _install_post_start 0777 on
grafana_storage.
gluetun — _install_post_start refreshes the provider snapshot,
reattaches every routed app (the netns container ID is
stale after gluetun gets recreated), then prompts to
onboard any existing apps.
+ the smaller bookstack-shape extractions for owncloud (version scrape),
trilium / searxng (wait-for-first-boot-config), gitea (Prometheus
bearer token sync), headscale / unbound (config copy), moneyapp
(Auth.js AUTH_URL), onlyoffice (compose-resolved user/pass into the
final message).
Manifest + arrays regenerated. Verified end-to-end:
- bash -n on every hook file + the driver: clean
- Each hook file sources cleanly in a subshell, exposes only the
intended functions, flagged lazy-loadable (not eager)
- Smoke-stubbed install run for jellyfin (pure), nextcloud (pure),
bookstack (hooked), crowdsec (kept): correct dispatch in all cases —
deleted apps route to installApp, kept apps still hit their real
function
Signed-off-by: librelad <librelad@digitalangels.vip>
112 lines
4.1 KiB
Bash
112 lines
4.1 KiB
Bash
#!/bin/bash
|
|
|
|
# Authelia install hooks — requirements check, config + secrets bootstrap,
|
|
# admin account provisioning, and an end-of-install credentials notice.
|
|
|
|
authelia_install_pre()
|
|
{
|
|
local app_name="$1"
|
|
if ! appInstallCheckRequirements "$app_name" "$CFG_AUTHELIA_REQUIRES"; then
|
|
authelia=n
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
authelia_install_post_compose()
|
|
{
|
|
local app_name="$1"
|
|
|
|
local result
|
|
result=$(copyResource "$app_name" "configuration.yml" "config" | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1)
|
|
checkSuccess "Copying configuration.yml to $containers_dir$app_name/config"
|
|
|
|
result=$(copyResource "$app_name" "users_database.yml" "config" | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1)
|
|
checkSuccess "Copying users_database.yml to $containers_dir$app_name/config"
|
|
|
|
local authelia_config_file="$containers_dir$app_name/config/configuration.yml"
|
|
runFileOp sed -i "s|AUTHELIA_THEME_PLACEHOLDER|$CFG_AUTHELIA_THEME|g" "$authelia_config_file"
|
|
runFileOp sed -i "s|AUTHELIA_DOMAIN_PLACEHOLDER|$domain_full|g" "$authelia_config_file"
|
|
runFileOp sed -i "s|AUTHELIA_HOST_PLACEHOLDER|$host_setup|g" "$authelia_config_file"
|
|
checkSuccess "Substituting Authelia configuration values (theme=$CFG_AUTHELIA_THEME domain=$domain_full host=$host_setup)"
|
|
|
|
local authelia_secrets_dir="$containers_dir$app_name/secrets"
|
|
runFileOp mkdir -p "$authelia_secrets_dir"
|
|
local secret_name secret_file
|
|
for secret_name in JWT_SECRET SESSION_SECRET STORAGE_ENCRYPTION_KEY; do
|
|
secret_file="$authelia_secrets_dir/$secret_name"
|
|
if [[ ! -s "$secret_file" ]]; then
|
|
openssl rand -hex 64 | runFileWrite "$secret_file"
|
|
runFileOp chmod 600 "$secret_file"
|
|
fi
|
|
done
|
|
runFileOp chown -R "$docker_install_user":"$docker_install_user" "$authelia_secrets_dir"
|
|
checkSuccess "Generated Authelia secrets at $authelia_secrets_dir"
|
|
|
|
# Authelia's metrics block lives in configuration.yml (not the compose),
|
|
# so toggle it here. The driver already toggled docker-compose.yml.
|
|
monitoringToggleAppConfig "$app_name" "config/configuration.yml"
|
|
}
|
|
|
|
authelia_install_post_start()
|
|
{
|
|
local app_name="$1"
|
|
|
|
((menu_number++))
|
|
echo ""
|
|
echo "---- $menu_number. Configuring Authelia admin account"
|
|
echo ""
|
|
|
|
local authelia_admin_user="${CFG_AUTHELIA_ADMIN_USERNAME:-admin}"
|
|
local authelia_admin_pass="${CFG_AUTHELIA_ADMIN_PASSWORD:-authelia}"
|
|
local authelia_users_file="$containers_dir$app_name/config/users_database.yml"
|
|
local authelia_attempts=0
|
|
while ((authelia_attempts < 30)); do
|
|
if runFileOp docker exec authelia-service authelia --version >/dev/null 2>&1; then
|
|
break
|
|
fi
|
|
sleep 2
|
|
((authelia_attempts++))
|
|
done
|
|
|
|
if ((authelia_attempts >= 30)); then
|
|
isNotice "Authelia container did not become responsive in time — admin left at default (admin / authelia)."
|
|
return 0
|
|
fi
|
|
|
|
local authelia_hash
|
|
authelia_hash=$(runFileOp docker exec authelia-service authelia crypto hash generate argon2 --password "$authelia_admin_pass" 2>/dev/null \
|
|
| grep -oE '\$argon2[^[:space:]]+')
|
|
if [[ -z "$authelia_hash" ]]; then
|
|
isNotice "Could not generate Authelia password hash — admin left at default (admin / authelia)."
|
|
return 0
|
|
fi
|
|
|
|
runFileWrite "$authelia_users_file" <<EOF
|
|
---
|
|
users:
|
|
${authelia_admin_user}:
|
|
disabled: false
|
|
displayname: "Admin"
|
|
password: "${authelia_hash}"
|
|
email: ${authelia_admin_user}@${domain_full:-example.com}
|
|
groups:
|
|
- admins
|
|
EOF
|
|
runFileOp chown "$docker_install_user":"$docker_install_user" "$authelia_users_file"
|
|
isSuccessful "Configured Authelia admin (user: $authelia_admin_user)."
|
|
dockerComposeRestart "$app_name"
|
|
}
|
|
|
|
authelia_install_post()
|
|
{
|
|
local app_name="$1"
|
|
local authelia_admin_user="${CFG_AUTHELIA_ADMIN_USERNAME:-admin}"
|
|
local authelia_admin_pass="${CFG_AUTHELIA_ADMIN_PASSWORD:-authelia}"
|
|
echo ""
|
|
isNotice "Authelia admin login:"
|
|
echo ""
|
|
echo " Username : ${authelia_admin_user}"
|
|
echo " Password : ${authelia_admin_pass}"
|
|
echo ""
|
|
}
|