diff --git a/misc/tools.func b/misc/tools.func index d389d9a5d..2dc208570 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -37,8 +37,8 @@ check_for_gh_release() { # jq check if ! command -v jq &>/dev/null; then - $STD apt-get update -qq - $STD apt-get install -y jq || { + $STD apt update -qq + $STD apt install -y jq || { msg_error "Failed to install jq" return 1 } @@ -134,12 +134,27 @@ check_for_gh_release() { # Variables: # APP - Application name (default: $APPLICATION variable) # ------------------------------------------------------------------------------ -function create_selfsigned_certs() { - local app=${APP:-$(echo "${APPLICATION,,}" | tr -d ' ')} - $STD openssl req -x509 -nodes -days 365 -newkey rsa:4096 \ - -keyout /etc/ssl/private/"$app"-selfsigned.key \ - -out /etc/ssl/certs/"$app"-selfsigned.crt \ - -subj "/C=US/O=$app/OU=Domain Control Validated/CN=localhost" +create_self_signed_cert() { + local APP_NAME="${1:-${APPLICATION}}" + local CERT_DIR="/etc/ssl/${APP_NAME}" + local CERT_KEY="${CERT_DIR}/${APP_NAME}.key" + local CERT_CRT="${CERT_DIR}/${APP_NAME}.crt" + + if [[ -f "$CERT_CRT" && -f "$CERT_KEY" ]]; then + return 0 + fi + + $STD apt update + $STD apt install -y openssl + + mkdir -p "$CERT_DIR" + $STD openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 \ + -subj "/C=US/ST=State/L=City/O=Organization/CN=${APP_NAME}" \ + -keyout "$CERT_KEY" \ + -out "$CERT_CRT" + + chmod 600 "$CERT_KEY" + chmod 644 "$CERT_CRT" } # ------------------------------------------------------------------------------ @@ -156,7 +171,7 @@ function download_with_progress() { if [ -n "$SPINNER_PID" ] && ps -p "$SPINNER_PID" >/dev/null; then kill "$SPINNER_PID" >/dev/null; fi if ! command -v pv &>/dev/null; then - $STD apt-get install -y pv + $STD apt install -y pv fi set -o pipefail @@ -255,7 +270,7 @@ function fetch_and_deploy_gh_release() { [[ -f "$version_file" ]] && current_version=$(<"$version_file") if ! command -v jq &>/dev/null; then - $STD apt-get install -y jq &>/dev/null + $STD apt install -y jq &>/dev/null fi local api_url="https://api.github.com/repos/$repo/releases" @@ -387,7 +402,7 @@ function fetch_and_deploy_gh_release() { } chmod 644 "$tmpdir/$filename" - $STD apt-get install -y "$tmpdir/$filename" || { + $STD apt install -y "$tmpdir/$filename" || { $STD dpkg -i "$tmpdir/$filename" || { msg_error "Both apt and dpkg installation failed" rm -rf "$tmpdir" @@ -438,7 +453,7 @@ function fetch_and_deploy_gh_release() { if [[ "$filename" == *.zip ]]; then if ! command -v unzip &>/dev/null; then - $STD apt-get install -y unzip + $STD apt install -y unzip fi unzip -q "$tmpdir/$filename" -d "$unpack_tmp" elif [[ "$filename" == *.tar.* || "$filename" == *.tgz ]]; then @@ -605,7 +620,7 @@ function setup_adminer() { msg_ok "Adminer available at /adminer (Alpine)" else msg_info "Setup Adminer (Debian/Ubuntu)" - $STD apt-get install -y adminer + $STD apt install -y adminer $STD a2enconf adminer $STD systemctl reload apache2 msg_ok "Adminer available at /adminer (Debian/Ubuntu)" @@ -699,8 +714,8 @@ function setup_ffmpeg() { fi if ! command -v jq &>/dev/null; then - $STD apt-get update - $STD apt-get install -y jq + $STD apt update + $STD apt install -y jq fi # Auto-detect latest stable version if none specified @@ -744,8 +759,8 @@ function setup_ffmpeg() { ;; esac - $STD apt-get update - $STD apt-get install -y "${DEPS[@]}" + $STD apt update + $STD apt install -y "${DEPS[@]}" curl -fsSL "https://github.com/${GITHUB_REPO}/archive/refs/tags/${VERSION}.tar.gz" -o "$TMP_DIR/ffmpeg.tar.gz" tar -xzf "$TMP_DIR/ffmpeg.tar.gz" -C "$TMP_DIR" @@ -915,7 +930,7 @@ function setup_gs() { msg_error "Failed to enter Ghostscript source directory." rm -rf "$TMP_DIR" } - $STD apt-get install -y build-essential libpng-dev zlib1g-dev + $STD apt install -y build-essential libpng-dev zlib1g-dev $STD ./configure >/dev/null $STD make $STD sudo make install @@ -960,8 +975,8 @@ function setup_imagemagick() { fi msg_info "Setup ImageMagick (Patience)" - $STD apt-get update - $STD apt-get install -y \ + $STD apt update + $STD apt install -y \ build-essential \ libtool \ libjpeg-dev \ @@ -1019,41 +1034,57 @@ function setup_imagemagick() { function setup_java() { local JAVA_VERSION="${JAVA_VERSION:-21}" - local DISTRO_CODENAME + local DISTRO_ID DISTRO_CODENAME + DISTRO_ID=$(awk -F= '/^ID=/{print $2}' /etc/os-release | tr -d '"') DISTRO_CODENAME=$(awk -F= '/VERSION_CODENAME/ { print $2 }' /etc/os-release) local DESIRED_PACKAGE="temurin-${JAVA_VERSION}-jdk" - # Add Adoptium repo if missing - if [[ ! -f /etc/apt/sources.list.d/adoptium.list ]]; then - $STD msg_info "Setting up Adoptium Repository" + # Add repo nur wenn nötig + if [[ ! -f /etc/apt/sources.list.d/adoptium.sources ]]; then + msg_info "Setting up Adoptium Repository" mkdir -p /etc/apt/keyrings - curl -fsSL "https://packages.adoptium.net/artifactory/api/gpg/key/public" | gpg --dearmor -o /etc/apt/trusted.gpg.d/adoptium.gpg - echo "deb [signed-by=/etc/apt/trusted.gpg.d/adoptium.gpg] https://packages.adoptium.net/artifactory/deb ${DISTRO_CODENAME} main" \ - >/etc/apt/sources.list.d/adoptium.list - $STD apt-get update - $STD msg_ok "Set up Adoptium Repository" + curl -fsSL "https://packages.adoptium.net/artifactory/api/gpg/key/public" | gpg --dearmor -o /etc/apt/keyrings/adoptium.gpg + + local SUITE="$DISTRO_CODENAME" + if ! curl -fsSL "https://packages.adoptium.net/artifactory/deb/dists/$DISTRO_CODENAME/Release" &>/dev/null; then + case "$DISTRO_ID" in + debian) SUITE="bookworm" ;; + ubuntu) SUITE="jammy" ;; + esac + fi + + cat </etc/apt/sources.list.d/adoptium.sources +Types: deb +URIs: https://packages.adoptium.net/artifactory/deb +Suites: $SUITE +Components: main +Architectures: amd64 arm64 +Signed-By: /etc/apt/keyrings/adoptium.gpg +EOF + $STD apt update + msg_ok "Set up Adoptium Repository" fi - # Detect currently installed temurin version local INSTALLED_VERSION="" if dpkg -l | grep -q "temurin-.*-jdk"; then INSTALLED_VERSION=$(dpkg -l | awk '/temurin-.*-jdk/{print $2}' | grep -oP 'temurin-\K[0-9]+') fi if [[ "$INSTALLED_VERSION" == "$JAVA_VERSION" ]]; then - $STD msg_info "Upgrading Temurin JDK $JAVA_VERSION" - $STD apt-get update - $STD apt-get install --only-upgrade -y "$DESIRED_PACKAGE" - $STD msg_ok "Upgraded Temurin JDK $JAVA_VERSION" + msg_info "Upgrading Temurin JDK $JAVA_VERSION" + $STD apt update + $STD apt install --only-upgrade -y "$DESIRED_PACKAGE" + msg_ok "Upgraded Temurin JDK $JAVA_VERSION" else if [[ -n "$INSTALLED_VERSION" ]]; then - $STD msg_info "Removing Temurin JDK $INSTALLED_VERSION" - $STD apt-get purge -y "temurin-${INSTALLED_VERSION}-jdk" + msg_info "Removing old Temurin JDK $INSTALLED_VERSION" + $STD apt purge -y "temurin-${INSTALLED_VERSION}-jdk" + msg_ok "Removed old Temurin JDK" fi - msg_info "Setup Temurin JDK $JAVA_VERSION" - $STD apt-get install -y "$DESIRED_PACKAGE" - msg_ok "Setup Temurin JDK $JAVA_VERSION" + msg_info "Installing Temurin JDK $JAVA_VERSION" + $STD apt install -y "$DESIRED_PACKAGE" + msg_ok "Installed Temurin JDK $JAVA_VERSION" fi } @@ -1075,8 +1106,8 @@ function setup_local_ip_helper() { # Install networkd-dispatcher if not present if ! dpkg -s networkd-dispatcher >/dev/null 2>&1; then - $STD apt-get update - $STD apt-get install -y networkd-dispatcher + $STD apt update + $STD apt install -y networkd-dispatcher fi # Write update_local_ip.sh @@ -1149,17 +1180,15 @@ EOF setup_mariadb() { local MARIADB_VERSION="${MARIADB_VERSION:-latest}" - local DISTRO_CODENAME - DISTRO_CODENAME="$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release)" - CURRENT_OS="$(awk -F= '/^ID=/{print $2}' /etc/os-release)" + local DISTRO_ID DISTRO_CODENAME + DISTRO_ID=$(awk -F= '/^ID=/{print $2}' /etc/os-release | tr -d '"') + DISTRO_CODENAME=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release) if ! curl -fsI http://mirror.mariadb.org/repo/ >/dev/null; then msg_error "MariaDB mirror not reachable" return 1 fi - msg_info "Setting up MariaDB $MARIADB_VERSION" - # Grab dynamic latest LTS version if [[ "$MARIADB_VERSION" == "latest" ]]; then MARIADB_VERSION=$(curl -fsSL http://mirror.mariadb.org/repo/ | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+/' | @@ -1179,54 +1208,56 @@ setup_mariadb() { fi if [[ "$CURRENT_VERSION" == "$MARIADB_VERSION" ]]; then - $STD msg_info "MariaDB $MARIADB_VERSION, upgrading" - $STD apt-get update - $STD apt-get install --only-upgrade -y mariadb-server mariadb-client - $STD msg_ok "MariaDB upgraded to $MARIADB_VERSION" + msg_info "Upgrading MariaDB $MARIADB_VERSION" + $STD apt update + $STD apt install --only-upgrade -y mariadb-server mariadb-client + msg_ok "Upgraded MariaDB $MARIADB_VERSION" return 0 fi + msg_info "Installing MariaDB $MARIADB_VERSION" + if [[ -n "$CURRENT_VERSION" ]]; then - $STD msg_info "Upgrading MariaDB $CURRENT_VERSION to $MARIADB_VERSION" $STD systemctl stop mariadb >/dev/null 2>&1 || true - $STD apt-get purge -y 'mariadb*' || true - rm -f /etc/apt/sources.list.d/mariadb.list /etc/apt/trusted.gpg.d/mariadb.gpg - else - $STD msg_info "Setup MariaDB $MARIADB_VERSION" + $STD apt purge -y 'mariadb*' || true + rm -f /etc/apt/sources.list.d/mariadb.* /etc/apt/keyrings/mariadb.gpg fi curl -fsSL "https://mariadb.org/mariadb_release_signing_key.asc" | - gpg --dearmor -o /etc/apt/trusted.gpg.d/mariadb.gpg + gpg --dearmor -o /etc/apt/keyrings/mariadb.gpg - echo "deb [signed-by=/etc/apt/trusted.gpg.d/mariadb.gpg] http://mirror.mariadb.org/repo/${MARIADB_VERSION}/${CURRENT_OS} ${DISTRO_CODENAME} main" \ - >/etc/apt/sources.list.d/mariadb.list + local SUITE="$DISTRO_CODENAME" + if ! curl -fsSL "http://mirror.mariadb.org/repo/${MARIADB_VERSION}/${DISTRO_ID}/dists/$DISTRO_CODENAME/Release" &>/dev/null; then + case "$DISTRO_ID" in + debian) SUITE="bookworm" ;; + ubuntu) SUITE="jammy" ;; + esac + fi - $STD apt-get update + cat </etc/apt/sources.list.d/mariadb.sources +Types: deb +URIs: http://mirror.mariadb.org/repo/${MARIADB_VERSION}/${DISTRO_ID} +Suites: $SUITE +Components: main +Architectures: amd64 arm64 +Signed-By: /etc/apt/keyrings/mariadb.gpg +EOF + + $STD apt update local MARIADB_MAJOR_MINOR MARIADB_MAJOR_MINOR=$(echo "$MARIADB_VERSION" | awk -F. '{print $1"."$2}') if [[ -n "$MARIADB_MAJOR_MINOR" ]]; then echo "mariadb-server-$MARIADB_MAJOR_MINOR mariadb-server/feedback boolean false" | debconf-set-selections - else - for ver in 12.1 12.0 11.4 11.3 11.2 11.1 11.0 10.11 10.6 10.5 10.4 10.3; do - echo "mariadb-server-$ver mariadb-server/feedback boolean false" | debconf-set-selections - done fi - DEBIAN_FRONTEND=noninteractive $STD apt-get install -y mariadb-server mariadb-client || { - msg_warn "Failed to install MariaDB ${MARIADB_VERSION} from upstream repo – trying distro package as fallback..." - # Cleanup, remove upstream repo to avoid conflicts - rm -f /etc/apt/sources.list.d/mariadb.list /etc/apt/trusted.gpg.d/mariadb.gpg - $STD apt-get update - # Final fallback: distro package - DEBIAN_FRONTEND=noninteractive $STD apt-get install -y mariadb-server mariadb-client || { - msg_error "MariaDB installation failed even with distro fallback!" - return 1 - } - msg_ok "Setup MariaDB (distro fallback)" - return 0 + + DEBIAN_FRONTEND=noninteractive $STD apt install -y mariadb-server mariadb-client || { + rm -f /etc/apt/sources.list.d/mariadb.sources /etc/apt/keyrings/mariadb.gpg + $STD apt update + DEBIAN_FRONTEND=noninteractive $STD apt install -y mariadb-server mariadb-client } - msg_ok "Setup MariaDB $MARIADB_VERSION" + msg_ok "Installed MariaDB $MARIADB_VERSION" } # ------------------------------------------------------------------------------ @@ -1242,7 +1273,7 @@ setup_mariadb() { function setup_mongodb() { local MONGO_VERSION="${MONGO_VERSION:-8.0}" - local DISTRO_ID DISTRO_CODENAME MONGO_BASE_URL + local DISTRO_ID DISTRO_CODENAME DISTRO_ID=$(awk -F= '/^ID=/{ gsub(/"/,"",$2); print $2 }' /etc/os-release) DISTRO_CODENAME=$(awk -F= '/^VERSION_CODENAME=/{ print $2 }' /etc/os-release) @@ -1270,40 +1301,64 @@ function setup_mongodb() { ;; esac - local REPO_LIST="/etc/apt/sources.list.d/mongodb-org-${MONGO_VERSION}.list" - local INSTALLED_VERSION="" if command -v mongod >/dev/null; then INSTALLED_VERSION=$(mongod --version | awk '/db version/{print $3}' | cut -d. -f1,2) fi if [[ "$INSTALLED_VERSION" == "$MONGO_VERSION" ]]; then - $STD msg_info "Upgrading MongoDB $MONGO_VERSION" - $STD apt-get update - $STD apt-get install --only-upgrade -y mongodb-org - $STD msg_ok "Upgraded MongoDB $MONGO_VERSION" + msg_info "Upgrading MongoDB $MONGO_VERSION" + $STD apt update + $STD apt install --only-upgrade -y mongodb-org + msg_ok "Upgraded MongoDB $MONGO_VERSION" return 0 fi if [[ -n "$INSTALLED_VERSION" ]]; then $STD systemctl stop mongod || true - $STD apt-get purge -y mongodb-org || true - rm -f /etc/apt/sources.list.d/mongodb-org-*.list - rm -f /etc/apt/trusted.gpg.d/mongodb-*.gpg + $STD apt purge -y mongodb-org || true + rm -f /etc/apt/sources.list.d/mongodb-org-*.* /etc/apt/keyrings/mongodb-*.gpg else msg_info "Setup MongoDB $MONGO_VERSION" fi - curl -fsSL "https://pgp.mongodb.com/server-${MONGO_VERSION}.asc" | gpg --dearmor -o "/etc/apt/trusted.gpg.d/mongodb-${MONGO_VERSION}.gpg" - echo "deb [signed-by=/etc/apt/trusted.gpg.d/mongodb-${MONGO_VERSION}.gpg] ${MONGO_BASE_URL} ${DISTRO_CODENAME}/mongodb-org/${MONGO_VERSION} ${REPO_COMPONENT}" \ - >"$REPO_LIST" + curl -fsSL "https://pgp.mongodb.com/server-${MONGO_VERSION}.asc" | gpg --dearmor -o "/etc/apt/keyrings/mongodb-${MONGO_VERSION}.gpg" - $STD apt-get update || { + # Fallback logic for MongoDB repos + local SUITE="$DISTRO_CODENAME" + if ! curl -fsSL "${MONGO_BASE_URL}/dists/${DISTRO_CODENAME}/Release" &>/dev/null; then + case "$DISTRO_ID" in + debian) + case "$DISTRO_CODENAME" in + trixie) SUITE="bookworm" ;; + *) SUITE="bookworm" ;; + esac + ;; + ubuntu) + case "$DISTRO_CODENAME" in + oracular | noble) SUITE="jammy" ;; + *) SUITE="jammy" ;; + esac + ;; + esac + msg_info "Using fallback suite: $SUITE (original: $DISTRO_CODENAME)" + fi + + cat </etc/apt/sources.list.d/mongodb-org-${MONGO_VERSION}.sources +Types: deb +URIs: ${MONGO_BASE_URL} +Suites: ${SUITE}/mongodb-org/${MONGO_VERSION} +Components: ${REPO_COMPONENT} +Architectures: amd64 arm64 +Signed-By: /etc/apt/keyrings/mongodb-${MONGO_VERSION}.gpg +EOF + + $STD apt update || { msg_error "APT update failed — invalid MongoDB repo for ${DISTRO_ID}-${DISTRO_CODENAME}?" return 1 } - $STD apt-get install -y mongodb-org + $STD apt install -y mongodb-org mkdir -p /var/lib/mongodb chown -R mongodb:mongodb /var/lib/mongodb @@ -1329,20 +1384,21 @@ function setup_mysql() { local MYSQL_VERSION="${MYSQL_VERSION:-8.0}" local CURRENT_VERSION="" local NEED_INSTALL=false - CURRENT_OS="$(awk -F= '/^ID=/{print $2}' /etc/os-release)" + local DISTRO_ID DISTRO_CODENAME + DISTRO_ID=$(awk -F= '/^ID=/{print $2}' /etc/os-release | tr -d '"') + DISTRO_CODENAME=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release) if command -v mysql >/dev/null; then CURRENT_VERSION="$(mysql --version | grep -oP '[0-9]+\.[0-9]+' | head -n1)" if [[ "$CURRENT_VERSION" != "$MYSQL_VERSION" ]]; then - $STD msg_info "MySQL $CURRENT_VERSION will be upgraded to $MYSQL_VERSION" + msg_info "MySQL $CURRENT_VERSION will be upgraded to $MYSQL_VERSION" NEED_INSTALL=true else - # Check for patch-level updates if apt list --upgradable 2>/dev/null | grep -q '^mysql-server/'; then - $STD msg_info "MySQL $CURRENT_VERSION available for upgrade" - $STD apt-get update - $STD apt-get install --only-upgrade -y mysql-server - $STD msg_ok "MySQL upgraded" + msg_info "MySQL $CURRENT_VERSION available for upgrade" + $STD apt update + $STD apt install --only-upgrade -y mysql-server + msg_ok "MySQL upgraded" fi return fi @@ -1353,18 +1409,43 @@ function setup_mysql() { if [[ "$NEED_INSTALL" == true ]]; then $STD systemctl stop mysql || true - $STD apt-get purge -y "^mysql-server.*" "^mysql-client.*" "^mysql-common.*" || true - rm -f /etc/apt/sources.list.d/mysql.list /etc/apt/trusted.gpg.d/mysql.gpg + $STD apt purge -y "^mysql-server.*" "^mysql-client.*" "^mysql-common.*" || true + rm -f /etc/apt/sources.list.d/mysql.* /etc/apt/keyrings/mysql.gpg - local DISTRO_CODENAME - DISTRO_CODENAME="$(awk -F= '/VERSION_CODENAME/ { print $2 }' /etc/os-release)" - curl -fsSL https://repo.mysql.com/RPM-GPG-KEY-mysql-2023 | gpg --dearmor -o /etc/apt/trusted.gpg.d/mysql.gpg - echo "deb [signed-by=/etc/apt/trusted.gpg.d/mysql.gpg] https://repo.mysql.com/apt/${CURRENT_OS}/ ${DISTRO_CODENAME} mysql-${MYSQL_VERSION}" \ - >/etc/apt/sources.list.d/mysql.list + # Fallback logic for MySQL repos + local SUITE="$DISTRO_CODENAME" + if ! curl -fsSL "https://repo.mysql.com/apt/${DISTRO_ID}/dists/$DISTRO_CODENAME/Release" &>/dev/null; then + case "$DISTRO_ID" in + debian) + case "$DISTRO_CODENAME" in + trixie) SUITE="bookworm" ;; + *) SUITE="bookworm" ;; + esac + ;; + ubuntu) + case "$DISTRO_CODENAME" in + oracular | noble) SUITE="jammy" ;; + *) SUITE="jammy" ;; + esac + ;; + esac + msg_info "Using fallback suite: $SUITE (original: $DISTRO_CODENAME)" + fi + + curl -fsSL https://repo.mysql.com/RPM-GPG-KEY-mysql-2023 | gpg --dearmor -o /etc/apt/keyrings/mysql.gpg + + cat </etc/apt/sources.list.d/mysql.sources +Types: deb +URIs: https://repo.mysql.com/apt/${DISTRO_ID} +Suites: ${SUITE} +Components: mysql-${MYSQL_VERSION} +Architectures: amd64 arm64 +Signed-By: /etc/apt/keyrings/mysql.gpg +EOF export DEBIAN_FRONTEND=noninteractive - $STD apt-get update - $STD apt-get install -y mysql-server + $STD apt update + $STD apt install -y mysql-server msg_ok "Setup MySQL $MYSQL_VERSION" fi } @@ -1386,8 +1467,10 @@ function setup_nodejs() { local NODE_MODULE="${NODE_MODULE:-}" local CURRENT_NODE_VERSION="" local NEED_NODE_INSTALL=false + local DISTRO_ID DISTRO_CODENAME + DISTRO_ID=$(awk -F= '/^ID=/{print $2}' /etc/os-release | tr -d '"') + DISTRO_CODENAME=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release) - # Check if Node.js is already installed if command -v node >/dev/null; then CURRENT_NODE_VERSION="$(node -v | grep -oP '^v\K[0-9]+')" if [[ "$CURRENT_NODE_VERSION" != "$NODE_VERSION" ]]; then @@ -1400,102 +1483,101 @@ function setup_nodejs() { fi if ! command -v jq &>/dev/null; then - $STD apt-get update - $STD apt-get install -y jq || { + $STD apt update + $STD apt install -y jq || { msg_error "Failed to install jq" return 1 } fi - # Install Node.js if required if [[ "$NEED_NODE_INSTALL" == true ]]; then - $STD apt-get purge -y nodejs - rm -f /etc/apt/sources.list.d/nodesource.list /etc/apt/keyrings/nodesource.gpg + $STD apt purge -y nodejs + rm -f /etc/apt/sources.list.d/nodesource.* /etc/apt/keyrings/nodesource.gpg mkdir -p /etc/apt/keyrings if ! curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg; then msg_error "Failed to download or import NodeSource GPG key" - exit 1 + return 1 fi - echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_VERSION}.x nodistro main" \ - >/etc/apt/sources.list.d/nodesource.list + # NodeSource uses 'nodistro' for all distributions + cat </etc/apt/sources.list.d/nodesource.sources +Types: deb +URIs: https://deb.nodesource.com/node_${NODE_VERSION}.x +Suites: nodistro +Components: main +Architectures: amd64 arm64 +Signed-By: /etc/apt/keyrings/nodesource.gpg +EOF sleep 2 - if ! apt-get update >/dev/null 2>&1; then + if ! $STD apt update; then msg_warn "APT update failed – retrying in 5s" sleep 5 - if ! apt-get update >/dev/null 2>&1; then + if ! $STD apt update; then msg_error "Failed to update APT repositories after adding NodeSource" - exit 1 + return 1 fi fi - if ! apt-get install -y nodejs >/dev/null 2>&1; then + if ! $STD apt install -y nodejs; then msg_error "Failed to install Node.js ${NODE_VERSION} from NodeSource" - exit 1 + return 1 fi - # Update to latest npm $STD npm install -g npm@latest || { - msg_error "Failed to update npm to latest version" + msg_warn "Failed to update npm to latest version" } msg_ok "Setup Node.js ${NODE_VERSION}" fi export NODE_OPTIONS="--max-old-space-size=4096" - # Ensure valid working directory for npm (avoids uv_cwd error) if [[ ! -d /opt ]]; then mkdir -p /opt fi cd /opt || { msg_error "Failed to set safe working directory before npm install" - exit 1 + return 1 } - # Install global Node modules if [[ -n "$NODE_MODULE" ]]; then IFS=',' read -ra MODULES <<<"$NODE_MODULE" for mod in "${MODULES[@]}"; do local MODULE_NAME MODULE_REQ_VERSION MODULE_INSTALLED_VERSION if [[ "$mod" == @*/*@* ]]; then - # Scoped package with version, e.g. @vue/cli-service@latest MODULE_NAME="${mod%@*}" MODULE_REQ_VERSION="${mod##*@}" elif [[ "$mod" == *"@"* ]]; then - # Unscoped package with version, e.g. yarn@latest MODULE_NAME="${mod%@*}" MODULE_REQ_VERSION="${mod##*@}" else - # No version specified MODULE_NAME="$mod" MODULE_REQ_VERSION="latest" fi - # Check if the module is already installed if npm list -g --depth=0 "$MODULE_NAME" >/dev/null 2>&1; then MODULE_INSTALLED_VERSION="$(npm list -g --depth=0 "$MODULE_NAME" | grep "$MODULE_NAME@" | awk -F@ '{print $2}' | tr -d '[:space:]')" if [[ "$MODULE_REQ_VERSION" != "latest" && "$MODULE_REQ_VERSION" != "$MODULE_INSTALLED_VERSION" ]]; then msg_info "Updating $MODULE_NAME from v$MODULE_INSTALLED_VERSION to v$MODULE_REQ_VERSION" if ! $STD npm install -g "${MODULE_NAME}@${MODULE_REQ_VERSION}"; then msg_error "Failed to update $MODULE_NAME to version $MODULE_REQ_VERSION" - exit 1 + return 1 fi elif [[ "$MODULE_REQ_VERSION" == "latest" ]]; then msg_info "Updating $MODULE_NAME to latest version" if ! $STD npm install -g "${MODULE_NAME}@latest"; then msg_error "Failed to update $MODULE_NAME to latest version" - exit 1 + return 1 fi fi else msg_info "Installing $MODULE_NAME@$MODULE_REQ_VERSION" if ! $STD npm install -g "${MODULE_NAME}@${MODULE_REQ_VERSION}"; then msg_error "Failed to install $MODULE_NAME@$MODULE_REQ_VERSION" - exit 1 + return 1 fi fi done @@ -1527,8 +1609,9 @@ function setup_php() { local PHP_MODULE="${PHP_MODULE:-}" local PHP_APACHE="${PHP_APACHE:-NO}" local PHP_FPM="${PHP_FPM:-NO}" - local DISTRO_CODENAME - DISTRO_CODENAME=$(awk -F= '/VERSION_CODENAME/ { print $2 }' /etc/os-release) + local DISTRO_ID DISTRO_CODENAME + DISTRO_ID=$(awk -F= '/^ID=/{print $2}' /etc/os-release | tr -d '"') + DISTRO_CODENAME=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release) local DEFAULT_MODULES="bcmath,cli,curl,gd,intl,mbstring,opcache,readline,xml,zip" local COMBINED_MODULES @@ -1558,16 +1641,43 @@ function setup_php() { msg_info "Setup PHP $PHP_VERSION" elif [[ "$CURRENT_PHP" != "$PHP_VERSION" ]]; then msg_info "Old PHP $CURRENT_PHP detected, Setup new PHP $PHP_VERSION" - $STD apt-get purge -y "php${CURRENT_PHP//./}"* || true + $STD apt purge -y "php${CURRENT_PHP//./}"* || true fi # Ensure Sury repo is available - if [[ ! -f /etc/apt/sources.list.d/php.list ]]; then + if [[ ! -f /etc/apt/sources.list.d/php.sources ]]; then $STD curl -fsSLo /tmp/debsuryorg-archive-keyring.deb https://packages.sury.org/debsuryorg-archive-keyring.deb $STD dpkg -i /tmp/debsuryorg-archive-keyring.deb - echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ ${DISTRO_CODENAME} main" \ - >/etc/apt/sources.list.d/php.list - $STD apt-get update + + # Fallback logic for PHP repos + local SUITE="$DISTRO_CODENAME" + if ! curl -fsSL "https://packages.sury.org/php/dists/$DISTRO_CODENAME/Release" &>/dev/null; then + case "$DISTRO_ID" in + debian) + case "$DISTRO_CODENAME" in + trixie) SUITE="bookworm" ;; + *) SUITE="bookworm" ;; + esac + ;; + ubuntu) + case "$DISTRO_CODENAME" in + oracular | noble) SUITE="jammy" ;; + *) SUITE="jammy" ;; + esac + ;; + esac + msg_info "Using fallback suite: $SUITE (original: $DISTRO_CODENAME)" + fi + + cat </etc/apt/sources.list.d/php.sources +Types: deb +URIs: https://packages.sury.org/php/ +Suites: $SUITE +Components: main +Architectures: amd64 arm64 +Signed-By: /usr/share/keyrings/deb.sury.org-php.gpg +EOF + $STD apt update fi # Build module list @@ -1588,14 +1698,14 @@ function setup_php() { if [[ "$PHP_APACHE" == "YES" ]]; then if ! dpkg -l | grep -q "libapache2-mod-php${PHP_VERSION}"; then msg_info "Installing Apache with PHP${PHP_VERSION} support" - $STD apt-get install -y apache2 libapache2-mod-php${PHP_VERSION} + $STD apt install -y apache2 libapache2-mod-php${PHP_VERSION} else msg_info "Apache with PHP${PHP_VERSION} already installed – skipping install" fi fi # setup / update PHP modules - $STD apt-get install -y $MODULE_LIST + $STD apt install -y $MODULE_LIST msg_ok "Setup PHP $PHP_VERSION" # optional stop old PHP-FPM service @@ -1610,12 +1720,12 @@ function setup_php() { [[ "$PHP_APACHE" == "YES" ]] && PHP_INI_PATHS+=("/etc/php/${PHP_VERSION}/apache2/php.ini") for ini in "${PHP_INI_PATHS[@]}"; do if [[ -f "$ini" ]]; then - $STD msg_info "Patching $ini" + msg_info "Patching $ini" sed -i "s|^memory_limit = .*|memory_limit = ${PHP_MEMORY_LIMIT}|" "$ini" sed -i "s|^upload_max_filesize = .*|upload_max_filesize = ${PHP_UPLOAD_MAX_FILESIZE}|" "$ini" sed -i "s|^post_max_size = .*|post_max_size = ${PHP_POST_MAX_SIZE}|" "$ini" sed -i "s|^max_execution_time = .*|max_execution_time = ${PHP_MAX_EXECUTION_TIME}|" "$ini" - $STD msg_ok "Patched $ini" + msg_ok "Patched $ini" fi done @@ -1660,60 +1770,85 @@ function setup_postgresql() { local PG_VERSION="${PG_VERSION:-16}" local PG_MODULES="${PG_MODULES:-}" local CURRENT_PG_VERSION="" - local DISTRO + local DISTRO_ID DISTRO_CODENAME local NEED_PG_INSTALL=false - DISTRO="$(awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release)" + DISTRO_ID=$(awk -F= '/^ID=/{print $2}' /etc/os-release | tr -d '"') + DISTRO_CODENAME=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release) if command -v psql >/dev/null; then CURRENT_PG_VERSION="$(psql -V | awk '{print $3}' | cut -d. -f1)" if [[ "$CURRENT_PG_VERSION" == "$PG_VERSION" ]]; then - : # PostgreSQL is already at the desired version – no action needed + : # PostgreSQL is already at the desired version else - $STD msg_info "Detected PostgreSQL $CURRENT_PG_VERSION, preparing upgrade to $PG_VERSION" + msg_info "Detected PostgreSQL $CURRENT_PG_VERSION, preparing upgrade to $PG_VERSION" NEED_PG_INSTALL=true fi else - NEED_PG_INSTALL=true fi if [[ "$NEED_PG_INSTALL" == true ]]; then if [[ -n "$CURRENT_PG_VERSION" ]]; then - $STD msg_info "Dumping PostgreSQL $CURRENT_PG_VERSION data" + msg_info "Dumping PostgreSQL $CURRENT_PG_VERSION data" su - postgres -c "pg_dumpall > /var/lib/postgresql/backup_$(date +%F)_v${CURRENT_PG_VERSION}.sql" - $STD msg_ok "Data dump completed" - + msg_ok "Data dump completed" systemctl stop postgresql fi - rm -f /etc/apt/sources.list.d/pgdg.list /etc/apt/trusted.gpg.d/postgresql.gpg + rm -f /etc/apt/sources.list.d/pgdg.* /etc/apt/keyrings/postgresql.gpg - $STD msg_info "Adding PostgreSQL PGDG repository" + msg_info "Adding PostgreSQL PGDG repository" curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | - gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg + gpg --dearmor -o /etc/apt/keyrings/postgresql.gpg - echo "deb https://apt.postgresql.org/pub/repos/apt ${DISTRO}-pgdg main" \ - >/etc/apt/sources.list.d/pgdg.list + # Fallback logic for PostgreSQL repos + local SUITE="$DISTRO_CODENAME" + if ! curl -fsSL "https://apt.postgresql.org/pub/repos/apt/dists/${DISTRO_CODENAME}-pgdg/Release" &>/dev/null; then + case "$DISTRO_ID" in + debian) + case "$DISTRO_CODENAME" in + trixie) SUITE="bookworm" ;; + *) SUITE="bookworm" ;; + esac + ;; + ubuntu) + case "$DISTRO_CODENAME" in + oracular | noble) SUITE="jammy" ;; + *) SUITE="jammy" ;; + esac + ;; + esac + msg_info "Using fallback suite: $SUITE (original: $DISTRO_CODENAME)" + fi - $STD apt-get update - $STD msg_ok "Repository added" + cat </etc/apt/sources.list.d/pgdg.sources +Types: deb +URIs: https://apt.postgresql.org/pub/repos/apt +Suites: ${SUITE}-pgdg +Components: main +Architectures: amd64 arm64 +Signed-By: /etc/apt/keyrings/postgresql.gpg +EOF + + $STD apt update + msg_ok "Repository added" msg_info "Setup PostgreSQL $PG_VERSION" - $STD apt-get install -y "postgresql-${PG_VERSION}" "postgresql-client-${PG_VERSION}" + $STD apt install -y "postgresql-${PG_VERSION}" "postgresql-client-${PG_VERSION}" if [[ -n "$CURRENT_PG_VERSION" ]]; then - $STD apt-get purge -y "postgresql-${CURRENT_PG_VERSION}" "postgresql-client-${CURRENT_PG_VERSION}" || true + $STD apt purge -y "postgresql-${CURRENT_PG_VERSION}" "postgresql-client-${CURRENT_PG_VERSION}" || true fi systemctl enable -q --now postgresql if [[ -n "$CURRENT_PG_VERSION" ]]; then - $STD msg_info "Restoring dumped data" + msg_info "Restoring dumped data" su - postgres -c "psql < /var/lib/postgresql/backup_$(date +%F)_v${CURRENT_PG_VERSION}.sql" - $STD msg_ok "Data restored" + msg_ok "Data restored" fi - $STD msg_ok "PostgreSQL $PG_VERSION installed" + msg_ok "PostgreSQL $PG_VERSION installed" fi # Install optional PostgreSQL modules @@ -1721,13 +1856,13 @@ function setup_postgresql() { IFS=',' read -ra MODULES <<<"$PG_MODULES" for module in "${MODULES[@]}"; do local pkg="postgresql-${PG_VERSION}-${module}" - $STD msg_info "Setup PostgreSQL module/s: $pkg" - $STD apt-get install -y "$pkg" || { + msg_info "Setup PostgreSQL module/s: $pkg" + $STD apt install -y "$pkg" || { msg_error "Failed to install $pkg" continue } done - $STD msg_ok "Setup PostgreSQL modules" + msg_ok "Setup PostgreSQL modules" fi } @@ -1801,7 +1936,7 @@ function setup_ruby() { if [[ "$RUBY_INSTALL_RAILS" == "true" ]]; then msg_info "Setup Rails via gem" - gem install rails + $STD gem install rails msg_ok "Setup Rails $(rails -v)" fi @@ -2013,8 +2148,8 @@ function setup_yq() { local GITHUB_REPO="mikefarah/yq" if ! command -v jq &>/dev/null; then - $STD apt-get update - $STD apt-get install -y jq || { + $STD apt update + $STD apt install -y jq || { msg_error "Failed to install jq" rm -rf "$TMP_DIR" return 1