Merge claude/1
This commit is contained in:
commit
fa2df5dffe
@ -2,4 +2,4 @@
|
|||||||
# Rootless Networking - Network stack and behaviour for rootless Docker **ADVANCED**
|
# 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)]
|
||||||
|
|||||||
@ -60,10 +60,10 @@ installAuthelia()
|
|||||||
|
|
||||||
dockerComposeSetupFile $app_name;
|
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"
|
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"
|
checkSuccess "Copying users_database.yml to $containers_dir$app_name/config"
|
||||||
|
|
||||||
local authelia_config_file="$containers_dir$app_name/config/configuration.yml"
|
local authelia_config_file="$containers_dir$app_name/config/configuration.yml"
|
||||||
|
|||||||
@ -54,7 +54,7 @@ installHeadscale()
|
|||||||
local result=$(createFolders "loud" $docker_install_user $containers_dir$app_name/config)
|
local result=$(createFolders "loud" $docker_install_user $containers_dir$app_name/config)
|
||||||
checkSuccess "Create config folder"
|
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."
|
checkSuccess "Copying config.yaml to config folder."
|
||||||
|
|
||||||
configSetupFileWithData $app_name "config.yaml" "config";
|
configSetupFileWithData $app_name "config.yaml" "config";
|
||||||
|
|||||||
@ -57,7 +57,7 @@ installPrometheus()
|
|||||||
local result=$(createTouch "$containers_dir$app_name/$app_name/$app_name.yml" $docker_install_user)
|
local result=$(createTouch "$containers_dir$app_name/$app_name/$app_name.yml" $docker_install_user)
|
||||||
checkSuccess "Created $app_name.yml file for $app_name"
|
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."
|
checkSuccess "Copying $app_name.yml to containers folder."
|
||||||
|
|
||||||
((menu_number++))
|
((menu_number++))
|
||||||
|
|||||||
@ -53,7 +53,7 @@ installUnbound()
|
|||||||
|
|
||||||
monitoringToggleAppConfig "$app_name" "docker-compose.yml";
|
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."
|
checkSuccess "Copying unbound.conf to containers folder."
|
||||||
|
|
||||||
monitoringToggleAppConfig "$app_name" "etc/unbound.conf";
|
monitoringToggleAppConfig "$app_name" "etc/unbound.conf";
|
||||||
|
|||||||
@ -44,7 +44,7 @@ dockerConfigSetupToContainer()
|
|||||||
if [ "$silent_flag" == "loud" ]; then
|
if [ "$silent_flag" == "loud" ]; then
|
||||||
isNotice "Copying config file to '$target_path/$config_file'..."
|
isNotice "Copying config file to '$target_path/$config_file'..."
|
||||||
fi
|
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
|
fi
|
||||||
|
|
||||||
if [[ -n "$config_overrides" ]]; then
|
if [[ -n "$config_overrides" ]]; then
|
||||||
@ -124,7 +124,7 @@ dockerConfigSetupToContainer()
|
|||||||
case $resetconfigaccept in
|
case $resetconfigaccept in
|
||||||
[yY])
|
[yY])
|
||||||
isNotice "Resetting $app_name config file."
|
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
|
source $target_path/$config_file
|
||||||
dockerConfigSetupToContainer "loud" $app_name;
|
dockerConfigSetupToContainer "loud" $app_name;
|
||||||
while true; do
|
while true; do
|
||||||
@ -204,7 +204,7 @@ dockerConfigSetupToContainer()
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
isNotice "Config file for $app_name does not exist. Creating it..."
|
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."
|
isNotice "Config file for $app_name contains no edits."
|
||||||
while true; do
|
while true; do
|
||||||
#isQuestion "Would you like to make edits to the config file? (y/n): "
|
#isQuestion "Would you like to make edits to the config file? (y/n): "
|
||||||
|
|||||||
@ -62,7 +62,7 @@ tagsProcessorGluetunForwardedPorts()
|
|||||||
if [[ ! -f "$docker_dir/$db_file" ]]; then return 0; fi
|
if [[ ! -f "$docker_dir/$db_file" ]]; then return 0; fi
|
||||||
|
|
||||||
local installed_apps
|
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)
|
"SELECT name FROM apps WHERE status = 1 ORDER BY name;" 2>/dev/null)
|
||||||
|
|
||||||
local routed_lines=""
|
local routed_lines=""
|
||||||
@ -75,7 +75,7 @@ tagsProcessorGluetunForwardedPorts()
|
|||||||
[[ "$net" != "gluetun" ]] && continue
|
[[ "$net" != "gluetun" ]] && continue
|
||||||
|
|
||||||
local ports
|
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)
|
"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
|
while IFS= read -r p; do
|
||||||
[[ -z "$p" ]] && continue
|
[[ -z "$p" ]] && continue
|
||||||
|
|||||||
@ -31,7 +31,7 @@ databaseAppScan()
|
|||||||
local updated_count=0
|
local updated_count=0
|
||||||
|
|
||||||
# Get the list of all folder names and statuses from the database
|
# 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
|
# Create an array to store existing folder names in the database
|
||||||
local existing_folder_names=()
|
local existing_folder_names=()
|
||||||
@ -43,7 +43,7 @@ databaseAppScan()
|
|||||||
if (( status == 0 )); then
|
if (( status == 0 )); then
|
||||||
isNotice "The folder for $folder_name has been found."
|
isNotice "The folder for $folder_name has been found."
|
||||||
# Update the database to set the status to 1 (installed) and unset the uninstall_date
|
# 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."
|
checkSuccess "Updating apps database for $folder_name to installed status."
|
||||||
((updated_count++)) # Increment updated_count
|
((updated_count++)) # Increment updated_count
|
||||||
fi
|
fi
|
||||||
@ -72,7 +72,7 @@ databaseAppScan()
|
|||||||
local folder_time=$(echo "$folder_datetime" | awk '{print $2}')
|
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
|
# 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."
|
checkSuccess "Adding $app_name to the apps database."
|
||||||
((updated_count++)) # Increment updated_count
|
((updated_count++)) # Increment updated_count
|
||||||
fi
|
fi
|
||||||
@ -97,7 +97,7 @@ databaseAppScan()
|
|||||||
isNotice "Folder $folder_name no longer exists. Removing from the Database."
|
isNotice "Folder $folder_name no longer exists. Removing from the Database."
|
||||||
|
|
||||||
# Delete the entry from the apps table
|
# 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."
|
checkSuccess "Removing $app_name from the apps database."
|
||||||
|
|
||||||
portsRemoveFromDatabase $app_name;
|
portsRemoveFromDatabase $app_name;
|
||||||
@ -196,7 +196,7 @@ databaseAppScan()
|
|||||||
else
|
else
|
||||||
# If the folder doesn't exist in the directory, uninstall it from the database
|
# 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."
|
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."
|
checkSuccess "Removing $folder_name from the apps database."
|
||||||
((updated_count++)) # Increment updated_count
|
((updated_count++)) # Increment updated_count
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -17,16 +17,16 @@ databaseListInstalledApp()
|
|||||||
isNotice "Database file not found. Make sure it's installed."
|
isNotice "Database file not found. Make sure it's installed."
|
||||||
else
|
else
|
||||||
# Check if app exists and is installed
|
# 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
|
if [ -z "$app_check" ]; then
|
||||||
isNotice "App '$app_name' not found or not installed."
|
isNotice "App '$app_name' not found or not installed."
|
||||||
else
|
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"
|
printf "\e[33m📦 %s\e[0m (Installed: %s)\n" "$app_name" "$app_details"
|
||||||
|
|
||||||
# Get all Docker services with IPs for this app
|
# 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
|
if [[ -n "$docker_services" ]]; then
|
||||||
local service_count=0
|
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"
|
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
|
# 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
|
if [[ -n "$service_ports" ]]; then
|
||||||
local port_count=0
|
local port_count=0
|
||||||
@ -97,7 +97,7 @@ databaseListInstalledApp()
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if Traefik is installed
|
# 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
|
# Per-port URL path: 10th column of the matching
|
||||||
# CFG_<APP>_PORT_N row in the deployed config. Find the
|
# CFG_<APP>_PORT_N row in the deployed config. Find the
|
||||||
@ -137,7 +137,7 @@ databaseListInstalledApp()
|
|||||||
|
|
||||||
local _domain=""
|
local _domain=""
|
||||||
if [[ -n "$traefik_installed" ]]; then
|
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
|
fi
|
||||||
|
|
||||||
local _path_idx _p
|
local _path_idx _p
|
||||||
|
|||||||
@ -51,13 +51,15 @@ runSystem() {
|
|||||||
sudo "$@"
|
sudo "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Op on the manager install dir / shipped templates — the LibrePortal clone and
|
# Op on a MANAGER-owned path — the LibrePortal clone + shipped templates AND the
|
||||||
# its container templates, owned by the manager user that runs the runtime.
|
# /docker management layer the runtime owns (apps DB, configs/, logs/, scripts).
|
||||||
# rooted -> sudo <cmd> (install tree is root-owned; byte-identical)
|
# In rootless these are owned by the manager user; ops on them need no privilege.
|
||||||
# rootless -> <cmd> (the manager user already owns it — no privilege)
|
# rooted -> sudo <cmd> (root-owned; byte-identical)
|
||||||
# For copies that read the install tree and write into /docker (two different
|
# rootless -> <cmd> (runs as the current user: root at install-time,
|
||||||
# owners in rootless), don't use this for the whole copy — read here and pipe
|
# the manager user at runtime — both can access)
|
||||||
# into runFileWrite so each side runs as the correct owner.
|
# Container-owned data under /docker/containers/<app>/ 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() {
|
runInstallOp() {
|
||||||
if [[ "$CFG_DOCKER_INSTALL_TYPE" == "rootless" ]]; then
|
if [[ "$CFG_DOCKER_INSTALL_TYPE" == "rootless" ]]; then
|
||||||
"$@"
|
"$@"
|
||||||
@ -65,3 +67,22 @@ runInstallOp() {
|
|||||||
sudo "$@"
|
sudo "$@"
|
||||||
fi
|
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
|
||||||
|
}
|
||||||
|
|||||||
@ -40,7 +40,7 @@ dockerComposeSetupFile()
|
|||||||
isError "The source file '$source_file' does not exist."
|
isError "The source file '$source_file' does not exist."
|
||||||
fi
|
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
|
if [ $? -ne 0 ]; then
|
||||||
isError "Failed to copy the source file to '$target_path'. Check '$docker_log_file' for more details."
|
isError "Failed to copy the source file to '$target_path'. Check '$docker_log_file' for more details."
|
||||||
|
|||||||
@ -212,29 +212,20 @@ EOL"
|
|||||||
# Enabling unprivileged user namespaces (needed for rootless) widens the
|
# Enabling unprivileged user namespaces (needed for rootless) widens the
|
||||||
# kernel attack surface reachable by unprivileged users. Offset that by
|
# kernel attack surface reachable by unprivileged users. Offset that by
|
||||||
# closing the surfaces that local-privilege-escalation chains lean on:
|
# closing the surfaces that local-privilege-escalation chains lean on:
|
||||||
# kptr_restrict hides kernel pointers (defeats info-leak primitives),
|
# kptr_restrict hides kernel pointers (info-leak primitives), ptrace_scope
|
||||||
# ptrace_scope blocks cross-process ptrace (limits credential theft after
|
# blocks cross-process ptrace (credential theft post-compromise), and
|
||||||
# a compromise), and bpf_jit_harden hardens the JIT against spraying.
|
# bpf_jit_harden hardens the JIT against spraying. Written under
|
||||||
# All three are distro-portable and have negligible runtime impact.
|
# /etc/sysctl.d/ so `sysctl --system` actually loads it — LibrePortal's
|
||||||
if ! grep -qF "# LIBREPORTAL KERNEL HARDENING START" "$sysctl"; then
|
# own $sysctl path (/etc/sysctl/…) is non-standard and is NOT read by
|
||||||
|
# `sysctl --system`.
|
||||||
local result=$(echo '# LIBREPORTAL KERNEL HARDENING START' | sudo tee -a "$sysctl" > /dev/null)
|
local hardening_conf="/etc/sysctl.d/99-libreportal-hardening.conf"
|
||||||
checkSuccess "Adding kernel hardening header to sysctl"
|
sudo bash -c "cat > '$hardening_conf'" <<'EOL'
|
||||||
|
# LibrePortal kernel LPE-surface hardening (paired with rootless unprivileged userns)
|
||||||
local result=$(echo 'kernel.kptr_restrict=2' | sudo tee -a "$sysctl" > /dev/null)
|
kernel.kptr_restrict=2
|
||||||
checkSuccess "Restricting kernel pointer exposure (kptr_restrict)"
|
kernel.yama.ptrace_scope=1
|
||||||
|
net.core.bpf_jit_harden=2
|
||||||
local result=$(echo 'kernel.yama.ptrace_scope=1' | sudo tee -a "$sysctl" > /dev/null)
|
EOL
|
||||||
checkSuccess "Restricting cross-process ptrace (yama.ptrace_scope)"
|
checkSuccess "Writing kernel LPE-surface hardening to $hardening_conf"
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
local result=$(sudo sysctl --system)
|
local result=$(sudo sysctl --system)
|
||||||
checkSuccess "Applying changes to sysctl"
|
checkSuccess "Applying changes to sysctl"
|
||||||
|
|||||||
@ -5,7 +5,7 @@ function checkSuccess()
|
|||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
isSuccessful "$1"
|
isSuccessful "$1"
|
||||||
if [ -f "$logs_dir/$docker_log_file" ]; then
|
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
|
fi
|
||||||
else
|
else
|
||||||
isError "$1"
|
isError "$1"
|
||||||
@ -14,8 +14,8 @@ function checkSuccess()
|
|||||||
# blocking on read.
|
# blocking on read.
|
||||||
if [[ "$LIBREPORTAL_NONINTERACTIVE" == "1" ]] || [ ! -t 0 ]; then
|
if [[ "$LIBREPORTAL_NONINTERACTIVE" == "1" ]] || [ ! -t 0 ]; then
|
||||||
if [ -f "$logs_dir/$docker_log_file" ]; then
|
if [ -f "$logs_dir/$docker_log_file" ]; then
|
||||||
isError " $1" | runFileWrite -a "$logs_dir/$docker_log_file" >/dev/null
|
isError " $1" | runInstallWrite -a "$logs_dir/$docker_log_file" >/dev/null
|
||||||
echo "===================================" | runFileWrite -a "$logs_dir/$docker_log_file" >/dev/null
|
echo "===================================" | runInstallWrite -a "$logs_dir/$docker_log_file" >/dev/null
|
||||||
fi
|
fi
|
||||||
isNotice "Non-interactive mode: aborting on error."
|
isNotice "Non-interactive mode: aborting on error."
|
||||||
exit 1
|
exit 1
|
||||||
@ -36,15 +36,15 @@ function checkSuccess()
|
|||||||
|
|
||||||
if [[ "$error_occurred" == [xX] ]]; then
|
if [[ "$error_occurred" == [xX] ]]; then
|
||||||
# Log the error output to the log file
|
# Log the error output to the log file
|
||||||
isError " $1" | runFileWrite -a "$logs_dir/$docker_log_file"
|
isError " $1" | runInstallWrite -a "$logs_dir/$docker_log_file"
|
||||||
echo "===================================" | runFileWrite -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
|
exit 1 # Exit the script with a non-zero status to stop the current action
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$error_occurred" == [mM] ]]; then
|
if [[ "$error_occurred" == [mM] ]]; then
|
||||||
# Log the error output to the log file
|
# Log the error output to the log file
|
||||||
isError " $1" | runFileWrite -a "$logs_dir/$docker_log_file"
|
isError " $1" | runInstallWrite -a "$logs_dir/$docker_log_file"
|
||||||
echo "===================================" | runFileWrite -a "$logs_dir/$docker_log_file"
|
echo "===================================" | runInstallWrite -a "$logs_dir/$docker_log_file"
|
||||||
if [[ "$initial_command2" == "terminal" ]]; then
|
if [[ "$initial_command2" == "terminal" ]]; then
|
||||||
resetToMenu;
|
resetToMenu;
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -18,7 +18,7 @@ fixAppFolderPermissions()
|
|||||||
|
|
||||||
# Updating $containers_dir with execute permissions
|
# Updating $containers_dir with execute permissions
|
||||||
if [ -d "$containers_dir" ]; then
|
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
|
if [ "$silent_flag" == "loud" ]; then
|
||||||
checkSuccess "Updating $containers_dir with execute permissions."
|
checkSuccess "Updating $containers_dir with execute permissions."
|
||||||
fi
|
fi
|
||||||
@ -30,7 +30,7 @@ fixAppFolderPermissions()
|
|||||||
|
|
||||||
# Updating $containers_dir$app_name with execute permissions
|
# Updating $containers_dir$app_name with execute permissions
|
||||||
if [ -d "$containers_dir$app_name" ]; then
|
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
|
if [ "$silent_flag" == "loud" ]; then
|
||||||
checkSuccess "Updating $containers_dir$app_name with execute permissions."
|
checkSuccess "Updating $containers_dir$app_name with execute permissions."
|
||||||
fi
|
fi
|
||||||
@ -42,7 +42,7 @@ fixAppFolderPermissions()
|
|||||||
|
|
||||||
# Updating $app_name with read permissions
|
# Updating $app_name with read permissions
|
||||||
if [ -d "$containers_dir$app_name" ]; then
|
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
|
if [ "$silent_flag" == "loud" ]; then
|
||||||
checkSuccess "Updating $app_name with read permissions"
|
checkSuccess "Updating $app_name with read permissions"
|
||||||
fi
|
fi
|
||||||
@ -54,7 +54,7 @@ fixAppFolderPermissions()
|
|||||||
|
|
||||||
# Updating compose file(s) for LibrePortal access
|
# Updating compose file(s) for LibrePortal access
|
||||||
if [ -d "$containers_dir$app_name" ]; then
|
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
|
if [ "$silent_flag" == "loud" ]; then
|
||||||
isNotice "Updating compose file(s) for LibrePortal access"
|
isNotice "Updating compose file(s) for LibrePortal access"
|
||||||
fi
|
fi
|
||||||
@ -70,7 +70,7 @@ fixAppFolderPermissions()
|
|||||||
local file_path="$containers_dir$app_name/$file"
|
local file_path="$containers_dir$app_name/$file"
|
||||||
# Check if the file exists
|
# Check if the file exists
|
||||||
if [ -e "$file_path" ]; then
|
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
|
if [ "$silent_flag" == "loud" ]; then
|
||||||
checkSuccess "Updating $file with $docker_install_user ownership"
|
checkSuccess "Updating $file with $docker_install_user ownership"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -5,23 +5,23 @@ fixFolderPermissions()
|
|||||||
local silent_flag="$1"
|
local silent_flag="$1"
|
||||||
local app_name="$2"
|
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
|
if [ "$silent_flag" == "loud" ]; then
|
||||||
checkSuccess "Updating $docker_dir with execute permissions."
|
checkSuccess "Updating $docker_dir with execute permissions."
|
||||||
fi
|
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
|
if [ "$silent_flag" == "loud" ]; then
|
||||||
checkSuccess "Updating $containers_dir with execute permissions."
|
checkSuccess "Updating $containers_dir with execute permissions."
|
||||||
fi
|
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
|
if [ "$silent_flag" == "loud" ]; then
|
||||||
checkSuccess "Adding execute permissions for $docker_install_user user"
|
checkSuccess "Adding execute permissions for $docker_install_user user"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Install user related
|
# 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
|
if [ "$silent_flag" == "loud" ]; then
|
||||||
checkSuccess "Updating $containers_dir with $docker_install_user ownership"
|
checkSuccess "Updating $containers_dir with $docker_install_user ownership"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -8,7 +8,7 @@ tailscaleInstallToContainer()
|
|||||||
local result=$(createFolders "loud" $docker_install_user $containers_dir$app_name/tailscale)
|
local result=$(createFolders "loud" $docker_install_user $containers_dir$app_name/tailscale)
|
||||||
checkSuccess "Creating Tailscale folder"
|
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
|
if [[ "$type" != "install" ]]; then
|
||||||
dockerComposeRestart $app_name;
|
dockerComposeRestart $app_name;
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
monitoringInstalledApps()
|
monitoringInstalledApps()
|
||||||
{
|
{
|
||||||
[[ -f "$docker_dir/$db_file" ]] || return 0
|
[[ -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
|
"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
|
[[ -f "$docker_dir/$db_file" ]] || return 1
|
||||||
local n
|
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)"
|
"SELECT COUNT(*) FROM apps WHERE name = '$1' AND status = 1;" 2>/dev/null)"
|
||||||
[[ -n "$n" && "$n" -gt 0 ]]
|
[[ -n "$n" && "$n" -gt 0 ]]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,23 +9,23 @@ portStoreMapping()
|
|||||||
local parent_service="$4" # parent Docker service (optional)
|
local parent_service="$4" # parent Docker service (optional)
|
||||||
|
|
||||||
# Check if ports already exist for this app/service
|
# 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
|
if [[ -n "$existing" ]]; then
|
||||||
# UPDATE existing ports
|
# UPDATE existing ports
|
||||||
if [[ -n "$parent_service" ]]; then
|
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
|
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
|
fi
|
||||||
isNotice "Updated ports for $app_name/$service_name"
|
isNotice "Updated ports for $app_name/$service_name"
|
||||||
#isNotice "Updated ports for $app_name/$service_name: $existing → $port_mapping"
|
#isNotice "Updated ports for $app_name/$service_name: $existing → $port_mapping"
|
||||||
else
|
else
|
||||||
# INSERT new ports
|
# INSERT new ports
|
||||||
if [[ -n "$parent_service" ]]; then
|
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
|
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
|
fi
|
||||||
isSuccessful "Allocated port: $port_mapping"
|
isSuccessful "Allocated port: $port_mapping"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -108,14 +108,14 @@ portUpdateComposeTags()
|
|||||||
# Only log to database if port is not disabled
|
# Only log to database if port is not disabled
|
||||||
if [[ "$access_type_for_tag" != "disabled" ]]; then
|
if [[ "$access_type_for_tag" != "disabled" ]]; then
|
||||||
# Log to database
|
# 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
|
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
|
||||||
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
|
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
|
||||||
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
|
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
|
||||||
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
|
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
|
||||||
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', 'url_accessible', '$url_accessible_for_tag', '$db_service_name', 'active', CURRENT_DATE, CURRENT_TIME);" 2>/dev/null
|
||||||
else
|
else
|
||||||
# Log disabled port with 'disabled' status
|
# 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
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user