From 68110d199c63348af2c42b68bc933c5142f7200c Mon Sep 17 00:00:00 2001 From: librelad Date: Sun, 24 May 2026 00:12:06 +0100 Subject: [PATCH] fix(rootless): slirp4netns default, manager-vs-container helper split, sysctl path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reinstall test on Debian 12 surfaced three rootless-only breakages (rooted was byte-identical/fine): 1. pasta blocked by Debian's passt AppArmor profile (DENIED ptrace read -> can't open container netns -> rootless dockerd never starts). Default CFG_ROOTLESS_NET back to slirp4netns (reliable); pasta stays selectable for hosts that relax the profile. 2. de-sudo mis-assigned helpers by owner. /docker management layer (apps DB chowned to libreportal by install_sqlite, /docker/logs) is MANAGER-owned, not dockerinstall. Add runInstallWrite; move apps-DB sqlite3 -> runInstallOp and /docker/logs appends -> runInstallWrite. Revert ownership-SETUP scripts (libreportal_folders, app_folder) to runSystem — they must run as root to establish ownership during install. Container files (/docker/containers/) stay runFileOp. 3. kernel hardening sysctls written to /etc/sysctl/99-custom.conf, which 'sysctl --system' does not read -> never applied. Write them to /etc/sysctl.d/99-libreportal-hardening.conf instead. Co-Authored-By: Claude Opus 4.7 Signed-off-by: librelad --- configs/network/network_rootless | 2 +- containers/authelia/authelia.sh | 4 +- containers/headscale/headscale.sh | 2 +- containers/prometheus/prometheus.sh | 2 +- containers/unbound/unbound.sh | 2 +- .../docker/docker_config_to_container.sh | 6 +-- .../processors/tags_processor_network_mode.sh | 4 +- scripts/database/app/db_app_scan.sh | 10 ++--- scripts/database/app/db_list_installed_app.sh | 12 +++--- scripts/docker/command/run_privileged.sh | 35 ++++++++++++++---- scripts/docker/compose/setup_compose_yml.sh | 2 +- .../install/rootless/rootless_docker.sh | 37 +++++++------------ scripts/function/checks/check_success.sh | 14 +++---- scripts/function/permission/app_folder.sh | 10 ++--- .../permission/libreportal_folders.sh | 8 ++-- .../headscale/tailscale/tailscale_install.sh | 2 +- scripts/network/monitoring/monitoring.sh | 4 +- .../ports/allocation/port_store_mapping.sh | 10 ++--- .../allocation/port_update_compose_tags.sh | 12 +++--- 19 files changed, 95 insertions(+), 83 deletions(-) diff --git a/configs/network/network_rootless b/configs/network/network_rootless index 6c99cec..5067a20 100644 --- a/configs/network/network_rootless +++ b/configs/network/network_rootless @@ -2,4 +2,4 @@ # Rootless Networking - Network stack and behaviour for rootless Docker **ADVANCED** # ================================================================================ -CFG_ROOTLESS_NET=pasta # Rootless Network Driver - Network stack for rootless Docker; pasta (default): faster and preserves the real client source IP; slirp4netns: legacy fallback if pasta misbehaves. The matching rootlesskit port driver is selected automatically. **ADVANCED** [pasta:Pasta (recommended)|slirp4netns:slirp4netns (fallback)] +CFG_ROOTLESS_NET=slirp4netns # Rootless Network Driver - Network stack for rootless Docker; slirp4netns (default): reliable everywhere; pasta: faster and preserves the real client source IP BUT on Debian the shipped passt AppArmor profile denies the ptrace it needs to open the container netns, so the daemon won't start unless that profile is relaxed. The matching rootlesskit port driver is selected automatically. **ADVANCED** [slirp4netns:slirp4netns (default, reliable)|pasta:Pasta (faster, needs AppArmor override)] diff --git a/containers/authelia/authelia.sh b/containers/authelia/authelia.sh index 8ab7146..e21bfdc 100755 --- a/containers/authelia/authelia.sh +++ b/containers/authelia/authelia.sh @@ -60,10 +60,10 @@ installAuthelia() dockerComposeSetupFile $app_name; - local result=$(copyResource "$app_name" "configuration.yml" "config" | runFileWrite -a "$logs_dir/$docker_log_file" 2>&1) + 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" | runFileWrite -a "$logs_dir/$docker_log_file" 2>&1) + 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" diff --git a/containers/headscale/headscale.sh b/containers/headscale/headscale.sh index fbcdd79..f7f911a 100755 --- a/containers/headscale/headscale.sh +++ b/containers/headscale/headscale.sh @@ -54,7 +54,7 @@ installHeadscale() local result=$(createFolders "loud" $docker_install_user $containers_dir$app_name/config) checkSuccess "Create config folder" - local result=$(copyResource "$app_name" "config.yaml" "config" | runFileWrite -a "$logs_dir/$docker_log_file" 2>&1) + 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"; diff --git a/containers/prometheus/prometheus.sh b/containers/prometheus/prometheus.sh index 8e4c4f7..0a34ef1 100755 --- a/containers/prometheus/prometheus.sh +++ b/containers/prometheus/prometheus.sh @@ -57,7 +57,7 @@ installPrometheus() 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" | runFileWrite -a "$logs_dir/$docker_log_file" 2>&1) + 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++)) diff --git a/containers/unbound/unbound.sh b/containers/unbound/unbound.sh index 4cfef9a..2adb113 100755 --- a/containers/unbound/unbound.sh +++ b/containers/unbound/unbound.sh @@ -53,7 +53,7 @@ installUnbound() monitoringToggleAppConfig "$app_name" "docker-compose.yml"; - local result=$(copyResource "$app_name" "unbound.conf" "etc" | runFileWrite -a "$logs_dir/$docker_log_file" 2>&1) + 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"; diff --git a/scripts/config/docker/docker_config_to_container.sh b/scripts/config/docker/docker_config_to_container.sh index 717332e..7f78715 100755 --- a/scripts/config/docker/docker_config_to_container.sh +++ b/scripts/config/docker/docker_config_to_container.sh @@ -44,7 +44,7 @@ dockerConfigSetupToContainer() if [ "$silent_flag" == "loud" ]; then isNotice "Copying config file to '$target_path/$config_file'..." fi - copyFile "$silent_flag" "$source_file" "$target_path/$config_file" $sudo_user_name | runFileWrite -a "$logs_dir/$docker_log_file" 2>&1 + copyFile "$silent_flag" "$source_file" "$target_path/$config_file" $sudo_user_name | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1 fi if [[ -n "$config_overrides" ]]; then @@ -124,7 +124,7 @@ dockerConfigSetupToContainer() case $resetconfigaccept in [yY]) isNotice "Resetting $app_name config file." - copyFile "loud" "$source_file" "$target_path/$config_file" $docker_install_user | runFileWrite -a "$logs_dir/$docker_log_file" 2>&1 + copyFile "loud" "$source_file" "$target_path/$config_file" $docker_install_user | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1 source $target_path/$config_file dockerConfigSetupToContainer "loud" $app_name; while true; do @@ -204,7 +204,7 @@ dockerConfigSetupToContainer() fi else isNotice "Config file for $app_name does not exist. Creating it..." - copyFile "loud" "$source_file" "$target_path/$config_file" $docker_install_user | runFileWrite -a "$logs_dir/$docker_log_file" 2>&1 + copyFile "loud" "$source_file" "$target_path/$config_file" $docker_install_user | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1 isNotice "Config file for $app_name contains no edits." while true; do #isQuestion "Would you like to make edits to the config file? (y/n): " diff --git a/scripts/config/tags/processors/tags_processor_network_mode.sh b/scripts/config/tags/processors/tags_processor_network_mode.sh index 179787b..45b8865 100644 --- a/scripts/config/tags/processors/tags_processor_network_mode.sh +++ b/scripts/config/tags/processors/tags_processor_network_mode.sh @@ -62,7 +62,7 @@ tagsProcessorGluetunForwardedPorts() if [[ ! -f "$docker_dir/$db_file" ]]; then return 0; fi local installed_apps - installed_apps=$(runFileOp sqlite3 "$docker_dir/$db_file" \ + installed_apps=$(runInstallOp sqlite3 "$docker_dir/$db_file" \ "SELECT name FROM apps WHERE status = 1 ORDER BY name;" 2>/dev/null) local routed_lines="" @@ -75,7 +75,7 @@ tagsProcessorGluetunForwardedPorts() [[ "$net" != "gluetun" ]] && continue local ports - ports=$(runFileOp sqlite3 "$docker_dir/$db_file" \ + ports=$(runInstallOp sqlite3 "$docker_dir/$db_file" \ "SELECT resource_value FROM network_resources WHERE app_name = '$app' AND resource_type = 'port' AND status = 'active';" 2>/dev/null) while IFS= read -r p; do [[ -z "$p" ]] && continue diff --git a/scripts/database/app/db_app_scan.sh b/scripts/database/app/db_app_scan.sh index 2d5f0ee..cacd16a 100755 --- a/scripts/database/app/db_app_scan.sh +++ b/scripts/database/app/db_app_scan.sh @@ -31,7 +31,7 @@ databaseAppScan() local updated_count=0 # Get the list of all folder names and statuses from the database - local existing_folders=$(runFileOp sqlite3 "$docker_dir/$db_file" "SELECT name, status, uninstall_date FROM apps;") + local existing_folders=$(runInstallOp sqlite3 "$docker_dir/$db_file" "SELECT name, status, uninstall_date FROM apps;") # Create an array to store existing folder names in the database local existing_folder_names=() @@ -43,7 +43,7 @@ databaseAppScan() if (( status == 0 )); then isNotice "The folder for $folder_name has been found." # Update the database to set the status to 1 (installed) and unset the uninstall_date - local result=$(runFileOp sqlite3 "$docker_dir/$db_file" "UPDATE apps SET status = 1, uninstall_date = NULL WHERE name = '$folder_name';") + local result=$(runInstallOp sqlite3 "$docker_dir/$db_file" "UPDATE apps SET status = 1, uninstall_date = NULL WHERE name = '$folder_name';") checkSuccess "Updating apps database for $folder_name to installed status." ((updated_count++)) # Increment updated_count fi @@ -72,7 +72,7 @@ databaseAppScan() local folder_time=$(echo "$folder_datetime" | awk '{print $2}') # Add the new entry to the database with a default status of 1 (installed) and the extracted or current date - local result=$(runFileOp sqlite3 "$docker_dir/$db_file" "INSERT INTO apps (name, status, install_date, install_time) VALUES ('$app_name', 1, '$folder_date', '$folder_time');") + local result=$(runInstallOp sqlite3 "$docker_dir/$db_file" "INSERT INTO apps (name, status, install_date, install_time) VALUES ('$app_name', 1, '$folder_date', '$folder_time');") checkSuccess "Adding $app_name to the apps database." ((updated_count++)) # Increment updated_count fi @@ -97,7 +97,7 @@ databaseAppScan() isNotice "Folder $folder_name no longer exists. Removing from the Database." # Delete the entry from the apps table - local result=$(runFileOp sqlite3 "$docker_dir/$db_file" "DELETE FROM apps WHERE name = '$app_name';") + local result=$(runInstallOp sqlite3 "$docker_dir/$db_file" "DELETE FROM apps WHERE name = '$app_name';") checkSuccess "Removing $app_name from the apps database." portsRemoveFromDatabase $app_name; @@ -196,7 +196,7 @@ databaseAppScan() else # If the folder doesn't exist in the directory, uninstall it from the database isNotice "Folder $folder_name does not exist. Removing from the Database." - local result=$(runFileOp sqlite3 "$docker_dir/$db_file" "DELETE FROM apps WHERE name = '$folder_name';") + local result=$(runInstallOp sqlite3 "$docker_dir/$db_file" "DELETE FROM apps WHERE name = '$folder_name';") checkSuccess "Removing $folder_name from the apps database." ((updated_count++)) # Increment updated_count fi diff --git a/scripts/database/app/db_list_installed_app.sh b/scripts/database/app/db_list_installed_app.sh index cbe50f3..d270eb2 100755 --- a/scripts/database/app/db_list_installed_app.sh +++ b/scripts/database/app/db_list_installed_app.sh @@ -17,16 +17,16 @@ databaseListInstalledApp() isNotice "Database file not found. Make sure it's installed." else # Check if app exists and is installed - local app_check=$(runFileOp sqlite3 "$docker_dir/$db_file" "SELECT name FROM apps WHERE name = '$app_name' AND status = 1;") + local app_check=$(runInstallOp sqlite3 "$docker_dir/$db_file" "SELECT name FROM apps WHERE name = '$app_name' AND status = 1;") if [ -z "$app_check" ]; then isNotice "App '$app_name' not found or not installed." else - local app_details=$(runFileOp sqlite3 "$docker_dir/$db_file" "SELECT install_date, install_time FROM apps WHERE name = '$app_name';") + local app_details=$(runInstallOp sqlite3 "$docker_dir/$db_file" "SELECT install_date, install_time FROM apps WHERE name = '$app_name';") printf "\e[33m📦 %s\e[0m (Installed: %s)\n" "$app_name" "$app_details" # Get all Docker services with IPs for this app - local docker_services=$(runFileOp sqlite3 "$docker_dir/$db_file" "SELECT DISTINCT service_name, resource_value FROM network_resources WHERE app_name = '$app_name' AND resource_type = 'ip' AND status = 'active' ORDER BY service_name;" 2>/dev/null) + local docker_services=$(runInstallOp sqlite3 "$docker_dir/$db_file" "SELECT DISTINCT service_name, resource_value FROM network_resources WHERE app_name = '$app_name' AND resource_type = 'ip' AND status = 'active' ORDER BY service_name;" 2>/dev/null) if [[ -n "$docker_services" ]]; then local service_count=0 @@ -44,7 +44,7 @@ databaseListInstalledApp() printf "%s \e[94m🔌 Service:\e[0m %s (IP: %s)\n" "$connector" "$docker_service_name" "$docker_service_ip" # Get all ports for this Docker service - local service_ports=$(runFileOp sqlite3 "$docker_dir/$db_file" "SELECT service_name, resource_value FROM network_resources WHERE app_name = '$app_name' AND resource_type = 'port' AND parent_service = '$docker_service_name' AND status = 'active' ORDER BY service_name;" 2>/dev/null) + local service_ports=$(runInstallOp sqlite3 "$docker_dir/$db_file" "SELECT service_name, resource_value FROM network_resources WHERE app_name = '$app_name' AND resource_type = 'port' AND parent_service = '$docker_service_name' AND status = 'active' ORDER BY service_name;" 2>/dev/null) if [[ -n "$service_ports" ]]; then local port_count=0 @@ -97,7 +97,7 @@ databaseListInstalledApp() fi # Check if Traefik is installed - local traefik_installed=$(runFileOp sqlite3 "$docker_dir/$db_file" "SELECT name FROM apps WHERE name = 'traefik' AND status = 1;" 2>/dev/null) + local traefik_installed=$(runInstallOp sqlite3 "$docker_dir/$db_file" "SELECT name FROM apps WHERE name = 'traefik' AND status = 1;" 2>/dev/null) # Per-port URL path: 10th column of the matching # CFG__PORT_N row in the deployed config. Find the @@ -137,7 +137,7 @@ databaseListInstalledApp() local _domain="" if [[ -n "$traefik_installed" ]]; then - _domain=$(runFileOp sqlite3 "$docker_dir/$db_file" "SELECT resource_value FROM options WHERE option = 'domain_${app_name^^}_DOMAIN';" 2>/dev/null) + _domain=$(runInstallOp sqlite3 "$docker_dir/$db_file" "SELECT resource_value FROM options WHERE option = 'domain_${app_name^^}_DOMAIN';" 2>/dev/null) fi local _path_idx _p diff --git a/scripts/docker/command/run_privileged.sh b/scripts/docker/command/run_privileged.sh index 30f2bf5..5b4836b 100644 --- a/scripts/docker/command/run_privileged.sh +++ b/scripts/docker/command/run_privileged.sh @@ -51,13 +51,15 @@ runSystem() { sudo "$@" } -# Op on the manager install dir / shipped templates — the LibrePortal clone and -# its container templates, owned by the manager user that runs the runtime. -# rooted -> sudo (install tree is root-owned; byte-identical) -# rootless -> (the manager user already owns it — no privilege) -# For copies that read the install tree and write into /docker (two different -# owners in rootless), don't use this for the whole copy — read here and pipe -# into runFileWrite so each side runs as the correct owner. +# Op on a MANAGER-owned path — the LibrePortal clone + shipped templates AND the +# /docker management layer the runtime owns (apps DB, configs/, logs/, scripts). +# In rootless these are owned by the manager user; ops on them need no privilege. +# rooted -> sudo (root-owned; byte-identical) +# rootless -> (runs as the current user: root at install-time, +# the manager user at runtime — both can access) +# Container-owned data under /docker/containers// is NOT this — use runFileOp. +# For copies that read manager files and write container-owned ones, read here +# and pipe into runFileWrite so each side runs as the correct owner. runInstallOp() { if [[ "$CFG_DOCKER_INSTALL_TYPE" == "rootless" ]]; then "$@" @@ -65,3 +67,22 @@ runInstallOp() { sudo "$@" fi } + +# Write stdin to a MANAGER-owned path (apps DB sidecars, configs/, logs/ — e.g. +# the /docker/logs log-append idiom). Mirror of runFileWrite for the manager +# owner. Pass -a/--append as the first arg to append. +# rooted -> sudo tee +# rootless -> tee as the current (manager) user +runInstallWrite() { + local append="" + if [[ "$1" == "-a" || "$1" == "--append" ]]; then + append=" -a" + shift + fi + local dest="$1" + if [[ "$CFG_DOCKER_INSTALL_TYPE" == "rootless" ]]; then + tee$append "$dest" >/dev/null + else + sudo tee$append "$dest" >/dev/null + fi +} diff --git a/scripts/docker/compose/setup_compose_yml.sh b/scripts/docker/compose/setup_compose_yml.sh index 9b082b1..8b462f2 100755 --- a/scripts/docker/compose/setup_compose_yml.sh +++ b/scripts/docker/compose/setup_compose_yml.sh @@ -40,7 +40,7 @@ dockerComposeSetupFile() isError "The source file '$source_file' does not exist." fi - copyFile "loud" "$source_file" "$target_file" $docker_install_user | runFileWrite -a "$logs_dir/$docker_log_file" 2>&1 + copyFile "loud" "$source_file" "$target_file" $docker_install_user | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1 if [ $? -ne 0 ]; then isError "Failed to copy the source file to '$target_path'. Check '$docker_log_file' for more details." diff --git a/scripts/docker/install/rootless/rootless_docker.sh b/scripts/docker/install/rootless/rootless_docker.sh index a44cb29..f4501b9 100755 --- a/scripts/docker/install/rootless/rootless_docker.sh +++ b/scripts/docker/install/rootless/rootless_docker.sh @@ -212,29 +212,20 @@ EOL" # Enabling unprivileged user namespaces (needed for rootless) widens the # kernel attack surface reachable by unprivileged users. Offset that by # closing the surfaces that local-privilege-escalation chains lean on: - # kptr_restrict hides kernel pointers (defeats info-leak primitives), - # ptrace_scope blocks cross-process ptrace (limits credential theft after - # a compromise), and bpf_jit_harden hardens the JIT against spraying. - # All three are distro-portable and have negligible runtime impact. - if ! grep -qF "# LIBREPORTAL KERNEL HARDENING START" "$sysctl"; then - - local result=$(echo '# LIBREPORTAL KERNEL HARDENING START' | sudo tee -a "$sysctl" > /dev/null) - checkSuccess "Adding kernel hardening header to sysctl" - - local result=$(echo 'kernel.kptr_restrict=2' | sudo tee -a "$sysctl" > /dev/null) - checkSuccess "Restricting kernel pointer exposure (kptr_restrict)" - - local result=$(echo 'kernel.yama.ptrace_scope=1' | sudo tee -a "$sysctl" > /dev/null) - checkSuccess "Restricting cross-process ptrace (yama.ptrace_scope)" - - local result=$(echo 'net.core.bpf_jit_harden=2' | sudo tee -a "$sysctl" > /dev/null) - checkSuccess "Hardening the BPF JIT (bpf_jit_harden)" - - local result=$(echo '# LIBREPORTAL KERNEL HARDENING END' | sudo tee -a "$sysctl" > /dev/null) - checkSuccess "Adding kernel hardening end to sysctl" - - isSuccessful "Applied kernel LPE-surface hardening" - fi + # kptr_restrict hides kernel pointers (info-leak primitives), ptrace_scope + # blocks cross-process ptrace (credential theft post-compromise), and + # bpf_jit_harden hardens the JIT against spraying. Written under + # /etc/sysctl.d/ so `sysctl --system` actually loads it — LibrePortal's + # own $sysctl path (/etc/sysctl/…) is non-standard and is NOT read by + # `sysctl --system`. + local hardening_conf="/etc/sysctl.d/99-libreportal-hardening.conf" + sudo bash -c "cat > '$hardening_conf'" <<'EOL' +# LibrePortal kernel LPE-surface hardening (paired with rootless unprivileged userns) +kernel.kptr_restrict=2 +kernel.yama.ptrace_scope=1 +net.core.bpf_jit_harden=2 +EOL + checkSuccess "Writing kernel LPE-surface hardening to $hardening_conf" local result=$(sudo sysctl --system) checkSuccess "Applying changes to sysctl" diff --git a/scripts/function/checks/check_success.sh b/scripts/function/checks/check_success.sh index 5810aec..0accb5e 100755 --- a/scripts/function/checks/check_success.sh +++ b/scripts/function/checks/check_success.sh @@ -5,7 +5,7 @@ function checkSuccess() if [ $? -eq 0 ]; then isSuccessful "$1" if [ -f "$logs_dir/$docker_log_file" ]; then - echo "✓ Success $1" | runFileWrite -a "$logs_dir/$docker_log_file" >/dev/null + echo "✓ Success $1" | runInstallWrite -a "$logs_dir/$docker_log_file" >/dev/null fi else isError "$1" @@ -14,8 +14,8 @@ function checkSuccess() # blocking on read. if [[ "$LIBREPORTAL_NONINTERACTIVE" == "1" ]] || [ ! -t 0 ]; then if [ -f "$logs_dir/$docker_log_file" ]; then - isError " $1" | runFileWrite -a "$logs_dir/$docker_log_file" >/dev/null - echo "===================================" | runFileWrite -a "$logs_dir/$docker_log_file" >/dev/null + isError " $1" | runInstallWrite -a "$logs_dir/$docker_log_file" >/dev/null + echo "===================================" | runInstallWrite -a "$logs_dir/$docker_log_file" >/dev/null fi isNotice "Non-interactive mode: aborting on error." exit 1 @@ -36,15 +36,15 @@ function checkSuccess() if [[ "$error_occurred" == [xX] ]]; then # Log the error output to the log file - isError " $1" | runFileWrite -a "$logs_dir/$docker_log_file" - echo "===================================" | runFileWrite -a "$logs_dir/$docker_log_file" + isError " $1" | runInstallWrite -a "$logs_dir/$docker_log_file" + echo "===================================" | runInstallWrite -a "$logs_dir/$docker_log_file" exit 1 # Exit the script with a non-zero status to stop the current action fi if [[ "$error_occurred" == [mM] ]]; then # Log the error output to the log file - isError " $1" | runFileWrite -a "$logs_dir/$docker_log_file" - echo "===================================" | runFileWrite -a "$logs_dir/$docker_log_file" + isError " $1" | runInstallWrite -a "$logs_dir/$docker_log_file" + echo "===================================" | runInstallWrite -a "$logs_dir/$docker_log_file" if [[ "$initial_command2" == "terminal" ]]; then resetToMenu; fi diff --git a/scripts/function/permission/app_folder.sh b/scripts/function/permission/app_folder.sh index a808bae..00e1553 100755 --- a/scripts/function/permission/app_folder.sh +++ b/scripts/function/permission/app_folder.sh @@ -18,7 +18,7 @@ fixAppFolderPermissions() # Updating $containers_dir with execute permissions if [ -d "$containers_dir" ]; then - local result=$(runFileOp chmod +x "$containers_dir" > /dev/null 2>&1) + local result=$(runSystem chmod +x "$containers_dir" > /dev/null 2>&1) if [ "$silent_flag" == "loud" ]; then checkSuccess "Updating $containers_dir with execute permissions." fi @@ -30,7 +30,7 @@ fixAppFolderPermissions() # Updating $containers_dir$app_name with execute permissions if [ -d "$containers_dir$app_name" ]; then - local result=$(runFileOp chmod +x "$containers_dir$app_name" > /dev/null 2>&1) + local result=$(runSystem chmod +x "$containers_dir$app_name" > /dev/null 2>&1) if [ "$silent_flag" == "loud" ]; then checkSuccess "Updating $containers_dir$app_name with execute permissions." fi @@ -42,7 +42,7 @@ fixAppFolderPermissions() # Updating $app_name with read permissions if [ -d "$containers_dir$app_name" ]; then - local result=$(runFileOp chmod o+r "$containers_dir$app_name") + local result=$(runSystem chmod o+r "$containers_dir$app_name") if [ "$silent_flag" == "loud" ]; then checkSuccess "Updating $app_name with read permissions" fi @@ -54,7 +54,7 @@ fixAppFolderPermissions() # Updating compose file(s) for LibrePortal access if [ -d "$containers_dir$app_name" ]; then - local result=$(runFileOp find "$containers_dir$app_name" -type f -name '*docker-compose*' -exec chmod o+r {} \;) + local result=$(runSystem find "$containers_dir$app_name" -type f -name '*docker-compose*' -exec chmod o+r {} \;) if [ "$silent_flag" == "loud" ]; then isNotice "Updating compose file(s) for LibrePortal access" fi @@ -70,7 +70,7 @@ fixAppFolderPermissions() local file_path="$containers_dir$app_name/$file" # Check if the file exists if [ -e "$file_path" ]; then - local result=$(runFileOp chown $docker_install_user:$docker_install_user "$file_path") + local result=$(runSystem chown $docker_install_user:$docker_install_user "$file_path") if [ "$silent_flag" == "loud" ]; then checkSuccess "Updating $file with $docker_install_user ownership" fi diff --git a/scripts/function/permission/libreportal_folders.sh b/scripts/function/permission/libreportal_folders.sh index d2b7f34..800d597 100755 --- a/scripts/function/permission/libreportal_folders.sh +++ b/scripts/function/permission/libreportal_folders.sh @@ -5,23 +5,23 @@ fixFolderPermissions() local silent_flag="$1" local app_name="$2" - local result=$(runFileOp chmod +x "$docker_dir" > /dev/null 2>&1) + local result=$(runSystem chmod +x "$docker_dir" > /dev/null 2>&1) if [ "$silent_flag" == "loud" ]; then checkSuccess "Updating $docker_dir with execute permissions." fi - local result=$(runFileOp chmod +x "$containers_dir" > /dev/null 2>&1) + local result=$(runSystem chmod +x "$containers_dir" > /dev/null 2>&1) if [ "$silent_flag" == "loud" ]; then checkSuccess "Updating $containers_dir with execute permissions." fi - local result=$(runFileOp find "$script_dir" "$ssl_dir" "$ssh_dir" "$backup_dir" "$restore_dir" "$migrate_dir" -maxdepth 2 -type d -exec chmod +x {} \;) + local result=$(runSystem find "$script_dir" "$ssl_dir" "$ssh_dir" "$backup_dir" "$restore_dir" "$migrate_dir" -maxdepth 2 -type d -exec chmod +x {} \;) if [ "$silent_flag" == "loud" ]; then checkSuccess "Adding execute permissions for $docker_install_user user" fi # Install user related - local result=$(runFileOp chown $docker_install_user:$docker_install_user "$containers_dir" > /dev/null 2>&1) + local result=$(runSystem chown $docker_install_user:$docker_install_user "$containers_dir" > /dev/null 2>&1) if [ "$silent_flag" == "loud" ]; then checkSuccess "Updating $containers_dir with $docker_install_user ownership" fi diff --git a/scripts/headscale/tailscale/tailscale_install.sh b/scripts/headscale/tailscale/tailscale_install.sh index 02bb6aa..06c39e8 100755 --- a/scripts/headscale/tailscale/tailscale_install.sh +++ b/scripts/headscale/tailscale/tailscale_install.sh @@ -8,7 +8,7 @@ tailscaleInstallToContainer() local result=$(createFolders "loud" $docker_install_user $containers_dir$app_name/tailscale) checkSuccess "Creating Tailscale folder" - copyFile "loud" "${install_scripts_dir}tailscale.sh" "$containers_dir$app_name/tailscale/tailscale.sh" $docker_install_user | runFileWrite -a "$logs_dir/$docker_log_file" 2>&1 + copyFile "loud" "${install_scripts_dir}tailscale.sh" "$containers_dir$app_name/tailscale/tailscale.sh" $docker_install_user | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1 if [[ "$type" != "install" ]]; then dockerComposeRestart $app_name; diff --git a/scripts/network/monitoring/monitoring.sh b/scripts/network/monitoring/monitoring.sh index 3049317..65127b3 100644 --- a/scripts/network/monitoring/monitoring.sh +++ b/scripts/network/monitoring/monitoring.sh @@ -17,7 +17,7 @@ monitoringInstalledApps() { [[ -f "$docker_dir/$db_file" ]] || return 0 - runFileOp sqlite3 "$docker_dir/$db_file" \ + runInstallOp sqlite3 "$docker_dir/$db_file" \ "SELECT name FROM apps WHERE status = 1 ORDER BY name;" 2>/dev/null } @@ -26,7 +26,7 @@ monitoringIsInstalled() { [[ -f "$docker_dir/$db_file" ]] || return 1 local n - n="$(runFileOp sqlite3 "$docker_dir/$db_file" \ + n="$(runInstallOp sqlite3 "$docker_dir/$db_file" \ "SELECT COUNT(*) FROM apps WHERE name = '$1' AND status = 1;" 2>/dev/null)" [[ -n "$n" && "$n" -gt 0 ]] } diff --git a/scripts/network/ports/allocation/port_store_mapping.sh b/scripts/network/ports/allocation/port_store_mapping.sh index 0c1ade1..4557cfd 100755 --- a/scripts/network/ports/allocation/port_store_mapping.sh +++ b/scripts/network/ports/allocation/port_store_mapping.sh @@ -9,23 +9,23 @@ portStoreMapping() local parent_service="$4" # parent Docker service (optional) # Check if ports already exist for this app/service - local existing=$(runFileOp sqlite3 "$docker_dir/$db_file" "SELECT resource_value FROM network_resources WHERE app_name='$app_name' AND resource_type='port' AND service_name='$service_name' AND status='active';" 2>/dev/null) + local existing=$(runInstallOp sqlite3 "$docker_dir/$db_file" "SELECT resource_value FROM network_resources WHERE app_name='$app_name' AND resource_type='port' AND service_name='$service_name' AND status='active';" 2>/dev/null) if [[ -n "$existing" ]]; then # UPDATE existing ports if [[ -n "$parent_service" ]]; then - runFileOp sqlite3 "$docker_dir/$db_file" "UPDATE network_resources SET resource_value='$port_mapping', parent_service='$parent_service', created_time=CURRENT_TIME WHERE app_name='$app_name' AND resource_type='port' AND service_name='$service_name';" 2>/dev/null + runInstallOp sqlite3 "$docker_dir/$db_file" "UPDATE network_resources SET resource_value='$port_mapping', parent_service='$parent_service', created_time=CURRENT_TIME WHERE app_name='$app_name' AND resource_type='port' AND service_name='$service_name';" 2>/dev/null else - runFileOp sqlite3 "$docker_dir/$db_file" "UPDATE network_resources SET resource_value='$port_mapping', created_time=CURRENT_TIME WHERE app_name='$app_name' AND resource_type='port' AND service_name='$service_name';" 2>/dev/null + runInstallOp sqlite3 "$docker_dir/$db_file" "UPDATE network_resources SET resource_value='$port_mapping', created_time=CURRENT_TIME WHERE app_name='$app_name' AND resource_type='port' AND service_name='$service_name';" 2>/dev/null fi isNotice "Updated ports for $app_name/$service_name" #isNotice "Updated ports for $app_name/$service_name: $existing → $port_mapping" else # INSERT new ports if [[ -n "$parent_service" ]]; then - runFileOp sqlite3 "$docker_dir/$db_file" "INSERT INTO network_resources (app_name, resource_type, resource_value, service_name, parent_service, status, created_date, created_time) VALUES ('$app_name', 'port', '$port_mapping', '$service_name', '$parent_service', 'active', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null + runInstallOp sqlite3 "$docker_dir/$db_file" "INSERT INTO network_resources (app_name, resource_type, resource_value, service_name, parent_service, status, created_date, created_time) VALUES ('$app_name', 'port', '$port_mapping', '$service_name', '$parent_service', 'active', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null else - runFileOp sqlite3 "$docker_dir/$db_file" "INSERT INTO network_resources (app_name, resource_type, resource_value, service_name, status, created_date, created_time) VALUES ('$app_name', 'port', '$port_mapping', '$service_name', 'active', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null + runInstallOp sqlite3 "$docker_dir/$db_file" "INSERT INTO network_resources (app_name, resource_type, resource_value, service_name, status, created_date, created_time) VALUES ('$app_name', 'port', '$port_mapping', '$service_name', 'active', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null fi isSuccessful "Allocated port: $port_mapping" fi diff --git a/scripts/network/ports/allocation/port_update_compose_tags.sh b/scripts/network/ports/allocation/port_update_compose_tags.sh index 1f3c02d..0a0d7e7 100755 --- a/scripts/network/ports/allocation/port_update_compose_tags.sh +++ b/scripts/network/ports/allocation/port_update_compose_tags.sh @@ -108,14 +108,14 @@ portUpdateComposeTags() # Only log to database if port is not disabled if [[ "$access_type_for_tag" != "disabled" ]]; then # Log to database - runFileOp sqlite3 "$docker_dir/$db_file" "INSERT OR REPLACE INTO network_resources (app_name, resource_type, resource_value, service_name, status, created_date, created_time) VALUES ('$app_name', 'port_tag_combined', '$combined_port', '$db_service_name', 'active', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null - runFileOp sqlite3 "$docker_dir/$db_file" "INSERT OR REPLACE INTO network_resources (app_name, resource_type, resource_value, service_name, status, created_date, created_time) VALUES ('$app_name', 'port_tag_external', '$port_for_tag', '$db_service_name', 'active', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null - runFileOp sqlite3 "$docker_dir/$db_file" "INSERT OR REPLACE INTO network_resources (app_name, resource_type, resource_value, service_name, status, created_date, created_time) VALUES ('$app_name', 'port_tag_internal', '$internal_port_for_tag', '$db_service_name', 'active', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null - runFileOp sqlite3 "$docker_dir/$db_file" "INSERT OR REPLACE INTO network_resources (app_name, resource_type, resource_value, service_name, status, created_date, created_time) VALUES ('$app_name', 'traefik_managed', '$traefik_managed_for_tag', '$db_service_name', 'active', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null - runFileOp sqlite3 "$docker_dir/$db_file" "INSERT OR REPLACE INTO network_resources (app_name, resource_type, resource_value, service_name, status, created_date, created_time) VALUES ('$app_name', 'url_accessible', '$url_accessible_for_tag', '$db_service_name', 'active', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null + runInstallOp sqlite3 "$docker_dir/$db_file" "INSERT OR REPLACE INTO network_resources (app_name, resource_type, resource_value, service_name, status, created_date, created_time) VALUES ('$app_name', 'port_tag_combined', '$combined_port', '$db_service_name', 'active', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null + runInstallOp sqlite3 "$docker_dir/$db_file" "INSERT OR REPLACE INTO network_resources (app_name, resource_type, resource_value, service_name, status, created_date, created_time) VALUES ('$app_name', 'port_tag_external', '$port_for_tag', '$db_service_name', 'active', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null + runInstallOp sqlite3 "$docker_dir/$db_file" "INSERT OR REPLACE INTO network_resources (app_name, resource_type, resource_value, service_name, status, created_date, created_time) VALUES ('$app_name', 'port_tag_internal', '$internal_port_for_tag', '$db_service_name', 'active', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null + runInstallOp sqlite3 "$docker_dir/$db_file" "INSERT OR REPLACE INTO network_resources (app_name, resource_type, resource_value, service_name, status, created_date, created_time) VALUES ('$app_name', 'traefik_managed', '$traefik_managed_for_tag', '$db_service_name', 'active', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null + runInstallOp sqlite3 "$docker_dir/$db_file" "INSERT OR REPLACE INTO network_resources (app_name, resource_type, resource_value, service_name, status, created_date, created_time) VALUES ('$app_name', 'url_accessible', '$url_accessible_for_tag', '$db_service_name', 'active', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null else # Log disabled port with 'disabled' status - runFileOp sqlite3 "$docker_dir/$db_file" "INSERT OR REPLACE INTO network_resources (app_name, resource_type, resource_value, service_name, status, created_date, created_time) VALUES ('$app_name', 'port_tag_combined', '$combined_port', '$db_service_name', 'disabled', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null + runInstallOp sqlite3 "$docker_dir/$db_file" "INSERT OR REPLACE INTO network_resources (app_name, resource_type, resource_value, service_name, status, created_date, created_time) VALUES ('$app_name', 'port_tag_combined', '$combined_port', '$db_service_name', 'disabled', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null fi done