Merge claude/1

This commit is contained in:
librelad 2026-05-27 13:26:49 +01:00
commit e793c7a0e4
47 changed files with 1068 additions and 4115 deletions

View File

@ -1,276 +0,0 @@
#!/bin/bash
# Category : Networking
# Description : AdGuard - DNS based Ad Blocking (c/u/s/r/i):
installAdguard()
{
local config_variables="$1"
if [[ "$adguard" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent adguard;
local app_name=$CFG_ADGUARD_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$adguard" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$adguard" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$adguard" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$adguard" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$adguard" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
monitoringToggleAppConfig "$app_name" "docker-compose.yml";
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Completing AdGuardHome initial setup automatically"
echo ""
# The legacy `$usedport1` variable is no longer populated by the
# current install pipeline; the resolved host port is stored in the
# PORTS_TAG_1 docker-compose tag (format `external:internal`). Pull
# it from there so the curl + URL printout actually point somewhere.
local adguard_compose_file="$containers_dir$app_name/docker-compose.yml"
local adguard_port_pair
adguard_port_pair=$(tagsManagerGetTagContent "$adguard_compose_file" "PORTS_TAG_1")
local adguard_admin_port="${adguard_port_pair%%:*}"
if [[ -n "$public_ip_v4" && -n "$adguard_admin_port" ]]; then
echo " External : http://$public_ip_v4:$adguard_admin_port/"
fi
if [[ -n "$host_setup" ]]; then
echo " Hostname : http://$host_setup/"
fi
echo ""
# AdGuardHome ships a setup wizard that normally needs five clicks in a
# browser before the daemon writes its config file. Same wizard is
# exposed as an HTTP API (POST /control/install/configure), so we
# drive it from here and skip the manual interaction. We pre-poll the
# admin endpoint until the container is up, then send the form, then
# let the existing post-install sed edits run against the freshly
# written AdGuardHome.yaml.
local adguard_setup_url="http://127.0.0.1:${adguard_admin_port}"
local adguard_attempts=0
local adguard_max_attempts=60
while ((adguard_attempts < adguard_max_attempts)); do
if curl -fsS -o /dev/null --max-time 2 "${adguard_setup_url}/control/status" 2>/dev/null \
|| curl -fsS -o /dev/null --max-time 2 "${adguard_setup_url}/control/install/get_addresses" 2>/dev/null; then
break
fi
sleep 2
((adguard_attempts++))
done
if ((adguard_attempts >= adguard_max_attempts)); then
isError "AdGuardHome admin endpoint did not respond on $adguard_setup_url within $((adguard_max_attempts * 2))s — open the URL and complete setup manually, then re-run the installer to apply the post-setup tweaks."
else
local adguard_user="${CFG_ADGUARD_USER:-admin}"
local adguard_pass="${CFG_ADGUARD_PASSWORD:-}"
if [[ -z "$adguard_pass" ]]; then
adguard_pass=$(generateRandomPassword)
updateConfigOption "CFG_ADGUARD_PASSWORD" "$adguard_pass" >/dev/null 2>&1 || true
isNotice "Generated a random AdGuardHome admin password and saved it to CFG_ADGUARD_PASSWORD."
fi
# Internal container ports are fixed (3000 admin, 53 DNS); host
# mapping is what `usedport1` etc. handle.
local adguard_payload
adguard_payload=$(cat <<JSON
{
"web": { "ip": "0.0.0.0", "port": 3000, "autofix": false },
"dns": { "ip": "0.0.0.0", "port": 53, "autofix": false },
"username": "${adguard_user}",
"password": "${adguard_pass}"
}
JSON
)
if curl -fsS -X POST \
-H 'Content-Type: application/json' \
--data "$adguard_payload" \
--max-time 15 \
"${adguard_setup_url}/control/install/configure" >/dev/null 2>&1; then
isSuccessful "AdGuardHome admin setup completed automatically (user: $adguard_user)."
else
# 422/403 here typically means setup was already done on a
# previous install; the post-setup tweaks below are still
# safe to run against the existing yaml.
isNotice "AdGuardHome /control/install/configure rejected the request — assuming it's already configured. If this is a fresh install, complete setup manually at $adguard_setup_url."
fi
# Small breather so AdGuardHome finishes flushing AdGuardHome.yaml
# to disk before the sed edits below touch it.
#sleep 3
fi
#result=$(sudo sed -i "s/address: 0.0.0.0:80/address: 0.0.0.0:${usedport2}/g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
#checkSuccess "Changing port 80 to $usedport2 for Admin Panel"
#result=$(sudo sed -i "s/port: 53/port: ${usedport3}/g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
#checkSuccess "Changing port 53 to $usedport3 for DNS Port"
#result=$(sudo sed -i "s/port_https: 443/port_https: ${usedport4}/g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
#checkSuccess "Changing port 443 to $usedport4 for DNS Port"
#result=$(sudo sed -i "s/port_dns_over_tls: 853/port_dns_over_tls: ${usedport5}/g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
#checkSuccess "Changing port 853 to $usedport5 for port_dns_over_tls"
#result=$(sudo sed -i "s/port_dns_over_quic: 853/port_dns_over_quic: ${usedport5}/g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
#checkSuccess "Changing port 853 to $usedport5 for port_dns_over_quic"
# NOTE: We deliberately do *not* force `tls.enabled: true` here.
# That section configures encrypted DNS (DoT/DoH/DoQ) and AdGuardHome
# crash-loops on startup with `[fatal] creating dns server: parsing
# tls key pair: tls: failed to find any PEM data in certificate input`
# if `enabled: true` is set without a real certificate pair pointed
# at by `certificate_path` / `private_key_path`. The admin user can
# opt into encrypted DNS from Settings → Encryption once they've
# provided a cert.
if [[ $public == "true" ]]; then
result=$(runFileOp sed -i "s|allow_unencrypted_doh: false|allow_unencrypted_doh: true|g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
checkSuccess "Setting allow_unencrypted_doh to false for Traefik"
fi
result=$(runFileOp sed -i "s|anonymize_client_ip: false: false|anonymize_client_ip: true|g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
checkSuccess "Setting anonymize_client_ip to true for privacy reasons"
# Force the admin web bind back to 0.0.0.0:3000 inside the container.
# The docker-compose mapping is `<host_port>:3000`, so the container
# MUST listen on 3000 internally for the host port to reach it. After
# the install API call AdGuardHome sometimes ends up bound to 0.0.0.0:80
# (its build-time default) instead of the port we sent — which is
# exactly what causes "unable to connect" on the host port.
local adguard_yaml="$containers_dir$app_name/conf/AdGuardHome.yaml"
if [[ -f "$adguard_yaml" ]]; then
# New schema (v0.107+): single `address: 0.0.0.0:NN` line under `http:`.
runFileOp sed -i 's|^\(\s*address:\s*\)0\.0\.0\.0:[0-9]\+|\10.0.0.0:3000|' "$adguard_yaml"
# Old schema fallback: separate `bind_host:` / `bind_port:` keys.
runFileOp sed -i 's|^\(\s*bind_host:\s*\).*|\10.0.0.0|' "$adguard_yaml"
runFileOp sed -i 's|^\(\s*bind_port:\s*\)[0-9]\+|\13000|' "$adguard_yaml"
checkSuccess "Pinned AdGuardHome admin bind to 0.0.0.0:3000 (matches the compose port mapping)."
fi
dockerComposeRestart "$app_name";
# Health-check after the restart so the user finds out *here* if
# AdGuardHome didn't come back up cleanly, rather than later when
# they try to open the URL and just see "unable to connect".
#
# Drop `-f` and accept any HTTP status code: now that the admin
# account is configured, `/control/status` returns 401 to an
# unauthenticated request — which is fine, it means the server is
# up and answering. We only care whether the connection succeeded
# at all, not what the response body says. `-w '%{http_code}'`
# gives us a 3-digit code on success and an empty string on a
# connection failure / timeout.
local adguard_health_attempts=0
while ((adguard_health_attempts < 20)); do
local adguard_health_code
adguard_health_code=$(curl -sS -o /dev/null --max-time 2 \
-w '%{http_code}' "${adguard_setup_url}/control/status" 2>/dev/null)
if [[ "$adguard_health_code" =~ ^[1-5][0-9][0-9]$ ]]; then
isSuccessful "AdGuardHome admin UI is reachable on $adguard_setup_url (HTTP $adguard_health_code)"
break
fi
sleep 1
((adguard_health_attempts++))
done
if ((adguard_health_attempts >= 20)); then
isError "AdGuardHome admin UI did not respond after restart on $adguard_setup_url. Check the container logs (\`docker logs adguard-service\`) and the conf/AdGuardHome.yaml bind address."
fi
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating the WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Refreshing monitoring integration."
echo ""
monitoringRefreshAll;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
# Same final-summary call shape as wireguard / vaultwarden. Pass the
# admin user/password we just configured so the user sees the
# credentials exactly once, at the end of the install.
menuShowFinalMessages "$app_name" "${CFG_ADGUARD_USER:-admin}" "$CFG_ADGUARD_PASSWORD";
menu_number=0
#sleep 3s
cd
fi
adguard=n
}

View File

@ -0,0 +1,142 @@
#!/bin/bash
# AdGuard Home install hooks — drive the first-boot setup wizard via its
# HTTP API so the admin doesn't have to click through five pages, then
# pin the admin bind back to 0.0.0.0:3000 (matches the compose mapping)
# and health-check the result.
adguard_install_post_start()
{
local app_name="$1"
((menu_number++))
echo ""
echo "---- $menu_number. Completing AdGuardHome initial setup automatically"
echo ""
# The legacy `$usedport1` variable isn't populated by the current
# install pipeline; the resolved host port is stored in the PORTS_TAG_1
# docker-compose tag (format `external:internal`). Pull it from there
# so the curl + URL printout actually point somewhere real.
local adguard_compose_file="$containers_dir$app_name/docker-compose.yml"
local adguard_port_pair
adguard_port_pair=$(tagsManagerGetTagContent "$adguard_compose_file" "PORTS_TAG_1")
local adguard_admin_port="${adguard_port_pair%%:*}"
if [[ -n "$public_ip_v4" && -n "$adguard_admin_port" ]]; then
echo " External : http://$public_ip_v4:$adguard_admin_port/"
fi
if [[ -n "$host_setup" ]]; then
echo " Hostname : http://$host_setup/"
fi
echo ""
# AdGuardHome ships a setup wizard that normally needs five clicks in
# a browser before the daemon writes its config file. Same wizard is
# exposed as an HTTP API (POST /control/install/configure), so drive
# it from here and skip the manual interaction. Pre-poll the admin
# endpoint until the container is up, then send the form, then let
# the post-install sed edits run against the freshly written
# AdGuardHome.yaml.
local adguard_setup_url="http://127.0.0.1:${adguard_admin_port}"
local adguard_attempts=0
local adguard_max_attempts=60
while ((adguard_attempts < adguard_max_attempts)); do
if curl -fsS -o /dev/null --max-time 2 "${adguard_setup_url}/control/status" 2>/dev/null \
|| curl -fsS -o /dev/null --max-time 2 "${adguard_setup_url}/control/install/get_addresses" 2>/dev/null; then
break
fi
sleep 2
((adguard_attempts++))
done
if ((adguard_attempts >= adguard_max_attempts)); then
isError "AdGuardHome admin endpoint did not respond on $adguard_setup_url within $((adguard_max_attempts * 2))s — open the URL and complete setup manually, then re-run the installer to apply the post-setup tweaks."
else
local adguard_user="${CFG_ADGUARD_USER:-admin}"
local adguard_pass="${CFG_ADGUARD_PASSWORD:-}"
if [[ -z "$adguard_pass" ]]; then
adguard_pass=$(generateRandomPassword)
updateConfigOption "CFG_ADGUARD_PASSWORD" "$adguard_pass" >/dev/null 2>&1 || true
isNotice "Generated a random AdGuardHome admin password and saved it to CFG_ADGUARD_PASSWORD."
fi
# Internal container ports are fixed (3000 admin, 53 DNS); host
# mapping is what `usedport1` etc. handle.
local adguard_payload
adguard_payload=$(cat <<JSON
{
"web": { "ip": "0.0.0.0", "port": 3000, "autofix": false },
"dns": { "ip": "0.0.0.0", "port": 53, "autofix": false },
"username": "${adguard_user}",
"password": "${adguard_pass}"
}
JSON
)
if curl -fsS -X POST \
-H 'Content-Type: application/json' \
--data "$adguard_payload" \
--max-time 15 \
"${adguard_setup_url}/control/install/configure" >/dev/null 2>&1; then
isSuccessful "AdGuardHome admin setup completed automatically (user: $adguard_user)."
else
# 422/403 here typically means setup was already done on a
# previous install; the post-setup tweaks below are still
# safe to run against the existing yaml.
isNotice "AdGuardHome /control/install/configure rejected the request — assuming it's already configured. If this is a fresh install, complete setup manually at $adguard_setup_url."
fi
fi
local result
if [[ "$public" == "true" ]]; then
result=$(runFileOp sed -i "s|allow_unencrypted_doh: false|allow_unencrypted_doh: true|g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
checkSuccess "Setting allow_unencrypted_doh to false for Traefik"
fi
result=$(runFileOp sed -i "s|anonymize_client_ip: false: false|anonymize_client_ip: true|g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
checkSuccess "Setting anonymize_client_ip to true for privacy reasons"
# Force the admin web bind back to 0.0.0.0:3000 inside the container.
# The docker-compose mapping is `<host_port>:3000`, so the container
# MUST listen on 3000 internally for the host port to reach it. After
# the install API call AdGuardHome sometimes ends up bound to
# 0.0.0.0:80 (its build-time default) — exactly what causes "unable
# to connect" on the host port.
local adguard_yaml="$containers_dir$app_name/conf/AdGuardHome.yaml"
if [[ -f "$adguard_yaml" ]]; then
runFileOp sed -i 's|^\(\s*address:\s*\)0\.0\.0\.0:[0-9]\+|\10.0.0.0:3000|' "$adguard_yaml"
runFileOp sed -i 's|^\(\s*bind_host:\s*\).*|\10.0.0.0|' "$adguard_yaml"
runFileOp sed -i 's|^\(\s*bind_port:\s*\)[0-9]\+|\13000|' "$adguard_yaml"
checkSuccess "Pinned AdGuardHome admin bind to 0.0.0.0:3000 (matches the compose port mapping)."
fi
dockerComposeRestart "$app_name"
# Drop `-f` and accept any HTTP status code: now that the admin
# account is configured, /control/status returns 401 to an
# unauthenticated request — which is fine, it means the server is up
# and answering. We only care whether the connection succeeded at
# all, not what the response body says.
local adguard_health_attempts=0
local adguard_health_code
while ((adguard_health_attempts < 20)); do
adguard_health_code=$(curl -sS -o /dev/null --max-time 2 \
-w '%{http_code}' "${adguard_setup_url}/control/status" 2>/dev/null)
if [[ "$adguard_health_code" =~ ^[1-5][0-9][0-9]$ ]]; then
isSuccessful "AdGuardHome admin UI is reachable on $adguard_setup_url (HTTP $adguard_health_code)"
break
fi
sleep 1
((adguard_health_attempts++))
done
if ((adguard_health_attempts >= 20)); then
isError "AdGuardHome admin UI did not respond after restart on $adguard_setup_url. Check the container logs (\`docker logs adguard-service\`) and the conf/AdGuardHome.yaml bind address."
fi
}
adguard_install_message_data()
{
# Echo the admin user + password as space-separated tokens so they
# become $username $password positional args to menuShowFinalMessages.
echo "${CFG_ADGUARD_USER:-admin} $CFG_ADGUARD_PASSWORD"
}

View File

@ -1,208 +0,0 @@
#!/bin/bash
# Category : Security
# Description : Authelia - Authentication & SSO (c/u/s/r/i):
installAuthelia()
{
local config_variables="$1"
if [[ "$authelia" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent authelia;
local app_name=$CFG_AUTHELIA_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$authelia" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$authelia" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$authelia" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$authelia" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$authelia" == *[iI]* ]]; then
isHeader "Install $app_name"
# Pre-flight: bail out before touching any compose/config if the
# global prerequisites aren't met. CFG_AUTHELIA_REQUIRES lists
# what's needed (currently "domain,traefik"); the helper prints a
# clear list of what's missing so the user knows what to fix.
if ! appInstallCheckRequirements "$app_name" "$CFG_AUTHELIA_REQUIRES"; then
authelia=n
return 1
fi
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
local 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"
local 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"
for secret_name in JWT_SECRET SESSION_SECRET STORAGE_ENCRYPTION_KEY; do
local 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"
# Enable Authelia's telemetry/metrics endpoint only when
# CFG_AUTHELIA_MONITORING=true (toggles the libreportal-monitoring
# marker block in configuration.yml).
monitoringToggleAppConfig "$app_name" "config/configuration.yml";
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((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)."
else
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)."
else
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";
fi
fi
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Refreshing monitoring integration."
echo ""
# Self-correcting: adds Authelia's scrape target + dashboard to
# Prometheus/Grafana when CFG_AUTHELIA_MONITORING=true, removes them
# when it's off. No-ops with a notice if either app isn't installed.
monitoringRefreshAll;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your new service using one of the options below : "
echo ""
menuShowFinalMessages $app_name;
echo ""
isNotice "Authelia admin login:"
echo ""
echo " Username : ${authelia_admin_user}"
echo " Password : ${authelia_admin_pass}"
echo ""
menu_number=0
#sleep 3s
cd
fi
authelia=n
}

View File

@ -0,0 +1,111 @@
#!/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 ""
}

View File

@ -1,180 +0,0 @@
#!/bin/bash
# Category : Knowledge Management
# Description : Bookstack - Wiki/Knowledge Base (c/u/s/r/i):
installBookstack()
{
local config_variables="$1"
if [[ "$bookstack" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent bookstack;
local app_name=$CFG_BOOKSTACK_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$bookstack" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$bookstack" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$bookstack" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$bookstack" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$bookstack" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
menuShowFinalMessages $app_name;
bookstack_target_email="${CFG_BOOKSTACK_ADMIN_EMAIL:-admin@admin.com}"
bookstack_target_pass="${CFG_BOOKSTACK_ADMIN_PASSWORD:-password}"
bookstack_compose_file="$containers_dir$app_name/docker-compose.yml"
bookstack_port_pair=$(tagsManagerGetTagContent "$bookstack_compose_file" "PORTS_TAG_1")
bookstack_host_port="${bookstack_port_pair%%:*}"
bookstack_probe_url="http://127.0.0.1:${bookstack_host_port}/login"
isNotice "Waiting for Bookstack to come online at ${bookstack_probe_url} ..."
isNotice "This may take up to 20 seconds, please wait..."
bookstack_attempts=0
bookstack_ready=0
while ((bookstack_attempts < 60)); do
bookstack_http_code=$(curl -sS -o /dev/null --max-time 3 -w '%{http_code}' "$bookstack_probe_url" 2>/dev/null)
if [[ "$bookstack_http_code" =~ ^(200|302)$ ]]; then
bookstack_ready=1
break
fi
sleep 2
((bookstack_attempts++))
done
if ((bookstack_ready == 0)); then
isNotice "Bookstack did not respond on ${bookstack_probe_url} within $((60 * 2))s — admin account left at upstream defaults."
echo ""
isNotice "Bookstack admin login (default):"
echo ""
echo " Email : admin@admin.com"
echo " Password : password"
echo ""
else
isSuccessful "Bookstack is online (HTTP ${bookstack_http_code})."
bookstack_create_output=$(runFileOp docker exec \
-e EZ_BS_NEW_EMAIL="$bookstack_target_email" \
-e EZ_BS_NEW_PASS="$bookstack_target_pass" \
bookstack sh -c 'cd /app/www && s6-setuidgid abc php artisan bookstack:create-admin --no-ansi --email="$EZ_BS_NEW_EMAIL" --name=Admin --password="$EZ_BS_NEW_PASS" 2>&1')
bookstack_create_rc=$?
if [[ $bookstack_create_rc -eq 0 ]]; then
isSuccessful "Bookstack admin account created (email: $bookstack_target_email)."
if [[ "$bookstack_target_email" != "admin@admin.com" ]]; then
runFileOp docker exec -i bookstack php /app/www/artisan tinker --no-ansi >/dev/null 2>&1 <<'PHP'
$c = class_exists('\BookStack\Users\Models\User') ? '\BookStack\Users\Models\User' : '\BookStack\Auth\User';
optional($c::where('email', 'admin@admin.com')->first())->delete();
PHP
isSuccessful "Removed seeded admin@admin.com account."
fi
echo ""
isNotice "Bookstack admin login:"
echo ""
echo " Email : ${bookstack_target_email}"
echo " Password : ${bookstack_target_pass}"
echo ""
else
isNotice "Bookstack admin auto-create failed (exit $bookstack_create_rc). Output:"
echo "$bookstack_create_output" | sed 's/^/ /'
echo ""
isNotice "Falling back to upstream defaults — update from inside Bookstack."
echo ""
isNotice "Bookstack admin login (default):"
echo ""
echo " Email : admin@admin.com"
echo " Password : password"
echo ""
fi
fi
menu_number=0
#sleep 3s
cd
fi
bookstack=n
}

View File

@ -0,0 +1,84 @@
#!/bin/bash
# Bookstack install hooks — drive the post-start admin account bootstrap.
# Generic installApp driver handles compose / start / db / monitoring; this
# adds the readiness probe + first-admin provisioning the original
# installBookstack() did inline.
bookstack_install_post_start()
{
local app_name="$1"
local bookstack_target_email="${CFG_BOOKSTACK_ADMIN_EMAIL:-admin@admin.com}"
local bookstack_target_pass="${CFG_BOOKSTACK_ADMIN_PASSWORD:-password}"
local bookstack_compose_file="$containers_dir$app_name/docker-compose.yml"
local bookstack_port_pair
bookstack_port_pair=$(tagsManagerGetTagContent "$bookstack_compose_file" "PORTS_TAG_1")
local bookstack_host_port="${bookstack_port_pair%%:*}"
local bookstack_probe_url="http://127.0.0.1:${bookstack_host_port}/login"
isNotice "Waiting for Bookstack to come online at ${bookstack_probe_url} ..."
isNotice "This may take up to 20 seconds, please wait..."
local bookstack_attempts=0
local bookstack_ready=0
local bookstack_http_code
while ((bookstack_attempts < 60)); do
bookstack_http_code=$(curl -sS -o /dev/null --max-time 3 -w '%{http_code}' "$bookstack_probe_url" 2>/dev/null)
if [[ "$bookstack_http_code" =~ ^(200|302)$ ]]; then
bookstack_ready=1
break
fi
sleep 2
((bookstack_attempts++))
done
if ((bookstack_ready == 0)); then
isNotice "Bookstack did not respond on ${bookstack_probe_url} within $((60 * 2))s — admin account left at upstream defaults."
echo ""
isNotice "Bookstack admin login (default):"
echo ""
echo " Email : admin@admin.com"
echo " Password : password"
echo ""
return 0
fi
isSuccessful "Bookstack is online (HTTP ${bookstack_http_code})."
local bookstack_create_output
bookstack_create_output=$(runFileOp docker exec \
-e EZ_BS_NEW_EMAIL="$bookstack_target_email" \
-e EZ_BS_NEW_PASS="$bookstack_target_pass" \
bookstack sh -c 'cd /app/www && s6-setuidgid abc php artisan bookstack:create-admin --no-ansi --email="$EZ_BS_NEW_EMAIL" --name=Admin --password="$EZ_BS_NEW_PASS" 2>&1')
local bookstack_create_rc=$?
if [[ $bookstack_create_rc -eq 0 ]]; then
isSuccessful "Bookstack admin account created (email: $bookstack_target_email)."
if [[ "$bookstack_target_email" != "admin@admin.com" ]]; then
runFileOp docker exec -i bookstack php /app/www/artisan tinker --no-ansi >/dev/null 2>&1 <<'PHP'
$c = class_exists('\BookStack\Users\Models\User') ? '\BookStack\Users\Models\User' : '\BookStack\Auth\User';
optional($c::where('email', 'admin@admin.com')->first())->delete();
PHP
isSuccessful "Removed seeded admin@admin.com account."
fi
echo ""
isNotice "Bookstack admin login:"
echo ""
echo " Email : ${bookstack_target_email}"
echo " Password : ${bookstack_target_pass}"
echo ""
else
isNotice "Bookstack admin auto-create failed (exit $bookstack_create_rc). Output:"
echo "$bookstack_create_output" | sed 's/^/ /'
echo ""
isNotice "Falling back to upstream defaults — update from inside Bookstack."
echo ""
isNotice "Bookstack admin login (default):"
echo ""
echo " Email : admin@admin.com"
echo " Password : password"
echo ""
fi
}

View File

@ -1,114 +0,0 @@
#!/bin/bash
# Category : Miscellaneous
# Description : Dashy - Dashboard Tool (c/t/u/s/r/i):
installDashy()
{
local config_variables="$1"
if [[ "$dashy" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent dashy;
local app_name=$CFG_DASHY_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$dashy" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$dashy" == *[tT]* ]]; then
dashyToolsMenu;
fi
if [[ "$dashy" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$dashy" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$dashy" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$dashy" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your new service using one of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
dashy=n
}

View File

@ -1,110 +0,0 @@
#!/bin/bash
# Category : Productivity
# Description : Focalboard - Project Management (c/u/s/r/i):
installFocalboard()
{
local config_variables="$1"
if [[ "$focalboard" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent focalboard;
local app_name=$CFG_FOCALBOARD_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$focalboard" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$focalboard" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$focalboard" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$focalboard" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$focalboard" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using one of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
focalboard=n
}

View File

@ -1,139 +0,0 @@
#!/bin/bash
# Category : Development & Version Control
# Description : Gitea - Git Repository Management (c/u/s/r/i):
installGitea()
{
local config_variables="$1"
if [[ "$gitea" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent gitea;
local app_name=$CFG_GITEA_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$gitea" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$gitea" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$gitea" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$gitea" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$gitea" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
# Enable Gitea's /metrics endpoint only when CFG_GITEA_MONITORING=true
# (toggles the libreportal-monitoring marker block in the compose).
monitoringToggleAppConfig "$app_name" "docker-compose.yml";
# /metrics rides Gitea's public web port, so it's locked behind a
# bearer token. CFG_GITEA_METRICS_TOKEN lives in the .config (filled
# once by the RANDOMIZEDPASSWORD scanner, preserved across reinstalls)
# and reaches the compose via the GITEA_METRICS_TOKEN_TAG tag — mirror
# that same value into the Prometheus scrape fragment so the two agree.
if monitoringAppEnabled "$app_name"; then
if [[ -n "$CFG_GITEA_METRICS_TOKEN" ]]; then
local result=$(runFileOp sed -i "s|GITEA_METRICS_TOKEN_PLACEHOLDER|${CFG_GITEA_METRICS_TOKEN}|g" \
"$containers_dir$app_name/resources/monitoring/prometheus-scrape.yml")
checkSuccess "Synced Gitea /metrics token to the Prometheus scrape config"
else
isNotice "CFG_GITEA_METRICS_TOKEN is empty — Gitea /metrics scrape may 401."
fi
fi
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Refreshing monitoring integration."
echo ""
# Self-correcting: adds Gitea's scrape target + dashboard to
# Prometheus/Grafana when CFG_GITEA_MONITORING=true, removes them when
# it's off. No-ops with a notice if either app isn't installed.
monitoringRefreshAll;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using one of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
gitea=n
}

View File

@ -0,0 +1,25 @@
#!/bin/bash
# Gitea install hooks — mirror CFG_GITEA_METRICS_TOKEN into the Prometheus
# scrape fragment so the bearer token in the compose env matches what the
# Prometheus side sends.
gitea_install_post_compose()
{
local app_name="$1"
# The driver already ran monitoringToggleAppConfig "$app_name" docker-compose.yml,
# so the metrics block reflects CFG_GITEA_MONITORING. /metrics rides
# Gitea's public web port and is token-protected; sync the token into
# the scrape config so the two sides agree.
if monitoringAppEnabled "$app_name"; then
if [[ -n "$CFG_GITEA_METRICS_TOKEN" ]]; then
local result
result=$(runFileOp sed -i "s|GITEA_METRICS_TOKEN_PLACEHOLDER|${CFG_GITEA_METRICS_TOKEN}|g" \
"$containers_dir$app_name/resources/monitoring/prometheus-scrape.yml")
checkSuccess "Synced Gitea /metrics token to the Prometheus scrape config"
else
isNotice "CFG_GITEA_METRICS_TOKEN is empty — Gitea /metrics scrape may 401."
fi
fi
}

View File

@ -1,136 +0,0 @@
#!/bin/bash
# Category : Networking
# Description : Gluetun - VPN client for routing other containers (c/u/s/r/i):
installGluetun()
{
local config_variables="$1"
if [[ "$gluetun" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent gluetun;
local app_name=$CFG_GLUETUN_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$gluetun" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$gluetun" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$gluetun" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$gluetun" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$gluetun" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
monitoringToggleAppConfig "$app_name" "docker-compose.yml";
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating the WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Refreshing Gluetun provider snapshot."
echo ""
appWebuiRefresh_gluetun;
((menu_number++))
echo ""
echo "---- $menu_number. Re-attaching gluetun-routed apps (post-recreate)."
echo ""
# Gluetun was just (re)created — every existing routed app holds a
# stale container ID in its network_mode. Reattach them now so the
# user doesn't have to chase silent netns drift later.
appGluetunRoutedRecreate
((menu_number++))
echo ""
echo "---- $menu_number. Routing existing apps through Gluetun (optional)."
echo ""
gluetunRouteExistingAppsPrompt;
((menu_number++))
echo ""
echo "---- $menu_number. Refreshing monitoring integration."
echo ""
monitoringRefreshAll;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
menuShowFinalMessages "$app_name";
menu_number=0
cd
fi
gluetun=n
}

View File

@ -0,0 +1,35 @@
#!/bin/bash
# Gluetun install hooks — post-start provider snapshot refresh + reattach
# any apps routed through gluetun (their network_mode holds a stale
# container ID after gluetun was just recreated) + offer to onboard
# existing apps.
gluetun_install_post_start()
{
local app_name="$1"
((menu_number++))
echo ""
echo "---- $menu_number. Refreshing Gluetun provider snapshot."
echo ""
appWebuiRefresh_gluetun
((menu_number++))
echo ""
echo "---- $menu_number. Re-attaching gluetun-routed apps (post-recreate)."
echo ""
# Gluetun was just (re)created — every existing routed app holds a
# stale container ID in its network_mode. Reattach them now so the
# user doesn't have to chase silent netns drift later.
appGluetunRoutedRecreate
((menu_number++))
echo ""
echo "---- $menu_number. Routing existing apps through Gluetun (optional)."
echo ""
gluetunRouteExistingAppsPrompt
}

View File

@ -1,133 +0,0 @@
#!/bin/bash
# Category : Development & Version Control
# Description : Grafana - Metrics Visualizer (c/u/s/r/i):
installGrafana()
{
local config_variables="$1"
if [[ "$grafana" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent grafana;
local app_name=$CFG_GRAFANA_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$grafana" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$grafana" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$grafana" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$grafana" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$grafana" == *[iI]* ]]; then
isHeader "Install $app_name"
if ! appInstallCheckRequirements "$app_name" "$CFG_GRAFANA_REQUIRES"; then
grafana=n
return 1
fi
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
# Grafana
if [ -d "${containers_dir}grafana/grafana_storage" ]; then
local result=$(sudo chmod -R 777 "${containers_dir}grafana/grafana_storage")
checkSuccess "Set permissions to grafana_storage folder."
fi
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Provisioning monitoring dashboards from installed apps."
echo ""
# Re-gather the Prometheus datasource + every monitoring-enabled app's
# dashboards into provisioning/ — so a fresh (or re-)install of Grafana
# picks up the apps that already had CFG_<APP>_MONITORING=true.
# monitoringRefreshAll also covers Grafana's own scrape target when
# CFG_GRAFANA_MONITORING=true.
monitoringRefreshAll;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
grafana=n
}

View File

@ -0,0 +1,23 @@
#!/bin/bash
# Grafana install hooks — pre-flight prereq check + post-start 0777 on the
# storage folder so Grafana can write its sqlite db regardless of host UID.
grafana_install_pre()
{
local app_name="$1"
if ! appInstallCheckRequirements "$app_name" "$CFG_GRAFANA_REQUIRES"; then
grafana=n
return 1
fi
}
grafana_install_post_start()
{
local app_name="$1"
if [ -d "${containers_dir}grafana/grafana_storage" ]; then
local result
result=$(sudo chmod -R 777 "${containers_dir}grafana/grafana_storage")
checkSuccess "Set permissions to grafana_storage folder."
fi
}

View File

@ -1,127 +0,0 @@
#!/bin/bash
# Category : Networking
# Description : Self-hosted WireGuard orchestrator (c/u/s/r/i):
installHeadscale()
{
local config_variables="$1"
if [[ "$headscale" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent headscale;
local app_name=$CFG_HEADSCALE_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$headscale" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$headscale" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$headscale" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$headscale" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$headscale" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
local result=$(createFolders "loud" $docker_install_user $containers_dir$app_name/config)
checkSuccess "Create config folder"
local result=$(copyResource "$app_name" "config.yaml" "config" | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1)
checkSuccess "Copying config.yaml to config folder."
configSetupFileWithData $app_name "config.yaml" "config";
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Setting up database records"
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Refreshing monitoring integration."
echo ""
monitoringRefreshAll;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
echo " NOTE - The password to login in defined in the yml install file that was installed"
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
headscale=n
}

View File

@ -0,0 +1,19 @@
#!/bin/bash
# Headscale install hooks — drop the config.yaml template into the
# container's config folder before start so the daemon has its config on
# first boot.
headscale_install_post_compose()
{
local app_name="$1"
local result
result=$(createFolders "loud" $docker_install_user $containers_dir$app_name/config)
checkSuccess "Create config folder"
result=$(copyResource "$app_name" "config.yaml" "config" | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1)
checkSuccess "Copying config.yaml to config folder."
configSetupFileWithData $app_name "config.yaml" "config"
}

View File

@ -1,114 +0,0 @@
#!/bin/bash
# Category : Media & Streaming
# Description : Invidious - Privacy-focused YouTube Frontend (c/u/s/r/i/t):
installInvidious()
{
local config_variables="$1"
if [[ "$invidious" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent invidious;
local app_name=$CFG_INVIDIOUS_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$invidious" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$invidious" == *[tT]* ]]; then
invidiousToolsMenu;
fi
if [[ "$invidious" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$invidious" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$invidious" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$invidious" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
invidious=n
}

View File

@ -1,110 +0,0 @@
#!/bin/bash
# Category : Networking
# Description : IPinfo - IP Geolocation and Information (c/u/s/r/i):
installIpinfo()
{
local config_variables="$1"
if [[ "$ipinfo" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent ipinfo;
local app_name=$CFG_IPINFO_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$ipinfo" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$ipinfo" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$ipinfo" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$ipinfo" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$ipinfo" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
ipinfo=n
}

View File

@ -1,103 +0,0 @@
#!/bin/bash
# Category : Media & Streaming
# Description : Jellyfin - Media Server (c/u/s/r/i):
installJellyfin()
{
local config_variables="$1"
if [[ "$jellyfin" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent jellyfin;
local app_name=$CFG_JELLYFIN_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$jellyfin" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$jellyfin" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$jellyfin" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$jellyfin" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$jellyfin" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Pulling a default Jellyfin docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start Jellyfin"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your new service using one of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
jellyfin=n
}

View File

@ -1,202 +0,0 @@
#!/bin/bash
# Category : Communication & Collaboration Tools
# Description : Jitsi Meet - Video Conferencing *UNFINISHED* (c/u/s/r/i):
installJitsimeet()
{
local config_variables="$1"
if [[ "$jitsimeet" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent jitsimeet;
local app_name=$CFG_JITSIMEET_APP_NAME
git_url=$CFG_JITSIMEET_GIT
initializeAppVariables $app_name;
fi
if [[ "$jitsimeet" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$jitsimeet" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$jitsimeet" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$jitsimeet" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$jitsimeet" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Downloading latest GitHub release"
echo ""
latest_tag=$(git ls-remote --refs --sort="version:refname" --tags $git_url | cut -d/ -f3- | tail -n1)
echo "The latest tag is: $latest_tag"
local result=$(createFolders "loud" $docker_install_user $containers_dir$app_name)
checkSuccess "Creating $app_name container installation folder"
local result=$(cd $containers_dir$app_name && runFileOp rm -rf $containers_dir$app_name/$latest_tag.zip)
checkSuccess "Deleting zip file to prevent conflicts"
local result=$(createTouch $containers_dir$app_name/$latest_tag.txt $docker_install_user && echo 'Installed "$latest_tag" on "$backupDate"!' > $latest_tag.txt)
checkSuccess "Create logging txt file"
# Download files and unzip
local result=$(runFileOp wget -O $containers_dir$app_name/$latest_tag.zip $git_url/archive/refs/tags/$latest_tag.zip)
checkSuccess "Downloading tagged zip file from GitHub"
local result=$(runFileOp unzip -o $containers_dir$app_name/$latest_tag.zip -d $containers_dir$app_name)
checkSuccess "Unzip downloaded file"
local result=$(runFileOp mv $containers_dir$app_name/docker-jitsi-meet-$latest_tag/* $containers_dir$app_name)
checkSuccess "Moving all files from zip file to install directory"
local result=$(runFileOp rm -rf $containers_dir$app_name/$latest_tag.zip && runFileOp rm -rf $containers_dir$app_name/$latest_tag/)
checkSuccess "Removing downloaded zip file as no longer needed"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Setting up .env file for setup"
echo ""
dockerSetupEnvFile;
# Updating custom .env values
local result=$(runFileOp sed -i "s|CONFIG=~/.jitsi-meet-cfg|CONFIG=$containers_dir$app_name/.jitsi-meet-cfg|g" $containers_dir$app_name/.env)
checkSuccess "Updating .env file with new install path"
local result=$(runFileOp sed -i "s|#PUBLIC_URL=https://meet.example.com|PUBLIC_URL=https://$host_setup|g" $containers_dir$app_name/.env)
checkSuccess "Updating .env file with Public URL to $host_setup"
local result=$(runFileOp sed -i "s|HTTP_PORT=8000|HTTP_PORT=$usedport1|g" $containers_dir$app_name/.env)
checkSuccess "Updating .env file with HTTP_PORT to $usedport1"
local result=$(runFileOp sed -i "s|HTTPS_PORT=8443|HTTPS_PORT=$usedport2|g" $containers_dir$app_name/.env)
checkSuccess "Updating .env file with HTTP_PORT to $usedport2"
#local result=$(echo "ENABLE_HTTP_REDIRECT=1" | runFileWrite -a "$containers_dir$app_name/.env")
#checkSuccess "Updating .env file with option : ENABLE_HTTP_REDIRECT"
# Values are missing from the .env by default for some reason
# https://github.com/jitsi/docker-jitsi-meet/commit/12051700562d9826f9e024ad649c4dd9b88f94de#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5
local result=$(echo "XMPP_DOMAIN=meet.jitsi" | runFileWrite -a "$containers_dir$app_name/.env")
checkSuccess "Updating .env file with missing option : XMPP_DOMAIN"
local result=$(echo "XMPP_SERVER=xmpp.meet.jitsi" | runFileWrite -a "$containers_dir$app_name/.env")
checkSuccess "Updating .env file with missing option : XMPP_SERVER"
local result=$(echo "JVB_PORT=$usedport4" | runFileWrite -a "$containers_dir$app_name/.env")
checkSuccess "Updating .env file with missing option : JVB_PORT"
local result=$(echo "JVB_TCP_MAPPED_PORT=$usedport5" | runFileWrite -a "$containers_dir$app_name/.env")
checkSuccess "Updating .env file with missing option : JVB_TCP_MAPPED_PORT"
local result=$(echo "JVB_TCP_PORT=$usedport5" | runFileWrite -a "$containers_dir$app_name/.env")
checkSuccess "Updating .env file with missing option : JVB_TCP_PORT"
local result=$(cd "$containers_dir$app_name" && runFileOp ./gen-passwords.sh)
checkSuccess "Running Jitsi Meet gen-passwords.sh script"
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Adjusting $app_name docker system files for port changes."
echo ""
#dockerCommandRun "docker exec -it $app_name /bin/bash && cd /"
#local result=$(sudo sed -i "s|80|$usedport1|g" $containers_dir$app_nameweb/default)
#checkSuccess "Updating Docker NGINX default site port 80 to $usedport1"
#local result=$(sudo sed -i "s|443|$usedport2|g" $containers_dir$app_nameweb/default)
#checkSuccess "Updating Docker NGINX default site port 443 to $usedport2"
local result=$(runFileOp sed -i "s|80|$usedport1|g" $containers_dir$app_name/web/rootfs/defaults/default)
checkSuccess "Updating NGINX default site port 80 to $usedport1"
local result=$(runFileOp sed -i "s|443|$usedport2|g" $containers_dir$app_name/web/rootfs/defaults/default)
checkSuccess "Updating NGINX default site port 443 to $usedport2"
#dockerCommandRun "docker cp '$containers_dir$app_name' '$app_name:/etc/nginx/sites-available/default'"
dockerComposeRestart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your new service using one of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
jitsimeet=n
}

View File

@ -0,0 +1,101 @@
#!/bin/bash
# Jitsi Meet install hooks — Jitsi ships its docker layout as a tagged
# release zip on GitHub, so we download + unpack it before compose setup.
# Then mass-edit the .env, generate passwords, and rewire the nginx ports.
jitsimeet_install_post_setup()
{
local app_name="$1"
local git_url="$CFG_JITSIMEET_GIT"
((menu_number++))
echo ""
echo "---- $menu_number. Downloading latest GitHub release"
echo ""
local latest_tag
latest_tag=$(git ls-remote --refs --sort="version:refname" --tags "$git_url" | cut -d/ -f3- | tail -n1)
echo "The latest tag is: $latest_tag"
local result
result=$(createFolders "loud" $docker_install_user $containers_dir$app_name)
checkSuccess "Creating $app_name container installation folder"
result=$(cd $containers_dir$app_name && runFileOp rm -rf $containers_dir$app_name/$latest_tag.zip)
checkSuccess "Deleting zip file to prevent conflicts"
result=$(createTouch $containers_dir$app_name/$latest_tag.txt $docker_install_user && echo "Installed \"$latest_tag\" on \"$backupDate\"!" > $latest_tag.txt)
checkSuccess "Create logging txt file"
result=$(runFileOp wget -O $containers_dir$app_name/$latest_tag.zip $git_url/archive/refs/tags/$latest_tag.zip)
checkSuccess "Downloading tagged zip file from GitHub"
result=$(runFileOp unzip -o $containers_dir$app_name/$latest_tag.zip -d $containers_dir$app_name)
checkSuccess "Unzip downloaded file"
result=$(runFileOp mv $containers_dir$app_name/docker-jitsi-meet-$latest_tag/* $containers_dir$app_name)
checkSuccess "Moving all files from zip file to install directory"
result=$(runFileOp rm -rf $containers_dir$app_name/$latest_tag.zip && runFileOp rm -rf $containers_dir$app_name/$latest_tag/)
checkSuccess "Removing downloaded zip file as no longer needed"
}
jitsimeet_install_post_compose()
{
local app_name="$1"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up .env file for setup"
echo ""
dockerSetupEnvFile
local result
result=$(runFileOp sed -i "s|CONFIG=~/.jitsi-meet-cfg|CONFIG=$containers_dir$app_name/.jitsi-meet-cfg|g" $containers_dir$app_name/.env)
checkSuccess "Updating .env file with new install path"
result=$(runFileOp sed -i "s|#PUBLIC_URL=https://meet.example.com|PUBLIC_URL=https://$host_setup|g" $containers_dir$app_name/.env)
checkSuccess "Updating .env file with Public URL to $host_setup"
result=$(runFileOp sed -i "s|HTTP_PORT=8000|HTTP_PORT=$usedport1|g" $containers_dir$app_name/.env)
checkSuccess "Updating .env file with HTTP_PORT to $usedport1"
result=$(runFileOp sed -i "s|HTTPS_PORT=8443|HTTPS_PORT=$usedport2|g" $containers_dir$app_name/.env)
checkSuccess "Updating .env file with HTTP_PORT to $usedport2"
# Defaults missing from the shipped .env (see jitsi/docker-jitsi-meet
# commit 12051700562d…). Append them here so the install boots.
result=$(echo "XMPP_DOMAIN=meet.jitsi" | runFileWrite -a "$containers_dir$app_name/.env")
checkSuccess "Updating .env file with missing option : XMPP_DOMAIN"
result=$(echo "XMPP_SERVER=xmpp.meet.jitsi" | runFileWrite -a "$containers_dir$app_name/.env")
checkSuccess "Updating .env file with missing option : XMPP_SERVER"
result=$(echo "JVB_PORT=$usedport4" | runFileWrite -a "$containers_dir$app_name/.env")
checkSuccess "Updating .env file with missing option : JVB_PORT"
result=$(echo "JVB_TCP_MAPPED_PORT=$usedport5" | runFileWrite -a "$containers_dir$app_name/.env")
checkSuccess "Updating .env file with missing option : JVB_TCP_MAPPED_PORT"
result=$(echo "JVB_TCP_PORT=$usedport5" | runFileWrite -a "$containers_dir$app_name/.env")
checkSuccess "Updating .env file with missing option : JVB_TCP_PORT"
result=$(cd "$containers_dir$app_name" && runFileOp ./gen-passwords.sh)
checkSuccess "Running Jitsi Meet gen-passwords.sh script"
}
jitsimeet_install_post_start()
{
local app_name="$1"
((menu_number++))
echo ""
echo "---- $menu_number. Adjusting $app_name docker system files for port changes."
echo ""
local result
result=$(runFileOp sed -i "s|80|$usedport1|g" $containers_dir$app_name/web/rootfs/defaults/default)
checkSuccess "Updating NGINX default site port 80 to $usedport1"
result=$(runFileOp sed -i "s|443|$usedport2|g" $containers_dir$app_name/web/rootfs/defaults/default)
checkSuccess "Updating NGINX default site port 443 to $usedport2"
dockerComposeRestart $app_name
}

View File

@ -1,106 +0,0 @@
#!/bin/bash
# Category : Communication & Collaboration Tools
# Description : Mastodon - Decentralized Social Network (c/u/s/r/i):
installMastodon()
{
local config_variables="$1"
if [[ "$mastodon" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent mastodon;
local app_name=$CFG_MASTODON_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$mastodon" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$mastodon" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$mastodon" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$mastodon" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$mastodon" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
mastodon=n
}

View File

@ -1,148 +0,0 @@
#!/bin/bash
# Category : Productivity
# Description : MoneyApp - Self-hosted household money management (c/u/s/r/i):
installMoneyapp()
{
local config_variables="$1"
if [[ "$moneyapp" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent moneyapp;
local app_name=$CFG_MONEYAPP_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$moneyapp" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$moneyapp" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$moneyapp" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$moneyapp" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$moneyapp" == *[iI]* ]]; then
isHeader "Install $app_name"
# Pre-flight: bail out before touching any compose/config if the
# global prerequisites aren't met. CFG_MONEYAPP_REQUIRES lists
# what's needed (currently "domain,traefik"); the helper prints a
# clear list of what's missing so the user knows what to fix.
if ! appInstallCheckRequirements "$app_name" "$CFG_MONEYAPP_REQUIRES"; then
moneyapp=n
return 1
fi
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Resolving Auth.js callback URL (AUTH_URL)."
echo ""
# Auth.js requires a fixed AUTH_URL that matches what the browser
# actually hits — otherwise OAuth-style callbacks bounce. We pick:
# * https://<host>.<domain> when traefik is on AND a real
# domain is configured (CFG_DOMAIN_<n>)
# * http://<server-ip>:<port> otherwise (raw port exposure)
local moneyapp_compose_file="$containers_dir$app_name/docker-compose.yml"
local moneyapp_auth_url=""
# `host_setup` is built as `<app>.<domain>` — when CFG_DOMAIN_<n> is
# empty it ends up as `<app>.` which is a valid-but-broken hostname.
# Reject that explicitly: we want a real TLD before going https.
local _has_real_domain=0
if [[ -n "$host_setup" && "$host_setup" != *. ]] && [[ "$host_setup" == *.* ]]; then
_has_real_domain=1
fi
if [[ "$public" == "true" && $_has_real_domain -eq 1 ]]; then
moneyapp_auth_url="https://$host_setup"
else
local moneyapp_port_pair
moneyapp_port_pair=$(tagsManagerGetTagContent "$moneyapp_compose_file" "PORTS_TAG_1")
local moneyapp_external_port="${moneyapp_port_pair%%:*}"
local moneyapp_host="${public_ip_v4:-localhost}"
moneyapp_auth_url="http://${moneyapp_host}:${moneyapp_external_port}"
if [[ "$public" == "true" && $_has_real_domain -eq 0 ]]; then
isNotice "PORT_1 has traefik=true but no domain configured — falling back to direct port URL."
fi
fi
tagsManagerUpdateUniversalTag "$moneyapp_compose_file" "MONEYAPP_AUTH_URL_TAG" "$moneyapp_auth_url"
isSuccessful "AUTH_URL set to $moneyapp_auth_url"
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating the WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " First account to sign up becomes the household owner."
echo ""
menuShowFinalMessages "$app_name";
menu_number=0
cd
fi
moneyapp=n
}

View File

@ -0,0 +1,54 @@
#!/bin/bash
# MoneyApp install hooks — pre-flight requirements + Auth.js callback URL.
moneyapp_install_pre()
{
local app_name="$1"
# Bail out before any compose/config work if global prerequisites are
# missing (currently "domain,traefik"). The helper prints what's
# missing.
if ! appInstallCheckRequirements "$app_name" "$CFG_MONEYAPP_REQUIRES"; then
moneyapp=n
return 1
fi
}
moneyapp_install_post_compose()
{
local app_name="$1"
((menu_number++))
echo ""
echo "---- $menu_number. Resolving Auth.js callback URL (AUTH_URL)."
echo ""
# Auth.js requires a fixed AUTH_URL matching what the browser actually
# hits — otherwise OAuth-style callbacks bounce. Pick:
# * https://<host>.<domain> when traefik is on AND a real domain
# is configured (CFG_DOMAIN_<n>)
# * http://<server-ip>:<port> otherwise (raw port exposure)
local moneyapp_compose_file="$containers_dir$app_name/docker-compose.yml"
local moneyapp_auth_url=""
# host_setup is built as `<app>.<domain>` — when CFG_DOMAIN_<n> is
# empty it ends up as `<app>.`, a valid-but-broken hostname. Reject
# that explicitly: we want a real TLD before going https.
local _has_real_domain=0
if [[ -n "$host_setup" && "$host_setup" != *. ]] && [[ "$host_setup" == *.* ]]; then
_has_real_domain=1
fi
if [[ "$public" == "true" && $_has_real_domain -eq 1 ]]; then
moneyapp_auth_url="https://$host_setup"
else
local moneyapp_port_pair
moneyapp_port_pair=$(tagsManagerGetTagContent "$moneyapp_compose_file" "PORTS_TAG_1")
local moneyapp_external_port="${moneyapp_port_pair%%:*}"
local moneyapp_host="${public_ip_v4:-localhost}"
moneyapp_auth_url="http://${moneyapp_host}:${moneyapp_external_port}"
if [[ "$public" == "true" && $_has_real_domain -eq 0 ]]; then
isNotice "PORT_1 has traefik=true but no domain configured — falling back to direct port URL."
fi
fi
tagsManagerUpdateUniversalTag "$moneyapp_compose_file" "MONEYAPP_AUTH_URL_TAG" "$moneyapp_auth_url"
isSuccessful "AUTH_URL set to $moneyapp_auth_url"
}

View File

@ -1,119 +0,0 @@
#!/bin/bash
# Category : Cloud Storage & File Sharing
# Description : Nextcloud - Self-hosted Cloud Storage (c/t/u/s/r/i):
installNextcloud()
{
local config_variables="$1"
if [[ "$nextcloud" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent nextcloud;
local app_name=$CFG_NEXTCLOUD_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$nextcloud" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$nextcloud" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$nextcloud" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$nextcloud" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$nextcloud" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
monitoringToggleAppConfig "$app_name" "docker-compose.yml";
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Refreshing monitoring integration."
echo ""
monitoringRefreshAll;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your new service using one of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
nextcloud=n
}

View File

@ -1,119 +0,0 @@
#!/bin/bash
# Category : Development & Version Control
# Description : Ollama - Local AI Model Hosting (c/u/s/r/i):
installOllama()
{
local config_variables="$1"
if [[ "$ollama" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent ollama;
local app_name=$CFG_OLLAMA_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$ollama" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$ollama" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$ollama" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$ollama" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$ollama" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
monitoringToggleAppConfig "$app_name" "docker-compose.yml";
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Refreshing monitoring integration."
echo ""
monitoringRefreshAll;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
ollama=n
}

View File

@ -1,117 +0,0 @@
#!/bin/bash
# Category : Cloud Storage & File Sharing
# Description : OnlyOffice - Collaborative Office Suite (c/t/u/s/r/i):
installOnlyoffice()
{
local config_variables="$1"
if [[ "$onlyoffice" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent onlyoffice;
local app_name=$CFG_ONLYOFFICE_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$onlyoffice" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$onlyoffice" == *[tT]* ]]; then
onlyofficeToolsMenu;
fi
if [[ "$onlyoffice" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$onlyoffice" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$onlyoffice" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$onlyoffice" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your new service using one of the options below : "
echo ""
# Extract the content after the equals sign for username and password
local username=$(grep -oP 'username=\K[^ ]+' "$containers_dir$app_name/docker-compose.yml")
local password=$(grep -oP 'password=\K[^ ]+' "$containers_dir$app_name/docker-compose.yml")
menuShowFinalMessages $app_name $username $password;
menu_number=0
#sleep 3s
cd
fi
onlyoffice=n
}

View File

@ -0,0 +1,14 @@
#!/bin/bash
# OnlyOffice install hooks — pull the compose-resolved username/password
# into the final-message argv so the user sees the credentials at the
# end of the install.
onlyoffice_install_message_data()
{
local app_name="$1"
local username password
username=$(grep -oP 'username=\K[^ ]+' "$containers_dir$app_name/docker-compose.yml" 2>/dev/null)
password=$(grep -oP 'password=\K[^ ]+' "$containers_dir$app_name/docker-compose.yml" 2>/dev/null)
echo "$username $password"
}

View File

@ -1,152 +0,0 @@
#!/bin/bash
# Category : Cloud Storage & File Sharing
# Description : OwnCloud - Cloud Storage (c/u/s/r/i):
installOwncloud()
{
local config_variables="$1"
if [[ "$owncloud" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent owncloud;
local app_name=$CFG_OWNCLOUD_APP_NAME
owncloud_version=$CFG_OWNCLOUD_VERSION
initializeAppVariables $app_name;
fi
if [[ "$owncloud" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$owncloud" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$owncloud" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$owncloud" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$owncloud" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Obtain latest version number of $app_name"
echo ""
local webpage_file="/tmp/webpage.html"
# Download the webpage to the temporary directory
curl -s "https://doc.owncloud.com/docs/next/server_release_notes.html" > "$webpage_file"
if [ $? -eq 0 ]; then
# Extract the latest version from the temporary HTML file
local latest_version=$(grep -o 'Changes in [0-9.-]*' "$webpage_file" | awk -F " " '{print $3}' | sort -V | tail -n 1)
if [ -n "$latest_version" ]; then
isSuccessful "Latest Retrieved Version: $latest_version"
isSuccessful "Using for installation"
owncloud_version="$latest_version"
else
isNotice "Failed to extract the latest version from the OwnCloud website."
isNotice "Defaulting to config value : $CFG_OWNCLOUD_VERSION."
owncloud_version="$CFG_OWNCLOUD_VERSION"
fi
# Remove the temporary HTML file
rm "$webpage_file"
if [ $? -eq 0 ]; then
isSuccessful "Removed the temporary HTML file"
else
isNotice "Failed to remove the temporary HTML file"
fi
else
isNotice "Failed to retrieve the web page."
fi
local result=$(runFileOp sed -i \
-e "s|OWNCLOUD_SETUP_VERSION|$owncloud_version|g" \
-e "s|OWNCLOUD_SETUP_ADMIN_USERNAME|$CFG_OWNCLOUD_ADMIN_USERNAME|g" \
-e "s|OWNCLOUD_SETUP_ADMIN_PASSWORD|$CFG_OWNCLOUD_ADMIN_PASSWORD|g" \
-e "s|OWNCLOUD_SETUP_HTTP_PORT|$usedport1|g" \
"$file_path")
checkSuccess "Updating $file_name for $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your new service using one of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
owncloud=n
}

View File

@ -0,0 +1,44 @@
#!/bin/bash
# OwnCloud install hooks — latest-version scrape + compose substitution.
owncloud_install_post_compose()
{
local app_name="$1"
((menu_number++))
echo ""
echo "---- $menu_number. Obtain latest version number of $app_name"
echo ""
local owncloud_version="$CFG_OWNCLOUD_VERSION"
local webpage_file="/tmp/webpage.html"
curl -s "https://doc.owncloud.com/docs/next/server_release_notes.html" > "$webpage_file"
if [ $? -eq 0 ]; then
local latest_version
latest_version=$(grep -o 'Changes in [0-9.-]*' "$webpage_file" | awk -F " " '{print $3}' | sort -V | tail -n 1)
if [ -n "$latest_version" ]; then
isSuccessful "Latest Retrieved Version: $latest_version"
isSuccessful "Using for installation"
owncloud_version="$latest_version"
else
isNotice "Failed to extract the latest version from the OwnCloud website."
isNotice "Defaulting to config value : $CFG_OWNCLOUD_VERSION."
fi
rm -f "$webpage_file"
else
isNotice "Failed to retrieve the web page."
fi
local file_path="$containers_dir$app_name/docker-compose.yml"
local file_name="docker-compose.yml"
local result
result=$(runFileOp sed -i \
-e "s|OWNCLOUD_SETUP_VERSION|$owncloud_version|g" \
-e "s|OWNCLOUD_SETUP_ADMIN_USERNAME|$CFG_OWNCLOUD_ADMIN_USERNAME|g" \
-e "s|OWNCLOUD_SETUP_ADMIN_PASSWORD|$CFG_OWNCLOUD_ADMIN_PASSWORD|g" \
-e "s|OWNCLOUD_SETUP_HTTP_PORT|$usedport1|g" \
"$file_path")
checkSuccess "Updating $file_name for $app_name"
}

View File

@ -1,121 +0,0 @@
#!/bin/bash
# Category : Networking
# Description : PiHole - DNS-based Ad Blocking (c/u/s/r/i):
installPihole()
{
local config_variables="$1"
if [[ "$pihole" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent pihole;
local app_name=$CFG_PIHOLE_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$pihole" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$pihole" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$pihole" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$pihole" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$pihole" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
monitoringToggleAppConfig "$app_name" "docker-compose.yml";
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Setting up database records"
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Refreshing monitoring integration."
echo ""
monitoringRefreshAll;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
echo " NOTE - The password to login in defined in the yml install file that was installed"
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
pihole=n
}

View File

@ -1,142 +0,0 @@
#!/bin/bash
# Category : Development & Version Control
# Description : Prometheus - Monitoring and Alerting (c/u/s/r/i):
installPrometheus()
{
local config_variables="$1"
if [[ "$prometheus" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent prometheus;
local app_name=$CFG_PROMETHEUS_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$prometheus" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$prometheus" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$prometheus" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$prometheus" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$prometheus" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
local result=$(createFolders "loud" $docker_install_user "$containers_dir$app_name/$app_name")
checkSuccess "Created $app_name folder in $app_name"
local result=$(createTouch "$containers_dir$app_name/$app_name/$app_name.yml" $docker_install_user)
checkSuccess "Created $app_name.yml file for $app_name"
local result=$(copyResource "$app_name" "$app_name.yml" "$app_name" | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1)
checkSuccess "Copying $app_name.yml to containers folder."
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
# Prometheus
if [ -f "${containers_dir}prometheus/prometheus/prometheus.yml" ]; then
updateFileOwnership "${containers_dir}prometheus/prometheus/prometheus.yml" $docker_install_user $docker_install_user
fi
if [ -d "${containers_dir}prometheus/prometheus" ]; then
local result=$(sudo chmod -R 777 "${containers_dir}prometheus/prometheus")
checkSuccess "Set permissions to prometheus folder."
fi
if [ -d "${containers_dir}prometheus/prom_data" ]; then
local result=$(sudo chmod -R 777 "${containers_dir}prometheus/prom_data")
checkSuccess "Set permissions to prom_data folder."
fi
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Gathering monitoring scrape targets from installed apps."
echo ""
# Re-gather every monitoring-enabled app's scrape fragment into
# scrape.d/ — so a fresh (or re-)install of Prometheus picks up the
# apps that already had CFG_<APP>_MONITORING=true.
monitoringRefreshPrometheus;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
prometheus=n
}

View File

@ -0,0 +1,39 @@
#!/bin/bash
# Prometheus install hooks — drop the prometheus.yml template alongside the
# compose, and 0777 the storage dirs so the container can write its TSDB
# regardless of the host UID mapping.
prometheus_install_post_compose()
{
local app_name="$1"
local result
result=$(createFolders "loud" $docker_install_user "$containers_dir$app_name/$app_name")
checkSuccess "Created $app_name folder in $app_name"
result=$(createTouch "$containers_dir$app_name/$app_name/$app_name.yml" $docker_install_user)
checkSuccess "Created $app_name.yml file for $app_name"
result=$(copyResource "$app_name" "$app_name.yml" "$app_name" | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1)
checkSuccess "Copying $app_name.yml to containers folder."
}
prometheus_install_post_start()
{
local app_name="$1"
if [ -f "${containers_dir}prometheus/prometheus/prometheus.yml" ]; then
updateFileOwnership "${containers_dir}prometheus/prometheus/prometheus.yml" $docker_install_user $docker_install_user
fi
if [ -d "${containers_dir}prometheus/prometheus" ]; then
local result
result=$(sudo chmod -R 777 "${containers_dir}prometheus/prometheus")
checkSuccess "Set permissions to prometheus folder."
fi
if [ -d "${containers_dir}prometheus/prom_data" ]; then
local result
result=$(sudo chmod -R 777 "${containers_dir}prometheus/prom_data")
checkSuccess "Set permissions to prom_data folder."
fi
}

View File

@ -0,0 +1,26 @@
#!/bin/bash
# SearxNG install hooks — wait for settings.yml, apply theme, restart.
searxng_install_post_start()
{
local app_name="$1"
local searxng_timeout=10
local searxng_counter=0
while [ ! -f "$containers_dir$app_name/searxng-data/settings.yml" ]; do
if [ "$searxng_counter" -ge "$searxng_timeout" ]; then
isNotice "File not found after 10 seconds. Exiting..."
return 0
fi
isNotice "Waiting for the file to appear..."
read -t 1
searxng_counter=$((searxng_counter + 1))
done
local result
result=$(runFileOp sed -i "s/simple_style: auto/simple_style: $CFG_SEARXNG_THEME/" "$containers_dir$app_name/searxng-data/settings.yml")
checkSuccess "Changing from light mode to dark mode to avoid eye strain installs"
dockerComposeRestart $app_name
}

View File

@ -1,135 +0,0 @@
#!/bin/bash
# Category : Privacy & Security Tools
# Description : SearxNG - Privacy-focused Search Engine (c/u/s/r/i):
installSearxng()
{
local config_variables="$1"
if [[ "$searxng" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent searxng;
local app_name=$CFG_SEARXNG_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$searxng" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$searxng" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$searxng" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$searxng" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$searxng" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
local searxng_timeout=10
local searxng_counter=0
# Loop to check for the existence of the file every second
while [ ! -f "$containers_dir$app_name/searxng-data/settings.yml" ]; do
if [ "$searxng_counter" -ge "$searxng_timeout" ]; then
isNotice "File not found after 10 seconds. Exiting..."
break
fi
isNotice "Waiting for the file to appear..."
read -t 1 # Wait for 1 second
# Increment the counter
local searxng_counter=$((searxng_counter + 1))
done
# Check if the file was found or if we timed out
if [ -f "$containers_dir$app_name/searxng-data/settings.yml" ]; then
# Perform the required operation on the file once it exists
local result=$(runFileOp sed -i "s/simple_style: auto/simple_style: $CFG_SEARXNG_THEME/" "$containers_dir$app_name/searxng-data/settings.yml")
checkSuccess "Changing from light mode to dark mode to avoid eye strain installs"
dockerComposeRestart $app_name;
fi
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
searxng=n
}

View File

@ -1,110 +0,0 @@
#!/bin/bash
# Category : Networking
# Description : Speedtest - Network Performance Monitoring (c/u/s/r/i):
installSpeedtest()
{
local config_variables="$1"
if [[ "$speedtest" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent speedtest;
local app_name=$CFG_SPEEDTEST_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$speedtest" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$speedtest" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$speedtest" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$speedtest" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$speedtest" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
speedtest=n
}

View File

@ -0,0 +1,99 @@
#!/bin/bash
# Traefik install hooks — interactive email prompt (LE notices), static +
# dynamic config copy, dashboard-access mode wiring (local-only / domain-
# only / public), monitoring toggle on traefik.yml, whitelist + login.
traefik_install_pre()
{
local app_name="$1"
if [[ -z "$CFG_TRAEFIK_EMAIL" || "$CFG_TRAEFIK_EMAIL" == "changeme" || "$CFG_TRAEFIK_EMAIL" == "Change-Me" ]]; then
if [[ "$LIBREPORTAL_NONINTERACTIVE" == "1" ]]; then
isError "CFG_TRAEFIK_EMAIL not set. Run 'libreportal config update CFG_TRAEFIK_EMAIL=you@example.com' first."
return 1
fi
local traefik_email=""
while true; do
isQuestion "Administrator email for LetsEncrypt (cert-expiry notices) : "
read -p "" traefik_email
emailValidation "$traefik_email"
[[ $? -eq 0 ]] && break
isNotice "Please provide a valid email address."
done
updateConfigOption "CFG_TRAEFIK_EMAIL" "$traefik_email"
sourceScanFiles "libreportal_configs"
fi
}
traefik_install_post_compose()
{
local app_name="$1"
local result
result=$(createFolders "loud" $docker_install_user "$containers_dir$app_name/etc" "$containers_dir$app_name/etc/certs" "$containers_dir$app_name/etc/dynamic" "$containers_dir$app_name/etc/dynamic/middlewears")
checkSuccess "Created etc and certs & dynamic Directories"
result=$(copyResource "$app_name" "traefik.yml" "etc")
checkSuccess "Copy Traefik configuration file for $app_name"
result=$(runFileOp sed -i "s|DEBUGLEVEL|$CFG_TRAEFIK_LOGGING|g" "$containers_dir$app_name/etc/traefik.yml")
checkSuccess "Configured Traefik debug level with: $CFG_TRAEFIK_LOGGING for $app_name"
configSetupFileWithData $app_name "traefik.yml" "etc"
# Apply CFG_TRAEFIK_DASHBOARD_ACCESS: rewrites api.insecure + the
# `traefik:` entrypoint in traefik.yml, and (for local-only) prefixes
# the compose port mapping with 127.0.0.1: so :8080 binds to loopback.
local traefik_yml="$containers_dir$app_name/etc/traefik.yml"
local compose_yml="$containers_dir$app_name/docker-compose.yml"
local access="${CFG_TRAEFIK_DASHBOARD_ACCESS:-local-only}"
case "$access" in
local-only)
runFileOp sed -i 's|^\(\s*insecure:\s*\).*$|\1true|' "$traefik_yml"
runFileOp sed -i '/#LIBREPORTAL|PORTS_TAG_1|/ {
/127\.0\.0\.1:/! s|"\([0-9]\+:[0-9]\+\)"|"127.0.0.1:\1"|
}' "$compose_yml"
checkSuccess "Dashboard access: local-only (loopback :8080 + auth-protected domain)"
;;
domain-only)
runFileOp sed -i 's|^\(\s*insecure:\s*\).*$|\1false|' "$traefik_yml"
runFileOp sed -i '/^\s*traefik:\s*$/,/^\s*address:\s*:8080\s*$/d' "$traefik_yml"
checkSuccess "Dashboard access: domain-only (auth-protected via Host route only)"
;;
public)
runFileOp sed -i 's|^\(\s*insecure:\s*\).*$|\1true|' "$traefik_yml"
runFileOp sed -i '/#LIBREPORTAL|PORTS_TAG_1|/ s|"127\.0\.0\.1:\([0-9]\+:[0-9]\+\)"|"\1"|' "$compose_yml"
checkSuccess "Dashboard access: public (unauthenticated :8080 on all interfaces — legacy)"
;;
*)
isNotice "Unknown CFG_TRAEFIK_DASHBOARD_ACCESS='$access'; leaving traefik.yml at defaults."
;;
esac
# Traefik's metrics block lives in traefik.yml; toggle that here. The
# driver already toggled docker-compose.yml.
monitoringToggleAppConfig "$app_name" "etc/traefik.yml"
result=$(copyResource "$app_name" "config.yml" "etc/dynamic")
checkSuccess "Copy Traefik Dynamic config.yml configuration file for $app_name"
result=$(runFileOp sed -i "s|ERRORWEBSITE|$CFG_TRAEFIK_404_SITE|g" "$containers_dir$app_name/etc/dynamic/config.yml")
checkSuccess "Configured Traefik error website with URL: $CFG_TRAEFIK_404_SITE for $app_name"
configSetupFileWithData $app_name "config.yml" "etc/dynamic"
result=$(copyResource "$app_name" "whitelist.yml" "etc/dynamic")
checkSuccess "Copy Traefik Dynamic whitelist.yml configuration file for $app_name"
result=$(copyResource "$app_name" "protectionauth.yml" "etc/dynamic/middlewears")
checkSuccess "Copy Traefik Dynamic protectionauth.yml configuration file for $app_name"
traefikUpdateWhitelist
result=$(copyResource "$app_name" "tls.yml" "etc/dynamic")
checkSuccess "Copy Traefik Dynamic tls.yml configuration file for $app_name"
traefikSetupLoginCredentials
}

View File

@ -1,222 +0,0 @@
#!/bin/bash
# Category : Networking
# Description : Traefik - Reverse Proxy & Load Balancer (c/u/s/r/i):
installTraefik()
{
local config_variables="$1"
if [[ "$traefik" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent traefik;
local app_name=$CFG_TRAEFIK_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$traefik" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$traefik" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$traefik" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$traefik" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$traefik" == *[iI]* ]]; then
isHeader "Install $app_name"
if [[ -z "$CFG_TRAEFIK_EMAIL" || "$CFG_TRAEFIK_EMAIL" == "changeme" || "$CFG_TRAEFIK_EMAIL" == "Change-Me" ]]; then
if [[ "$LIBREPORTAL_NONINTERACTIVE" == "1" ]]; then
isError "CFG_TRAEFIK_EMAIL not set. Run 'libreportal config update CFG_TRAEFIK_EMAIL=you@example.com' first."
return 1
fi
local traefik_email=""
while true; do
isQuestion "Administrator email for LetsEncrypt (cert-expiry notices) : "
read -p "" traefik_email
emailValidation "$traefik_email"
[[ $? -eq 0 ]] && break
isNotice "Please provide a valid email address."
done
updateConfigOption "CFG_TRAEFIK_EMAIL" "$traefik_email"
sourceScanFiles "libreportal_configs"
fi
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
# Create necessary directories and set permissions
local result=$(createFolders "loud" $docker_install_user "$containers_dir$app_name/etc" "$containers_dir$app_name/etc/certs" "$containers_dir$app_name/etc/dynamic" "$containers_dir$app_name/etc/dynamic/middlewears")
checkSuccess "Created etc and certs & dynamic Directories"
# Static traefik.yml File
# Copy the Traefik configuration file and customize it
local result=$(copyResource "$app_name" "traefik.yml" "etc")
checkSuccess "Copy Traefik configuration file for $app_name"
# Setup Debug Level
local result=$(runFileOp sed -i "s|DEBUGLEVEL|$CFG_TRAEFIK_LOGGING|g" "$containers_dir$app_name/etc/traefik.yml")
checkSuccess "Configured Traefik debug level with: $CFG_TRAEFIK_LOGGING for $app_name"
configSetupFileWithData $app_name "traefik.yml" "etc";
# Apply CFG_TRAEFIK_DASHBOARD_ACCESS: rewrites api.insecure + the
# `traefik:` entrypoint in traefik.yml, and (for local-only) prefixes
# the compose port mapping with 127.0.0.1: so :8080 binds to loopback.
local traefik_yml="$containers_dir$app_name/etc/traefik.yml"
local compose_yml="$containers_dir$app_name/docker-compose.yml"
local access="${CFG_TRAEFIK_DASHBOARD_ACCESS:-local-only}"
case "$access" in
local-only)
runFileOp sed -i 's|^\(\s*insecure:\s*\).*$|\1true|' "$traefik_yml"
# Bind PORT_1 mapping to 127.0.0.1 only. Idempotent — only
# adds the prefix if it isn't already there.
runFileOp sed -i '/#LIBREPORTAL|PORTS_TAG_1|/ {
/127\.0\.0\.1:/! s|"\([0-9]\+:[0-9]\+\)"|"127.0.0.1:\1"|
}' "$compose_yml"
checkSuccess "Dashboard access: local-only (loopback :8080 + auth-protected domain)"
;;
domain-only)
runFileOp sed -i 's|^\(\s*insecure:\s*\).*$|\1false|' "$traefik_yml"
# Drop the :8080 entrypoint entirely — nothing should listen
# there if the dashboard is domain-only.
runFileOp sed -i '/^\s*traefik:\s*$/,/^\s*address:\s*:8080\s*$/d' "$traefik_yml"
checkSuccess "Dashboard access: domain-only (auth-protected via Host route only)"
;;
public)
runFileOp sed -i 's|^\(\s*insecure:\s*\).*$|\1true|' "$traefik_yml"
# Strip any 127.0.0.1: prefix the compose port may have
# picked up from a previous local-only install.
runFileOp sed -i '/#LIBREPORTAL|PORTS_TAG_1|/ s|"127\.0\.0\.1:\([0-9]\+:[0-9]\+\)"|"\1"|' "$compose_yml"
checkSuccess "Dashboard access: public (unauthenticated :8080 on all interfaces — legacy)"
;;
*)
isNotice "Unknown CFG_TRAEFIK_DASHBOARD_ACCESS='$access'; leaving traefik.yml at defaults."
;;
esac
# Enable the Prometheus metrics endpoint + provider only when
# CFG_TRAEFIK_MONITORING=true (toggles the libreportal-monitoring
# marker blocks in traefik.yml). monitoringRefreshAll later in this
# install picks up the scrape fragment + dashboard.
monitoringToggleAppConfig "$app_name" "etc/traefik.yml";
# Dynamic config.yml File
# Copy the Traefik configuration file and customize it
local result=$(copyResource "$app_name" "config.yml" "etc/dynamic")
checkSuccess "Copy Traefik Dynamic config.yml configuration file for $app_name"
# Setup Error 404 Website
local result=$(runFileOp sed -i "s|ERRORWEBSITE|$CFG_TRAEFIK_404_SITE|g" "$containers_dir$app_name/etc/dynamic/config.yml")
checkSuccess "Configured Traefik error website with URL: $CFG_TRAEFIK_404_SITE for $app_name"
configSetupFileWithData $app_name "config.yml" "etc/dynamic";
# Dynamic whitelist.yml File
local result=$(copyResource "$app_name" "whitelist.yml" "etc/dynamic")
checkSuccess "Copy Traefik Dynamic whitelist.yml configuration file for $app_name"
# Middlewears
# Dynamic protectionauth.yml File
local result=$(copyResource "$app_name" "protectionauth.yml" "etc/dynamic/middlewears")
checkSuccess "Copy Traefik Dynamic protectionauth.yml configuration file for $app_name"
traefikUpdateWhitelist;
# Dynamic tls.yml File
local result=$(copyResource "$app_name" "tls.yml" "etc/dynamic")
checkSuccess "Copy Traefik Dynamic tls.yml configuration file for $app_name"
traefikSetupLoginCredentials;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Refreshing monitoring integration."
echo ""
# Self-correcting: adds Traefik's scrape target + dashboard to
# Prometheus/Grafana when CFG_TRAEFIK_MONITORING=true, removes them
# when it's off. No-ops with a notice if either app isn't installed.
monitoringRefreshAll;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
traefik=n
}

View File

@ -0,0 +1,31 @@
#!/bin/bash
# Trilium install hooks — wait for first-boot config.ini, retune port, restart.
trilium_install_post_start()
{
local app_name="$1"
((menu_number++))
echo ""
echo "---- $menu_number. Updating default port and restarting $app_name"
echo ""
local trilium_timeout=10
local trilium_counter=0
while [ ! -f "$containers_dir$app_name/trilium-data/config.ini" ]; do
if [ "$trilium_counter" -ge "$trilium_timeout" ]; then
isNotice "File not found after 10 seconds. Exiting..."
return 0
fi
isNotice "Waiting for the file to appear..."
read -t 1
trilium_counter=$((trilium_counter + 1))
done
local result
result=$(runFileOp sed -i "s|port=8080|port=$usedport1|g" "$containers_dir$app_name/trilium-data/config.ini")
checkSuccess "Configured $app_name from default 8080 to $usedport1"
dockerComposeRestart $app_name
}

View File

@ -1,136 +0,0 @@
#!/bin/bash
# Category : Knowledge Management
# Description : Trilium - Notes & Knowledge Management (c/u/s/r/i):
installTrilium()
{
local config_variables="$1"
if [[ "$trilium" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent trilium;
local app_name=$CFG_TRILIUM_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$trilium" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$trilium" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$trilium" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$trilium" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$trilium" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Updating defaul port and restarting $app_name"
echo ""
local trilium_timeout=10
local trilium_counter=0
# Loop to check for the existence of the file every second
while [ ! -f "$containers_dir$app_name/trilium-data/config.ini" ]; do
if [ "$trilium_counter" -ge "$trilium_timeout" ]; then
isNotice "File not found after 10 seconds. Exiting..."
break
fi
isNotice "Waiting for the file to appear..."
read -t 1 # Wait for 1 second
# Increment the counter
local trilium_counter=$((trilium_counter + 1))
done
result=$(runFileOp sed -i "s|port=8080|port=$usedport1|g" "$containers_dir$app_name/trilium-data/config.ini")
checkSuccess "Configured $app_name from default 8080 to $usedport1"
dockerComposeRestart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
trilium=n
}

View File

@ -0,0 +1,15 @@
#!/bin/bash
# Unbound install hooks — drop unbound.conf into etc/ and toggle the
# monitoring marker in it (the driver already handled docker-compose.yml).
unbound_install_post_compose()
{
local app_name="$1"
local result
result=$(copyResource "$app_name" "unbound.conf" "etc" | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1)
checkSuccess "Copying unbound.conf to containers folder."
monitoringToggleAppConfig "$app_name" "etc/unbound.conf"
}

View File

@ -1,126 +0,0 @@
#!/bin/bash
# Category : Networking
# Description : Unbound - DNS Resolver (c/u/s/r/i):
installUnbound()
{
local config_variables="$1"
if [[ "$unbound" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent unbound;
local app_name=$CFG_UNBOUND_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$unbound" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$unbound" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$unbound" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$unbound" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$unbound" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
monitoringToggleAppConfig "$app_name" "docker-compose.yml";
local result=$(copyResource "$app_name" "unbound.conf" "etc" | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1)
checkSuccess "Copying unbound.conf to containers folder."
monitoringToggleAppConfig "$app_name" "etc/unbound.conf";
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Refreshing monitoring integration."
echo ""
monitoringRefreshAll;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
echo " NOTICE : Below are the URLs for the admin panel to use after you have setup Unbound"
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
unbound=n
}

View File

@ -1,119 +0,0 @@
#!/bin/bash
# Category : Privacy & Security Tools
# Description : Vaultwarden - Password Manager (c/u/s/r/i):
installVaultwarden()
{
local config_variables="$1"
if [[ "$vaultwarden" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent vaultwarden;
local app_name=$CFG_VAULTWARDEN_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$vaultwarden" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$vaultwarden" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$vaultwarden" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$vaultwarden" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$vaultwarden" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
monitoringToggleAppConfig "$app_name" "docker-compose.yml";
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Refreshing monitoring integration."
echo ""
monitoringRefreshAll;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
vaultwarden=n
}

View File

@ -0,0 +1,103 @@
#!/bin/bash
# WireGuard install hooks — host-conflict guard, tunnel subnet generation,
# WG_HOST resolution, IP forwarding setup, and a post-start restart so
# the firewall rules from wg-easy take effect cleanly.
wireguard_install_pre()
{
local app_name="$1"
((menu_number++))
echo ""
echo "---- $menu_number. Checking if $app_name can be installed."
echo ""
# Host-conflict guard: a host-level WireGuard (e.g. the angristan
# wireguard-install script — marker /etc/wireguard/params) collides
# with this container on the wg kernel module + UDP 51820. Abort.
if [[ -e /etc/wireguard/params ]]; then
isError "WireGuard is already installed on the host — this conflicts with the $app_name app."
isError "Installation is now aborting..."
dockerUninstallApp "$app_name"
return 1
fi
}
wireguard_install_post_compose()
{
local app_name="$1"
((menu_number++))
echo ""
echo "---- $menu_number. Resolving wireguard tunnel subnet (WG_DEFAULT_ADDRESS)"
echo ""
# Generate-once-and-persist tunnel subnet. Second-octet 200-250 is
# outside the docker network generator range (100-149), so the two
# subnets cannot collide. Reusing the persisted value keeps existing
# peer configs valid across reinstalls.
local _wg_compose_for_subnet="$containers_dir$app_name/docker-compose.yml"
if [[ -z "$CFG_WIREGUARD_SUBNET" ]]; then
local _wg_second=$(( RANDOM % 51 + 200 ))
local _wg_third=$(( RANDOM % 256 ))
CFG_WIREGUARD_SUBNET="10.${_wg_second}.${_wg_third}.0"
updateConfigOption "CFG_WIREGUARD_SUBNET" "$CFG_WIREGUARD_SUBNET"
isSuccessful "Generated wireguard tunnel subnet: $CFG_WIREGUARD_SUBNET"
else
isNotice "Reusing existing wireguard tunnel subnet: $CFG_WIREGUARD_SUBNET"
fi
# wg-easy expects the address pattern `<base>.x` (literal x).
local _wg_addr_pattern="${CFG_WIREGUARD_SUBNET%.0}.x"
tagsManagerUpdateUniversalTag "$_wg_compose_for_subnet" "WIREGUARD_SUBNET_TAG" "$_wg_addr_pattern"
isSuccessful "WG_DEFAULT_ADDRESS set to $_wg_addr_pattern"
((menu_number++))
echo ""
echo "---- $menu_number. Resolving WG_HOST for peer configs"
echo ""
local wg_compose_file="$containers_dir$app_name/docker-compose.yml"
local wg_host_value=""
local _wg_traefik_installed=0
if declare -f checkServiceInstalled >/dev/null 2>&1 && checkServiceInstalled "traefik"; then
_wg_traefik_installed=1
fi
if [[ -n "$domain_full" && $_wg_traefik_installed -eq 1 ]]; then
wg_host_value="$host_setup"
isNotice "Domain + Traefik present — peer configs will use $wg_host_value"
else
wg_host_value="${public_ip_v4:-127.0.0.1}"
if [[ -n "$domain_full" && $_wg_traefik_installed -eq 0 ]]; then
isNotice "Domain configured but Traefik not installed — falling back to IP $wg_host_value so peer configs actually resolve."
else
isNotice "No domain configured — peer configs will use IP $wg_host_value (LAN only)"
fi
fi
tagsManagerUpdateUniversalTag "$wg_compose_file" "PUBLIC_IP_TAG" "$wg_host_value"
isSuccessful "WG_HOST set to $wg_host_value"
((menu_number++))
echo ""
echo "---- $menu_number. Enabling IP forwarding"
echo ""
# Drop in /etc/sysctl.d/99-libreportal-wireguard.conf + reload — the
# whole thing runs as root through libreportal-appcfg so the manager
# never needs blanket /etc write or `sudo sysctl` itself.
local result
result=$(runAppCfg wireguard-ip-forward)
checkSuccess "Enabling IPv4 IP Forwarding (sysctl drop-in + reload)"
}
wireguard_install_post_start()
{
local app_name="$1"
((menu_number++))
echo ""
echo "---- $menu_number. Restarting $app_name after firewall changes"
echo ""
dockerComposeRestart $app_name
}

View File

@ -1,201 +0,0 @@
#!/bin/bash
# Category : Networking
# Description : Wireguard Easy - VPN Server (c/u/s/r/i):
installWireguard()
{
local config_variables="$1"
if [[ "$wireguard" == *[cCtTuUsSrRiI]* ]]; then
dockerConfigSetupToContainer silent wireguard;
local app_name=$CFG_WIREGUARD_APP_NAME
initializeAppVariables $app_name;
fi
if [[ "$wireguard" == *[cC]* ]]; then
editAppConfig $app_name;
fi
if [[ "$wireguard" == *[uU]* ]]; then
dockerUninstallApp $app_name;
fi
if [[ "$wireguard" == *[sS]* ]]; then
dockerComposeDown $app_name;
fi
if [[ "$wireguard" == *[rR]* ]]; then
dockerComposeRestart $app_name;
fi
if [[ "$wireguard" == *[iI]* ]]; then
isHeader "Install $app_name"
((menu_number++))
echo ""
echo "---- $menu_number. Checking if $app_name can be installed."
echo ""
# Host-conflict guard: a host-level WireGuard (e.g. the angristan
# wireguard-install script — marker /etc/wireguard/params) collides with
# this container on the wg kernel module + UDP 51820. Abort if present.
if [[ -e /etc/wireguard/params ]]; then
isError "WireGuard is already installed on the host — this conflicts with the $app_name app."
isError "Installation is now aborting..."
dockerUninstallApp "$app_name"
return 1
fi
((menu_number++))
echo ""
echo "---- $menu_number. Setting up install folder and config file for $app_name."
echo ""
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
isSuccessful "Install folders and Config files have been setup for $app_name."
((menu_number++))
echo ""
((menu_number++))
echo ""
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
echo ""
dockerComposeSetupFile $app_name;
monitoringToggleAppConfig "$app_name" "docker-compose.yml";
((menu_number++))
echo ""
echo "---- $menu_number. Resolving wireguard tunnel subnet (WG_DEFAULT_ADDRESS)"
echo ""
# Generate-once-and-persist tunnel subnet. Second-octet 200-250 is
# outside the docker network generator range (100-149), so the two
# subnets cannot collide. Reusing the persisted value keeps existing
# peer configs valid across reinstalls.
local _wg_compose_for_subnet="$containers_dir$app_name/docker-compose.yml"
if [[ -z "$CFG_WIREGUARD_SUBNET" ]]; then
local _wg_second=$(( RANDOM % 51 + 200 )) # 200-250
local _wg_third=$(( RANDOM % 256 )) # 0-255
CFG_WIREGUARD_SUBNET="10.${_wg_second}.${_wg_third}.0"
updateConfigOption "CFG_WIREGUARD_SUBNET" "$CFG_WIREGUARD_SUBNET"
isSuccessful "Generated wireguard tunnel subnet: $CFG_WIREGUARD_SUBNET"
else
isNotice "Reusing existing wireguard tunnel subnet: $CFG_WIREGUARD_SUBNET"
fi
# wg-easy expects the address pattern `<base>.x` (literal x).
local _wg_addr_pattern="${CFG_WIREGUARD_SUBNET%.0}.x"
tagsManagerUpdateUniversalTag "$_wg_compose_for_subnet" "WIREGUARD_SUBNET_TAG" "$_wg_addr_pattern"
isSuccessful "WG_DEFAULT_ADDRESS set to $_wg_addr_pattern"
((menu_number++))
echo ""
echo "---- $menu_number. Resolving WG_HOST for peer configs"
echo ""
local wg_compose_file="$containers_dir$app_name/docker-compose.yml"
local wg_host_value=""
local _wg_traefik_installed=0
if declare -f checkServiceInstalled >/dev/null 2>&1 && checkServiceInstalled "traefik"; then
_wg_traefik_installed=1
fi
if [[ -n "$domain_full" && $_wg_traefik_installed -eq 1 ]]; then
wg_host_value="$host_setup"
isNotice "Domain + Traefik present — peer configs will use $wg_host_value"
else
wg_host_value="${public_ip_v4:-127.0.0.1}"
if [[ -n "$domain_full" && $_wg_traefik_installed -eq 0 ]]; then
isNotice "Domain configured but Traefik not installed — falling back to IP $wg_host_value so peer configs actually resolve."
else
isNotice "No domain configured — peer configs will use IP $wg_host_value (LAN only)"
fi
fi
tagsManagerUpdateUniversalTag "$wg_compose_file" "PUBLIC_IP_TAG" "$wg_host_value"
isSuccessful "WG_HOST set to $wg_host_value"
((menu_number++))
echo ""
echo "---- $menu_number. Enabling IP forwarding"
echo ""
# Drop in /etc/sysctl.d/99-libreportal-wireguard.conf + reload — the
# whole thing runs as root through libreportal-appcfg so the manager
# never needs blanket /etc write or `sudo sysctl` itself.
local result=$(runAppCfg wireguard-ip-forward)
checkSuccess "Enabling IPv4 IP Forwarding (sysctl drop-in + reload)"
((menu_number++))
echo ""
echo "---- $menu_number. Updating file permissions before starting."
echo ""
fixPermissionsBeforeStart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running the docker-compose.yml to Install $app_name"
echo ""
dockerComposeUpdateAndStartApp $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Restarting $app_name after firewall changes"
echo ""
dockerComposeRestart $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Application specific updates (if required)"
echo ""
appUpdateSpecifics $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Running Headscale setup (if required)"
echo ""
setupHeadscale $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Adding $app_name to the Apps Database table."
echo ""
databaseInstallApp $app_name;
((menu_number++))
echo ""
echo "---- $menu_number. Updating WebUI config file."
echo ""
webuiContainerSetup $app_name install;
((menu_number++))
echo ""
echo "---- $menu_number. Refreshing monitoring integration."
echo ""
monitoringRefreshAll;
((menu_number++))
echo ""
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
echo ""
echo " You can now navigate to your $app_name service using any of the options below : "
echo ""
menuShowFinalMessages $app_name;
menu_number=0
#sleep 3s
cd
fi
wireguard=n
}

View File

@ -58,12 +58,10 @@ _appPostStartIntegrations()
databaseInstallApp "$app_name"
webuiContainerSetup "$app_name" install
# Monitoring registration — 6 of the 31 apps used to call these inline.
# Idempotent + no-op-safe for apps without monitoring tags, so we run
# them unconditionally now and let each function handle its own gating.
if declare -F monitoringToggleAppConfig >/dev/null 2>&1; then
monitoringToggleAppConfig "$app_name" "docker-compose.yml" 2>/dev/null || true
fi
# Scrape-target + dashboard re-gather. The compose-level toggle ran
# already (post-compose, so the running container reflects it).
# monitoringRefreshAll is self-correcting and no-ops when Prometheus
# / Grafana aren't installed.
if declare -F monitoringRefreshAll >/dev/null 2>&1; then
monitoringRefreshAll 2>/dev/null || true
fi
@ -126,6 +124,18 @@ installApp()
echo "---- $menu_number. Setting up the $app_name docker-compose.yml."
echo ""
dockerComposeSetupFile "$app_name"
# Compose-level monitoring toggle MUST run before docker-compose up
# — the compose file is the source of truth for the running
# container, so editing it post-start wouldn't take effect until
# the next restart. Idempotent + no-op for apps without a marker
# block; apps that toggle additional files (authelia config.yml,
# traefik traefik.yml, unbound unbound.conf …) call it again from
# their _install_post_compose hook.
if declare -F monitoringToggleAppConfig >/dev/null 2>&1; then
monitoringToggleAppConfig "$app_name" "docker-compose.yml" 2>/dev/null || true
fi
_appCallHook "${app_slug}_install_post_compose" "$app_name"
# Optional .env handling — apps that ship a .env in their template

View File

@ -12,6 +12,8 @@
# "containers" entries — see LP_FN_ROOT below.
declare -gA LP_FN_MAP=(
[acquireSingletonLock]="crontab/task/crontab_task_processor.sh"
[adguard_install_message_data]="adguard/scripts/adguard_install_hooks.sh"
[adguard_install_post_start]="adguard/scripts/adguard_install_hooks.sh"
[adoptDockerSubnet]="checks/requirements/check_docker_network.sh"
[appAdguardApplyDnsUpdater]="adguard/tools/adguard_apply_dns_updater.sh"
[appAdguardResetPassword]="adguard/tools/adguard_reset_password.sh"
@ -134,6 +136,10 @@ declare -gA LP_FN_MAP=(
[authAdapter_nextcloud_setAdmin]="nextcloud/scripts/nextcloud_auth.sh"
[authAdapter_nextcloud_setPassword]="nextcloud/scripts/nextcloud_auth.sh"
[authAdapter_traefik_setPassword]="traefik/scripts/traefik_auth.sh"
[authelia_install_post]="authelia/scripts/authelia_install_hooks.sh"
[authelia_install_post_compose]="authelia/scripts/authelia_install_hooks.sh"
[authelia_install_post_start]="authelia/scripts/authelia_install_hooks.sh"
[authelia_install_pre]="authelia/scripts/authelia_install_hooks.sh"
[authPersistCfg]="app/auth_adapter.sh"
[authToolArg]="app/auth_adapter.sh"
[backupAllApps]="backup/app/backup_app_all.sh"
@ -183,6 +189,7 @@ declare -gA LP_FN_MAP=(
[backupSystemConfig]="backup/system/backup_system.sh"
[backupVerifySnapshot]="backup/verify/backup_verify.sh"
[_bookstackArtisan]="bookstack/scripts/bookstack_auth.sh"
[bookstack_install_post_start]="bookstack/scripts/bookstack_install_hooks.sh"
[borgArchiveName]="backup/engine/borg_env.sh"
[borgBackupAppToLocation]="backup/engine/borg_backup.sh"
[borgBackupSystemToLocation]="backup/engine/borg_backup.sh"
@ -423,15 +430,20 @@ declare -gA LP_FN_MAP=(
[gitCheckGitDetails]="update/git/check_git_details.sh"
[gitCleanInstallBackups]="update/backup/install_git_backup.sh"
[_giteaCmd]="gitea/scripts/gitea_auth.sh"
[gitea_install_post_compose]="gitea/scripts/gitea_install_hooks.sh"
[gitFolderResetAndBackup]="update/backup/reset_git_backup.sh"
[gitPerformUpdate]="update/backup/reset_git_backup.sh"
[gitReset]="update/git/reset_git.sh"
[gitUntrackFiles]="update/git/untrack_files.sh"
[gitUseExistingBackup]="update/backup/use_git_backup.sh"
[gluetun_install_post_start]="gluetun/scripts/gluetun_install_hooks.sh"
[gluetunRouteExistingAppsPrompt]="gluetun/scripts/gluetun_route_apps.sh"
[grafana_install_post_start]="grafana/scripts/grafana_install_hooks.sh"
[grafana_install_pre]="grafana/scripts/grafana_install_hooks.sh"
[hashPassword]="config/password/password_hash.sh"
[headscaleCommands]="headscale/scripts/headscale_commands.sh"
[headscaleEditConfig]="headscale/scripts/headscale_edit_config.sh"
[headscale_install_post_compose]="headscale/scripts/headscale_install_hooks.sh"
[healthLogError]="crontab/task/crontab_check_processor.sh"
[healthLogInfo]="crontab/task/crontab_check_processor.sh"
[healthLogSuccess]="crontab/task/crontab_check_processor.sh"
@ -448,15 +460,11 @@ declare -gA LP_FN_MAP=(
[hostSshSetPasswordAuth]="ssh/host_access.sh"
[hostSshUser]="ssh/host_access.sh"
[initializeAppVariables]="network/variables/variables_init_app.sh"
[installAdguard]="adguard/adguard.sh"
[installApp]="app/install/app_install.sh"
[installArch]="os/install/arch.sh"
[installAuthelia]="authelia/authelia.sh"
[installBookstack]="bookstack/bookstack.sh"
[installCrontab]="crontab/crontab_install.sh"
[installCrowdsec]="crowdsec/crowdsec.sh"
[installCrowdsecHost]="crowdsec/scripts/crowdsec_install_host.sh"
[installDashy]="dashy/dashy.sh"
[installDebianUbuntu]="os/install/ubuntu.sh"
[installDockerNetwork]="docker/network/network_setup.sh"
[installDockerRooted]="docker/install/rooted/rooted_docker.sh"
@ -465,44 +473,20 @@ declare -gA LP_FN_MAP=(
[installDockerRootless]="docker/install/rootless/rootless_docker.sh"
[installDockerRootlessStartSetup]="docker/install/rootless/rootless_start_setup.sh"
[installDockerRootlessUser]="docker/install/rootless/rootless_user.sh"
[installFocalboard]="focalboard/focalboard.sh"
[installGitea]="gitea/gitea.sh"
[installGluetun]="gluetun/gluetun.sh"
[installGrafana]="grafana/grafana.sh"
[installHeadscale]="headscale/headscale.sh"
[installInvidious]="invidious/invidious.sh"
[installIpinfo]="ipinfo/ipinfo.sh"
[installJellyfin]="jellyfin/jellyfin.sh"
[installJitsimeet]="jitsimeet/jitsimeet.sh"
[installLibrePortal]="libreportal/libreportal.sh"
[installLibrePortalAppWebUI]="webui/webui_install_app.sh"
[installLibrePortalImageWebUI]="webui/webui_install_image.sh"
[installLibrePortalWebUITaskService]="webui/webui_install_systemd.sh"
[installMastodon]="mastodon/mastodon.sh"
[installMoneyapp]="moneyapp/moneyapp.sh"
[installNextcloud]="nextcloud/nextcloud.sh"
[installOllama]="ollama/ollama.sh"
[installOnlyoffice]="onlyoffice/onlyoffice.sh"
[installOptionalMetricsApps]="start/start_recommended.sh"
[installOwncloud]="owncloud/owncloud.sh"
[installPihole]="pihole/pihole.sh"
[installPrometheus]="prometheus/prometheus.sh"
[installRecommendedApps]="start/start_recommended.sh"
[installResticHost]="install/install_restic.sh"
[installResticMigrateLegacyPasswords]="install/install_restic.sh"
[installRootlessApparmorForPasta]="docker/install/rootless/rootless_apparmor.sh"
[installSearxng]="searxng/searxng.sh"
[installSpeedtest]="speedtest/speedtest.sh"
[installSQLiteDatabase]="database/install_sqlite.sh"
[installSSLCertificate]="install/install_certificate.sh"
[installSwapfile]="install/install_swapfile.sh"
[installTraefik]="traefik/traefik.sh"
[installTrilium]="trilium/trilium.sh"
[installUFW]="install/install_ufw.sh"
[installUFWDocker]="install/install_ufwd.sh"
[installUnbound]="unbound/unbound.sh"
[installVaultwarden]="vaultwarden/vaultwarden.sh"
[installWireguard]="wireguard/wireguard.sh"
[_invidiousBcrypt]="invidious/scripts/invidious_auth.sh"
[_invidiousPsql]="invidious/scripts/invidious_auth.sh"
[invidiousToolsMenu]="menu/tools/manage_invidious.sh"
@ -526,6 +510,9 @@ declare -gA LP_FN_MAP=(
[isQuestion]="menu/message/markers.sh"
[isSetupWizardComplete]="setup/setup_lock.sh"
[isSuccessful]="menu/message/markers.sh"
[jitsimeet_install_post_compose]="jitsimeet/scripts/jitsimeet_install_hooks.sh"
[jitsimeet_install_post_setup]="jitsimeet/scripts/jitsimeet_install_hooks.sh"
[jitsimeet_install_post_start]="jitsimeet/scripts/jitsimeet_install_hooks.sh"
[kopiaBackupAppToLocation]="backup/engine/kopia_backup.sh"
[kopiaBackupSystemToLocation]="backup/engine/kopia_backup.sh"
[kopiaCheckLocation]="backup/engine/kopia_check.sh"
@ -605,6 +592,8 @@ declare -gA LP_FN_MAP=(
[migrateRunHook]="migrate/migrate_hooks.sh"
[migrateSystem]="migrate/migrate_apply.sh"
[migrateUrlRewriteEnabled]="migrate/migrate_url_rewrite.sh"
[moneyapp_install_post_compose]="moneyapp/scripts/moneyapp_install_hooks.sh"
[moneyapp_install_pre]="moneyapp/scripts/moneyapp_install_hooks.sh"
[monitoringAppEnabled]="network/monitoring/monitoring.sh"
[monitoringInstalledApps]="network/monitoring/monitoring.sh"
[monitoringIsInstalled]="network/monitoring/monitoring.sh"
@ -616,7 +605,9 @@ declare -gA LP_FN_MAP=(
[moveFile]="function/file/move_file.sh"
[_nextcloudOcc]="nextcloud/scripts/nextcloud_auth.sh"
[_nextcloudOccWithPass]="nextcloud/scripts/nextcloud_auth.sh"
[onlyoffice_install_message_data]="onlyoffice/scripts/onlyoffice_install_hooks.sh"
[openFifoReader]="crontab/task/crontab_task_processor.sh"
[owncloud_install_post_compose]="owncloud/scripts/owncloud_install_hooks.sh"
[passwordValidation]="function/validation/password.sh"
[peerAdd]="peer/peer_add.sh"
[peerCheckAll]="peer/peer_check.sh"
@ -667,6 +658,8 @@ declare -gA LP_FN_MAP=(
[portStoreMapping]="network/ports/allocation/port_store_mapping.sh"
[portUpdateComposeTags]="network/ports/allocation/port_update_compose_tags.sh"
[processBcryptPassword]="config/password/bcrypt/password_process_bcrypt.sh"
[prometheus_install_post_compose]="prometheus/scripts/prometheus_install_hooks.sh"
[prometheus_install_post_start]="prometheus/scripts/prometheus_install_hooks.sh"
[readTaskField]="crontab/task/crontab_task_processor.sh"
[reconcileConfigFile]="config/core/variables/config_scan_variables.sh"
[reconcileContainersTopOwnership]="function/permission/libreportal_folders.sh"
@ -754,6 +747,7 @@ declare -gA LP_FN_MAP=(
[run_task_processor]="crontab/task/crontab_task_processor.sh"
[scanConfigsForRandomPassword]="config/password/password_update_all.sh"
[scanFileForRandomPasswordKeysUsers]="config/password/password_scan_file.sh"
[searxng_install_post_start]="searxng/scripts/searxng_install_hooks.sh"
[setupApply]="setup/setup_apply.sh"
[setupApplyConfig]="setup/setup_apply.sh"
[setupApplyFinalize]="setup/setup_apply.sh"
@ -805,9 +799,13 @@ declare -gA LP_FN_MAP=(
[tailscaleInstallToContainer]="headscale/scripts/tailscale_install.sh"
[toolArgsGet]="docker/app/functions/function_app_tool.sh"
[toolsMenu]="menu/tools/manage_main.sh"
[traefik_install_post_compose]="traefik/scripts/traefik_install_hooks.sh"
[traefik_install_pre]="traefik/scripts/traefik_install_hooks.sh"
[traefikSetupLabelsMiddlewares]="network/traefik/traefik_middlewares.sh"
[traefikSetupLoginCredentials]="network/traefik/traefik_login_credentials.sh"
[traefikUpdateWhitelist]="network/traefik/traefik_whitelist.sh"
[trilium_install_post_start]="trilium/scripts/trilium_install_hooks.sh"
[unbound_install_post_compose]="unbound/scripts/unbound_install_hooks.sh"
[uninstallCrowdsec]="crowdsec/crowdsec.sh"
[uninstallDockerRootless]="docker/install/rootless/rootless_uninstall.sh"
[updateAppConfig]="webui/data/generators/apps/webui_app_config.sh"
@ -887,6 +885,9 @@ declare -gA LP_FN_MAP=(
[webuiUpdateSystemConfig]="webui/data/generators/config/webui_update_config.sh"
[webuiValidateConfigValue]="webui/data/generators/config/webui_update_config.sh"
[whitelistPortUpdater]="docker/whitelist_port_updater.sh"
[wireguard_install_post_compose]="wireguard/scripts/wireguard_install_hooks.sh"
[wireguard_install_post_start]="wireguard/scripts/wireguard_install_hooks.sh"
[wireguard_install_pre]="wireguard/scripts/wireguard_install_hooks.sh"
[writeAtomic]="crontab/task/crontab_task_processor.sh"
[zipFile]="function/file/zip_file.sh"
)
@ -895,6 +896,8 @@ declare -gA LP_FN_MAP=(
# LP_FN_MAP; used by the loader / debugging tools.
declare -gA LP_FN_ROOT=(
[acquireSingletonLock]="scripts"
[adguard_install_message_data]="containers"
[adguard_install_post_start]="containers"
[adoptDockerSubnet]="scripts"
[appAdguardApplyDnsUpdater]="containers"
[appAdguardResetPassword]="containers"
@ -1017,6 +1020,10 @@ declare -gA LP_FN_ROOT=(
[authAdapter_nextcloud_setAdmin]="containers"
[authAdapter_nextcloud_setPassword]="containers"
[authAdapter_traefik_setPassword]="containers"
[authelia_install_post]="containers"
[authelia_install_post_compose]="containers"
[authelia_install_post_start]="containers"
[authelia_install_pre]="containers"
[authPersistCfg]="scripts"
[authToolArg]="scripts"
[backupAllApps]="scripts"
@ -1066,6 +1073,7 @@ declare -gA LP_FN_ROOT=(
[backupSystemConfig]="scripts"
[backupVerifySnapshot]="scripts"
[_bookstackArtisan]="containers"
[bookstack_install_post_start]="containers"
[borgArchiveName]="scripts"
[borgBackupAppToLocation]="scripts"
[borgBackupSystemToLocation]="scripts"
@ -1306,15 +1314,20 @@ declare -gA LP_FN_ROOT=(
[gitCheckGitDetails]="scripts"
[gitCleanInstallBackups]="scripts"
[_giteaCmd]="containers"
[gitea_install_post_compose]="containers"
[gitFolderResetAndBackup]="scripts"
[gitPerformUpdate]="scripts"
[gitReset]="scripts"
[gitUntrackFiles]="scripts"
[gitUseExistingBackup]="scripts"
[gluetun_install_post_start]="containers"
[gluetunRouteExistingAppsPrompt]="containers"
[grafana_install_post_start]="containers"
[grafana_install_pre]="containers"
[hashPassword]="scripts"
[headscaleCommands]="containers"
[headscaleEditConfig]="containers"
[headscale_install_post_compose]="containers"
[healthLogError]="scripts"
[healthLogInfo]="scripts"
[healthLogSuccess]="scripts"
@ -1331,15 +1344,11 @@ declare -gA LP_FN_ROOT=(
[hostSshSetPasswordAuth]="scripts"
[hostSshUser]="scripts"
[initializeAppVariables]="scripts"
[installAdguard]="containers"
[installApp]="scripts"
[installArch]="scripts"
[installAuthelia]="containers"
[installBookstack]="containers"
[installCrontab]="scripts"
[installCrowdsec]="containers"
[installCrowdsecHost]="containers"
[installDashy]="containers"
[installDebianUbuntu]="scripts"
[installDockerNetwork]="scripts"
[installDockerRooted]="scripts"
@ -1348,44 +1357,20 @@ declare -gA LP_FN_ROOT=(
[installDockerRootless]="scripts"
[installDockerRootlessStartSetup]="scripts"
[installDockerRootlessUser]="scripts"
[installFocalboard]="containers"
[installGitea]="containers"
[installGluetun]="containers"
[installGrafana]="containers"
[installHeadscale]="containers"
[installInvidious]="containers"
[installIpinfo]="containers"
[installJellyfin]="containers"
[installJitsimeet]="containers"
[installLibrePortal]="containers"
[installLibrePortalAppWebUI]="scripts"
[installLibrePortalImageWebUI]="scripts"
[installLibrePortalWebUITaskService]="scripts"
[installMastodon]="containers"
[installMoneyapp]="containers"
[installNextcloud]="containers"
[installOllama]="containers"
[installOnlyoffice]="containers"
[installOptionalMetricsApps]="scripts"
[installOwncloud]="containers"
[installPihole]="containers"
[installPrometheus]="containers"
[installRecommendedApps]="scripts"
[installResticHost]="scripts"
[installResticMigrateLegacyPasswords]="scripts"
[installRootlessApparmorForPasta]="scripts"
[installSearxng]="containers"
[installSpeedtest]="containers"
[installSQLiteDatabase]="scripts"
[installSSLCertificate]="scripts"
[installSwapfile]="scripts"
[installTraefik]="containers"
[installTrilium]="containers"
[installUFW]="scripts"
[installUFWDocker]="scripts"
[installUnbound]="containers"
[installVaultwarden]="containers"
[installWireguard]="containers"
[_invidiousBcrypt]="containers"
[_invidiousPsql]="containers"
[invidiousToolsMenu]="scripts"
@ -1409,6 +1394,9 @@ declare -gA LP_FN_ROOT=(
[isQuestion]="scripts"
[isSetupWizardComplete]="scripts"
[isSuccessful]="scripts"
[jitsimeet_install_post_compose]="containers"
[jitsimeet_install_post_setup]="containers"
[jitsimeet_install_post_start]="containers"
[kopiaBackupAppToLocation]="scripts"
[kopiaBackupSystemToLocation]="scripts"
[kopiaCheckLocation]="scripts"
@ -1488,6 +1476,8 @@ declare -gA LP_FN_ROOT=(
[migrateRunHook]="scripts"
[migrateSystem]="scripts"
[migrateUrlRewriteEnabled]="scripts"
[moneyapp_install_post_compose]="containers"
[moneyapp_install_pre]="containers"
[monitoringAppEnabled]="scripts"
[monitoringInstalledApps]="scripts"
[monitoringIsInstalled]="scripts"
@ -1499,7 +1489,9 @@ declare -gA LP_FN_ROOT=(
[moveFile]="scripts"
[_nextcloudOcc]="containers"
[_nextcloudOccWithPass]="containers"
[onlyoffice_install_message_data]="containers"
[openFifoReader]="scripts"
[owncloud_install_post_compose]="containers"
[passwordValidation]="scripts"
[peerAdd]="scripts"
[peerCheckAll]="scripts"
@ -1550,6 +1542,8 @@ declare -gA LP_FN_ROOT=(
[portStoreMapping]="scripts"
[portUpdateComposeTags]="scripts"
[processBcryptPassword]="scripts"
[prometheus_install_post_compose]="containers"
[prometheus_install_post_start]="containers"
[readTaskField]="scripts"
[reconcileConfigFile]="scripts"
[reconcileContainersTopOwnership]="scripts"
@ -1637,6 +1631,7 @@ declare -gA LP_FN_ROOT=(
[run_task_processor]="scripts"
[scanConfigsForRandomPassword]="scripts"
[scanFileForRandomPasswordKeysUsers]="scripts"
[searxng_install_post_start]="containers"
[setupApply]="scripts"
[setupApplyConfig]="scripts"
[setupApplyFinalize]="scripts"
@ -1688,9 +1683,13 @@ declare -gA LP_FN_ROOT=(
[tailscaleInstallToContainer]="containers"
[toolArgsGet]="scripts"
[toolsMenu]="scripts"
[traefik_install_post_compose]="containers"
[traefik_install_pre]="containers"
[traefikSetupLabelsMiddlewares]="scripts"
[traefikSetupLoginCredentials]="scripts"
[traefikUpdateWhitelist]="scripts"
[trilium_install_post_start]="containers"
[unbound_install_post_compose]="containers"
[uninstallCrowdsec]="containers"
[uninstallDockerRootless]="scripts"
[updateAppConfig]="scripts"
@ -1770,6 +1769,9 @@ declare -gA LP_FN_ROOT=(
[webuiUpdateSystemConfig]="scripts"
[webuiValidateConfigValue]="scripts"
[whitelistPortUpdater]="scripts"
[wireguard_install_post_compose]="containers"
[wireguard_install_post_start]="containers"
[wireguard_install_pre]="containers"
[writeAtomic]="scripts"
[zipFile]="scripts"
)
@ -1798,6 +1800,8 @@ LP_EAGER_FILES=(
# re-invokes. Sourced inline instead of eval-in-loop because bash
# parses one large file faster than it evals snippets at startup.
acquireSingletonLock() { source "${install_scripts_dir}crontab/task/crontab_task_processor.sh"; acquireSingletonLock "$@"; }
adguard_install_message_data() { source "${install_containers_dir}adguard/scripts/adguard_install_hooks.sh"; adguard_install_message_data "$@"; }
adguard_install_post_start() { source "${install_containers_dir}adguard/scripts/adguard_install_hooks.sh"; adguard_install_post_start "$@"; }
adoptDockerSubnet() { source "${install_scripts_dir}checks/requirements/check_docker_network.sh"; adoptDockerSubnet "$@"; }
appAdguardApplyDnsUpdater() { source "${install_containers_dir}adguard/tools/adguard_apply_dns_updater.sh"; appAdguardApplyDnsUpdater "$@"; }
appAdguardResetPassword() { source "${install_containers_dir}adguard/tools/adguard_reset_password.sh"; appAdguardResetPassword "$@"; }
@ -1920,6 +1924,10 @@ authAdapter_nextcloud_listUsers() { source "${install_containers_dir}nextcloud/s
authAdapter_nextcloud_setAdmin() { source "${install_containers_dir}nextcloud/scripts/nextcloud_auth.sh"; authAdapter_nextcloud_setAdmin "$@"; }
authAdapter_nextcloud_setPassword() { source "${install_containers_dir}nextcloud/scripts/nextcloud_auth.sh"; authAdapter_nextcloud_setPassword "$@"; }
authAdapter_traefik_setPassword() { source "${install_containers_dir}traefik/scripts/traefik_auth.sh"; authAdapter_traefik_setPassword "$@"; }
authelia_install_post() { source "${install_containers_dir}authelia/scripts/authelia_install_hooks.sh"; authelia_install_post "$@"; }
authelia_install_post_compose() { source "${install_containers_dir}authelia/scripts/authelia_install_hooks.sh"; authelia_install_post_compose "$@"; }
authelia_install_post_start() { source "${install_containers_dir}authelia/scripts/authelia_install_hooks.sh"; authelia_install_post_start "$@"; }
authelia_install_pre() { source "${install_containers_dir}authelia/scripts/authelia_install_hooks.sh"; authelia_install_pre "$@"; }
authPersistCfg() { source "${install_scripts_dir}app/auth_adapter.sh"; authPersistCfg "$@"; }
authToolArg() { source "${install_scripts_dir}app/auth_adapter.sh"; authToolArg "$@"; }
backupAllApps() { source "${install_scripts_dir}backup/app/backup_app_all.sh"; backupAllApps "$@"; }
@ -1969,6 +1977,7 @@ backupSshKeySet() { source "${install_scripts_dir}backup/locations/location_ssh.
backupSystemConfig() { source "${install_scripts_dir}backup/system/backup_system.sh"; backupSystemConfig "$@"; }
backupVerifySnapshot() { source "${install_scripts_dir}backup/verify/backup_verify.sh"; backupVerifySnapshot "$@"; }
_bookstackArtisan() { source "${install_containers_dir}bookstack/scripts/bookstack_auth.sh"; _bookstackArtisan "$@"; }
bookstack_install_post_start() { source "${install_containers_dir}bookstack/scripts/bookstack_install_hooks.sh"; bookstack_install_post_start "$@"; }
borgArchiveName() { source "${install_scripts_dir}backup/engine/borg_env.sh"; borgArchiveName "$@"; }
borgBackupAppToLocation() { source "${install_scripts_dir}backup/engine/borg_backup.sh"; borgBackupAppToLocation "$@"; }
borgBackupSystemToLocation() { source "${install_scripts_dir}backup/engine/borg_backup.sh"; borgBackupSystemToLocation "$@"; }
@ -2209,15 +2218,20 @@ gitCheckForUpdate() { source "${install_scripts_dir}update/git/checks/update_git
gitCheckGitDetails() { source "${install_scripts_dir}update/git/check_git_details.sh"; gitCheckGitDetails "$@"; }
gitCleanInstallBackups() { source "${install_scripts_dir}update/backup/install_git_backup.sh"; gitCleanInstallBackups "$@"; }
_giteaCmd() { source "${install_containers_dir}gitea/scripts/gitea_auth.sh"; _giteaCmd "$@"; }
gitea_install_post_compose() { source "${install_containers_dir}gitea/scripts/gitea_install_hooks.sh"; gitea_install_post_compose "$@"; }
gitFolderResetAndBackup() { source "${install_scripts_dir}update/backup/reset_git_backup.sh"; gitFolderResetAndBackup "$@"; }
gitPerformUpdate() { source "${install_scripts_dir}update/backup/reset_git_backup.sh"; gitPerformUpdate "$@"; }
gitReset() { source "${install_scripts_dir}update/git/reset_git.sh"; gitReset "$@"; }
gitUntrackFiles() { source "${install_scripts_dir}update/git/untrack_files.sh"; gitUntrackFiles "$@"; }
gitUseExistingBackup() { source "${install_scripts_dir}update/backup/use_git_backup.sh"; gitUseExistingBackup "$@"; }
gluetun_install_post_start() { source "${install_containers_dir}gluetun/scripts/gluetun_install_hooks.sh"; gluetun_install_post_start "$@"; }
gluetunRouteExistingAppsPrompt() { source "${install_containers_dir}gluetun/scripts/gluetun_route_apps.sh"; gluetunRouteExistingAppsPrompt "$@"; }
grafana_install_post_start() { source "${install_containers_dir}grafana/scripts/grafana_install_hooks.sh"; grafana_install_post_start "$@"; }
grafana_install_pre() { source "${install_containers_dir}grafana/scripts/grafana_install_hooks.sh"; grafana_install_pre "$@"; }
hashPassword() { source "${install_scripts_dir}config/password/password_hash.sh"; hashPassword "$@"; }
headscaleCommands() { source "${install_containers_dir}headscale/scripts/headscale_commands.sh"; headscaleCommands "$@"; }
headscaleEditConfig() { source "${install_containers_dir}headscale/scripts/headscale_edit_config.sh"; headscaleEditConfig "$@"; }
headscale_install_post_compose() { source "${install_containers_dir}headscale/scripts/headscale_install_hooks.sh"; headscale_install_post_compose "$@"; }
healthLogError() { source "${install_scripts_dir}crontab/task/crontab_check_processor.sh"; healthLogError "$@"; }
healthLogInfo() { source "${install_scripts_dir}crontab/task/crontab_check_processor.sh"; healthLogInfo "$@"; }
healthLogSuccess() { source "${install_scripts_dir}crontab/task/crontab_check_processor.sh"; healthLogSuccess "$@"; }
@ -2234,15 +2248,11 @@ hostSshRefreshUi() { source "${install_scripts_dir}ssh/host_access.sh"; hostSshR
hostSshSetPasswordAuth() { source "${install_scripts_dir}ssh/host_access.sh"; hostSshSetPasswordAuth "$@"; }
hostSshUser() { source "${install_scripts_dir}ssh/host_access.sh"; hostSshUser "$@"; }
initializeAppVariables() { source "${install_scripts_dir}network/variables/variables_init_app.sh"; initializeAppVariables "$@"; }
installAdguard() { source "${install_containers_dir}adguard/adguard.sh"; installAdguard "$@"; }
installApp() { source "${install_scripts_dir}app/install/app_install.sh"; installApp "$@"; }
installArch() { source "${install_scripts_dir}os/install/arch.sh"; installArch "$@"; }
installAuthelia() { source "${install_containers_dir}authelia/authelia.sh"; installAuthelia "$@"; }
installBookstack() { source "${install_containers_dir}bookstack/bookstack.sh"; installBookstack "$@"; }
installCrontab() { source "${install_scripts_dir}crontab/crontab_install.sh"; installCrontab "$@"; }
installCrowdsec() { source "${install_containers_dir}crowdsec/crowdsec.sh"; installCrowdsec "$@"; }
installCrowdsecHost() { source "${install_containers_dir}crowdsec/scripts/crowdsec_install_host.sh"; installCrowdsecHost "$@"; }
installDashy() { source "${install_containers_dir}dashy/dashy.sh"; installDashy "$@"; }
installDebianUbuntu() { source "${install_scripts_dir}os/install/ubuntu.sh"; installDebianUbuntu "$@"; }
installDockerNetwork() { source "${install_scripts_dir}docker/network/network_setup.sh"; installDockerNetwork "$@"; }
installDockerRooted() { source "${install_scripts_dir}docker/install/rooted/rooted_docker.sh"; installDockerRooted "$@"; }
@ -2251,44 +2261,20 @@ installDockerRootedCompose() { source "${install_scripts_dir}docker/install/root
installDockerRootless() { source "${install_scripts_dir}docker/install/rootless/rootless_docker.sh"; installDockerRootless "$@"; }
installDockerRootlessStartSetup() { source "${install_scripts_dir}docker/install/rootless/rootless_start_setup.sh"; installDockerRootlessStartSetup "$@"; }
installDockerRootlessUser() { source "${install_scripts_dir}docker/install/rootless/rootless_user.sh"; installDockerRootlessUser "$@"; }
installFocalboard() { source "${install_containers_dir}focalboard/focalboard.sh"; installFocalboard "$@"; }
installGitea() { source "${install_containers_dir}gitea/gitea.sh"; installGitea "$@"; }
installGluetun() { source "${install_containers_dir}gluetun/gluetun.sh"; installGluetun "$@"; }
installGrafana() { source "${install_containers_dir}grafana/grafana.sh"; installGrafana "$@"; }
installHeadscale() { source "${install_containers_dir}headscale/headscale.sh"; installHeadscale "$@"; }
installInvidious() { source "${install_containers_dir}invidious/invidious.sh"; installInvidious "$@"; }
installIpinfo() { source "${install_containers_dir}ipinfo/ipinfo.sh"; installIpinfo "$@"; }
installJellyfin() { source "${install_containers_dir}jellyfin/jellyfin.sh"; installJellyfin "$@"; }
installJitsimeet() { source "${install_containers_dir}jitsimeet/jitsimeet.sh"; installJitsimeet "$@"; }
installLibrePortal() { source "${install_containers_dir}libreportal/libreportal.sh"; installLibrePortal "$@"; }
installLibrePortalAppWebUI() { source "${install_scripts_dir}webui/webui_install_app.sh"; installLibrePortalAppWebUI "$@"; }
installLibrePortalImageWebUI() { source "${install_scripts_dir}webui/webui_install_image.sh"; installLibrePortalImageWebUI "$@"; }
installLibrePortalWebUITaskService() { source "${install_scripts_dir}webui/webui_install_systemd.sh"; installLibrePortalWebUITaskService "$@"; }
installMastodon() { source "${install_containers_dir}mastodon/mastodon.sh"; installMastodon "$@"; }
installMoneyapp() { source "${install_containers_dir}moneyapp/moneyapp.sh"; installMoneyapp "$@"; }
installNextcloud() { source "${install_containers_dir}nextcloud/nextcloud.sh"; installNextcloud "$@"; }
installOllama() { source "${install_containers_dir}ollama/ollama.sh"; installOllama "$@"; }
installOnlyoffice() { source "${install_containers_dir}onlyoffice/onlyoffice.sh"; installOnlyoffice "$@"; }
installOptionalMetricsApps() { source "${install_scripts_dir}start/start_recommended.sh"; installOptionalMetricsApps "$@"; }
installOwncloud() { source "${install_containers_dir}owncloud/owncloud.sh"; installOwncloud "$@"; }
installPihole() { source "${install_containers_dir}pihole/pihole.sh"; installPihole "$@"; }
installPrometheus() { source "${install_containers_dir}prometheus/prometheus.sh"; installPrometheus "$@"; }
installRecommendedApps() { source "${install_scripts_dir}start/start_recommended.sh"; installRecommendedApps "$@"; }
installResticHost() { source "${install_scripts_dir}install/install_restic.sh"; installResticHost "$@"; }
installResticMigrateLegacyPasswords() { source "${install_scripts_dir}install/install_restic.sh"; installResticMigrateLegacyPasswords "$@"; }
installRootlessApparmorForPasta() { source "${install_scripts_dir}docker/install/rootless/rootless_apparmor.sh"; installRootlessApparmorForPasta "$@"; }
installSearxng() { source "${install_containers_dir}searxng/searxng.sh"; installSearxng "$@"; }
installSpeedtest() { source "${install_containers_dir}speedtest/speedtest.sh"; installSpeedtest "$@"; }
installSQLiteDatabase() { source "${install_scripts_dir}database/install_sqlite.sh"; installSQLiteDatabase "$@"; }
installSSLCertificate() { source "${install_scripts_dir}install/install_certificate.sh"; installSSLCertificate "$@"; }
installSwapfile() { source "${install_scripts_dir}install/install_swapfile.sh"; installSwapfile "$@"; }
installTraefik() { source "${install_containers_dir}traefik/traefik.sh"; installTraefik "$@"; }
installTrilium() { source "${install_containers_dir}trilium/trilium.sh"; installTrilium "$@"; }
installUFW() { source "${install_scripts_dir}install/install_ufw.sh"; installUFW "$@"; }
installUFWDocker() { source "${install_scripts_dir}install/install_ufwd.sh"; installUFWDocker "$@"; }
installUnbound() { source "${install_containers_dir}unbound/unbound.sh"; installUnbound "$@"; }
installVaultwarden() { source "${install_containers_dir}vaultwarden/vaultwarden.sh"; installVaultwarden "$@"; }
installWireguard() { source "${install_containers_dir}wireguard/wireguard.sh"; installWireguard "$@"; }
_invidiousBcrypt() { source "${install_containers_dir}invidious/scripts/invidious_auth.sh"; _invidiousBcrypt "$@"; }
_invidiousPsql() { source "${install_containers_dir}invidious/scripts/invidious_auth.sh"; _invidiousPsql "$@"; }
invidiousToolsMenu() { source "${install_scripts_dir}menu/tools/manage_invidious.sh"; invidiousToolsMenu "$@"; }
@ -2312,6 +2298,9 @@ isOptionMenu() { source "${install_scripts_dir}menu/message/markers.sh"; isOptio
isQuestion() { source "${install_scripts_dir}menu/message/markers.sh"; isQuestion "$@"; }
isSetupWizardComplete() { source "${install_scripts_dir}setup/setup_lock.sh"; isSetupWizardComplete "$@"; }
isSuccessful() { source "${install_scripts_dir}menu/message/markers.sh"; isSuccessful "$@"; }
jitsimeet_install_post_compose() { source "${install_containers_dir}jitsimeet/scripts/jitsimeet_install_hooks.sh"; jitsimeet_install_post_compose "$@"; }
jitsimeet_install_post_setup() { source "${install_containers_dir}jitsimeet/scripts/jitsimeet_install_hooks.sh"; jitsimeet_install_post_setup "$@"; }
jitsimeet_install_post_start() { source "${install_containers_dir}jitsimeet/scripts/jitsimeet_install_hooks.sh"; jitsimeet_install_post_start "$@"; }
kopiaBackupAppToLocation() { source "${install_scripts_dir}backup/engine/kopia_backup.sh"; kopiaBackupAppToLocation "$@"; }
kopiaBackupSystemToLocation() { source "${install_scripts_dir}backup/engine/kopia_backup.sh"; kopiaBackupSystemToLocation "$@"; }
kopiaCheckLocation() { source "${install_scripts_dir}backup/engine/kopia_check.sh"; kopiaCheckLocation "$@"; }
@ -2391,6 +2380,8 @@ _migrateResolveLocation() { source "${install_scripts_dir}migrate/migrate_discov
migrateRunHook() { source "${install_scripts_dir}migrate/migrate_hooks.sh"; migrateRunHook "$@"; }
migrateSystem() { source "${install_scripts_dir}migrate/migrate_apply.sh"; migrateSystem "$@"; }
migrateUrlRewriteEnabled() { source "${install_scripts_dir}migrate/migrate_url_rewrite.sh"; migrateUrlRewriteEnabled "$@"; }
moneyapp_install_post_compose() { source "${install_containers_dir}moneyapp/scripts/moneyapp_install_hooks.sh"; moneyapp_install_post_compose "$@"; }
moneyapp_install_pre() { source "${install_containers_dir}moneyapp/scripts/moneyapp_install_hooks.sh"; moneyapp_install_pre "$@"; }
monitoringAppEnabled() { source "${install_scripts_dir}network/monitoring/monitoring.sh"; monitoringAppEnabled "$@"; }
monitoringInstalledApps() { source "${install_scripts_dir}network/monitoring/monitoring.sh"; monitoringInstalledApps "$@"; }
monitoringIsInstalled() { source "${install_scripts_dir}network/monitoring/monitoring.sh"; monitoringIsInstalled "$@"; }
@ -2402,7 +2393,9 @@ monitoringToggleAppConfig() { source "${install_scripts_dir}network/monitoring/m
moveFile() { source "${install_scripts_dir}function/file/move_file.sh"; moveFile "$@"; }
_nextcloudOcc() { source "${install_containers_dir}nextcloud/scripts/nextcloud_auth.sh"; _nextcloudOcc "$@"; }
_nextcloudOccWithPass() { source "${install_containers_dir}nextcloud/scripts/nextcloud_auth.sh"; _nextcloudOccWithPass "$@"; }
onlyoffice_install_message_data() { source "${install_containers_dir}onlyoffice/scripts/onlyoffice_install_hooks.sh"; onlyoffice_install_message_data "$@"; }
openFifoReader() { source "${install_scripts_dir}crontab/task/crontab_task_processor.sh"; openFifoReader "$@"; }
owncloud_install_post_compose() { source "${install_containers_dir}owncloud/scripts/owncloud_install_hooks.sh"; owncloud_install_post_compose "$@"; }
passwordValidation() { source "${install_scripts_dir}function/validation/password.sh"; passwordValidation "$@"; }
peerAdd() { source "${install_scripts_dir}peer/peer_add.sh"; peerAdd "$@"; }
peerCheckAll() { source "${install_scripts_dir}peer/peer_check.sh"; peerCheckAll "$@"; }
@ -2453,6 +2446,8 @@ portsRemoveFromDatabase() { source "${install_scripts_dir}network/ports/core/por
portStoreMapping() { source "${install_scripts_dir}network/ports/allocation/port_store_mapping.sh"; portStoreMapping "$@"; }
portUpdateComposeTags() { source "${install_scripts_dir}network/ports/allocation/port_update_compose_tags.sh"; portUpdateComposeTags "$@"; }
processBcryptPassword() { source "${install_scripts_dir}config/password/bcrypt/password_process_bcrypt.sh"; processBcryptPassword "$@"; }
prometheus_install_post_compose() { source "${install_containers_dir}prometheus/scripts/prometheus_install_hooks.sh"; prometheus_install_post_compose "$@"; }
prometheus_install_post_start() { source "${install_containers_dir}prometheus/scripts/prometheus_install_hooks.sh"; prometheus_install_post_start "$@"; }
readTaskField() { source "${install_scripts_dir}crontab/task/crontab_task_processor.sh"; readTaskField "$@"; }
reconcileConfigFile() { source "${install_scripts_dir}config/core/variables/config_scan_variables.sh"; reconcileConfigFile "$@"; }
reconcileContainersTopOwnership() { source "${install_scripts_dir}function/permission/libreportal_folders.sh"; reconcileContainersTopOwnership "$@"; }
@ -2540,6 +2535,7 @@ runTask() { source "${install_scripts_dir}crontab/task/crontab_task_processor.sh
run_task_processor() { source "${install_scripts_dir}crontab/task/crontab_task_processor.sh"; run_task_processor "$@"; }
scanConfigsForRandomPassword() { source "${install_scripts_dir}config/password/password_update_all.sh"; scanConfigsForRandomPassword "$@"; }
scanFileForRandomPasswordKeysUsers() { source "${install_scripts_dir}config/password/password_scan_file.sh"; scanFileForRandomPasswordKeysUsers "$@"; }
searxng_install_post_start() { source "${install_containers_dir}searxng/scripts/searxng_install_hooks.sh"; searxng_install_post_start "$@"; }
setupApply() { source "${install_scripts_dir}setup/setup_apply.sh"; setupApply "$@"; }
setupApplyConfig() { source "${install_scripts_dir}setup/setup_apply.sh"; setupApplyConfig "$@"; }
setupApplyFinalize() { source "${install_scripts_dir}setup/setup_apply.sh"; setupApplyFinalize "$@"; }
@ -2591,9 +2587,13 @@ tagsProcessorTrustedDomains() { source "${install_scripts_dir}config/tags/proces
tailscaleInstallToContainer() { source "${install_containers_dir}headscale/scripts/tailscale_install.sh"; tailscaleInstallToContainer "$@"; }
toolArgsGet() { source "${install_scripts_dir}docker/app/functions/function_app_tool.sh"; toolArgsGet "$@"; }
toolsMenu() { source "${install_scripts_dir}menu/tools/manage_main.sh"; toolsMenu "$@"; }
traefik_install_post_compose() { source "${install_containers_dir}traefik/scripts/traefik_install_hooks.sh"; traefik_install_post_compose "$@"; }
traefik_install_pre() { source "${install_containers_dir}traefik/scripts/traefik_install_hooks.sh"; traefik_install_pre "$@"; }
traefikSetupLabelsMiddlewares() { source "${install_scripts_dir}network/traefik/traefik_middlewares.sh"; traefikSetupLabelsMiddlewares "$@"; }
traefikSetupLoginCredentials() { source "${install_scripts_dir}network/traefik/traefik_login_credentials.sh"; traefikSetupLoginCredentials "$@"; }
traefikUpdateWhitelist() { source "${install_scripts_dir}network/traefik/traefik_whitelist.sh"; traefikUpdateWhitelist "$@"; }
trilium_install_post_start() { source "${install_containers_dir}trilium/scripts/trilium_install_hooks.sh"; trilium_install_post_start "$@"; }
unbound_install_post_compose() { source "${install_containers_dir}unbound/scripts/unbound_install_hooks.sh"; unbound_install_post_compose "$@"; }
uninstallCrowdsec() { source "${install_containers_dir}crowdsec/crowdsec.sh"; uninstallCrowdsec "$@"; }
uninstallDockerRootless() { source "${install_scripts_dir}docker/install/rootless/rootless_uninstall.sh"; uninstallDockerRootless "$@"; }
updateAppConfig() { source "${install_scripts_dir}webui/data/generators/apps/webui_app_config.sh"; updateAppConfig "$@"; }
@ -2673,5 +2673,8 @@ webuiUpdateAppStatus() { source "${install_scripts_dir}webui/data/generators/app
webuiUpdateSystemConfig() { source "${install_scripts_dir}webui/data/generators/config/webui_update_config.sh"; webuiUpdateSystemConfig "$@"; }
webuiValidateConfigValue() { source "${install_scripts_dir}webui/data/generators/config/webui_update_config.sh"; webuiValidateConfigValue "$@"; }
whitelistPortUpdater() { source "${install_scripts_dir}docker/whitelist_port_updater.sh"; whitelistPortUpdater "$@"; }
wireguard_install_post_compose() { source "${install_containers_dir}wireguard/scripts/wireguard_install_hooks.sh"; wireguard_install_post_compose "$@"; }
wireguard_install_post_start() { source "${install_containers_dir}wireguard/scripts/wireguard_install_hooks.sh"; wireguard_install_post_start "$@"; }
wireguard_install_pre() { source "${install_containers_dir}wireguard/scripts/wireguard_install_hooks.sh"; wireguard_install_pre "$@"; }
writeAtomic() { source "${install_scripts_dir}crontab/task/crontab_task_processor.sh"; writeAtomic "$@"; }
zipFile() { source "${install_scripts_dir}function/file/zip_file.sh"; zipFile "$@"; }