# Copyright (c) 2021-2025 community-scripts ORG # Author: michelroegl-brunner # License: MIT | https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/LICENSE colors() { YW=$(echo "\033[33m") BL=$(echo "\033[36m") RD=$(echo "\033[01;31m") BGN=$(echo "\033[4;92m") GN=$(echo "\033[1;92m") DGN=$(echo "\033[32m") CL=$(echo "\033[m") CL=$(echo "\033[m") BOLD=$(echo "\033[1m") BFR="\\r\\033[K" HOLD=" " TAB=" " CM="${TAB}✔️${TAB}${CL}" CROSS="${TAB}✖️${TAB}${CL}" INFO="${TAB}💡${TAB}${CL}" OS="${TAB}🖥️${TAB}${CL}" CONTAINERTYPE="${TAB}📦${TAB}${CL}" DISKSIZE="${TAB}💾${TAB}${CL}" CPUCORE="${TAB}🧠${TAB}${CL}" RAMSIZE="${TAB}🛠️${TAB}${CL}" CONTAINERID="${TAB}🆔${TAB}${CL}" HOSTNAME="${TAB}🏠${TAB}${CL}" BRIDGE="${TAB}🌉${TAB}${CL}" GATEWAY="${TAB}🌐${TAB}${CL}" DEFAULT="${TAB}⚙️${TAB}${CL}" MACADDRESS="${TAB}🔗${TAB}${CL}" VLANTAG="${TAB}🏷️${TAB}${CL}" CREATING="${TAB}🚀${TAB}${CL}" ADVANCED="${TAB}🧩${TAB}${CL}" } start_spinner() { local msg="$1" local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏') local spin_i=0 local interval=0.1 local term_width=$(tput cols) { while [ "${SPINNER_ACTIVE:-1}" -eq 1 ]; do printf "\r\e[2K${frames[spin_i]} ${YW}%b${CL}" "$msg" >&2 spin_i=$(((spin_i + 1) % ${#frames[@]})) sleep "$interval" done } & SPINNER_PID=$! } msg_info() { local msg="$1" if [ "${SPINNER_ACTIVE:-0}" -eq 1 ]; then return fi SPINNER_ACTIVE=1 start_spinner "$msg" } msg_ok() { if [ -n "${SPINNER_PID:-}" ] && ps -p "$SPINNER_PID" >/dev/null 2>&1; then kill "$SPINNER_PID" >/dev/null 2>&1 wait "$SPINNER_PID" 2>/dev/null || true fi local msg="$1" printf "\r\e[2K${CM}${GN}%b${CL}\n" "$msg" >&2 unset SPINNER_PID SPINNER_ACTIVE=0 log_message "OK" "$msg" } msg_error() { if [ -n "${SPINNER_PID:-}" ] && ps -p "$SPINNER_PID" >/dev/null 2>&1; then kill "$SPINNER_PID" >/dev/null 2>&1 wait "$SPINNER_PID" 2>/dev/null || true fi local msg="$1" printf "\r\e[2K${CROSS}${RD}%b${CL}\n" "$msg" >&2 unset SPINNER_PID SPINNER_ACTIVE=0 log_message "ERROR" "$msg" } root_check() { if [[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]; then clear msg_error "Please run this script as root." echo -e "\nExiting..." sleep 2 exit fi } pve_check() { if ! pveversion | grep -Eq "pve-manager/8\.[1-3](\.[0-9]+)*"; then msg_error "${CROSS}${RD}This version of Proxmox Virtual Environment is not supported" echo -e "Requires Proxmox Virtual Environment Version 8.1 or later." echo -e "Exiting..." sleep 2 exit fi } arch_check() { if [ "$(dpkg --print-architecture)" != "amd64" ]; then echo -e "\n ${INFO}${YWB}This script will not work with PiMox! \n" echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n" echo -e "Exiting..." sleep 2 exit fi } ssh_check() { if command -v pveversion >/dev/null 2>&1; then if [ -n "${SSH_CLIENT:+x}" ]; then if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH DETECTED" --yesno "It's suggested to use the Proxmox shell instead of SSH, since SSH can create issues while gathering variables. Would you like to proceed with using SSH?" 10 62; then echo "you've been warned" else clear exit fi fi fi } start_script() { if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "SETTINGS" --yesno "Use Default Settings?" --no-button Advanced 10 58); then header_info echo -e "${DEFAULT}${BOLD}${BL}Using Default Settings${CL}" default_settings else header_info echo -e "${ADVANCED}${BOLD}${RD}Using Advanced Settings${CL}" advanced_settings fi } exit-script() { clear echo -e "\n${CROSS}${RD}User exited script${CL}\n" exit } install_node_and_modules() { local NODE_VERSION="${NODE_VERSION:-22}" local NODE_MODULE="${NODE_MODULE:-}" local CURRENT_NODE_VERSION="" local NEED_NODE_INSTALL=false 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 msg_info "Node.js Version $CURRENT_NODE_VERSION found, replacing with $NODE_VERSION" NEED_NODE_INSTALL=true fi else msg_info "Node.js not found, installing version $NODE_VERSION" NEED_NODE_INSTALL=true fi if [[ "$NEED_NODE_INSTALL" == true ]]; then $STD apt-get purge -y nodejs rm -f /etc/apt/sources.list.d/nodesource.list rm -f /etc/apt/keyrings/nodesource.gpg mkdir -p /etc/apt/keyrings curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | \ gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg 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 $STD apt-get update $STD apt-get install -y nodejs msg_ok "Installed Node.js ${NODE_VERSION}" fi 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 MODULE_NAME="${mod%@*}" MODULE_REQ_VERSION="${mod#*@}" else MODULE_NAME="$mod" MODULE_REQ_VERSION="latest" fi 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" $STD npm install -g "${MODULE_NAME}@${MODULE_REQ_VERSION}" elif [[ "$MODULE_REQ_VERSION" == "latest" ]]; then msg_info "Updating $MODULE_NAME to latest version" $STD npm install -g "${MODULE_NAME}@latest" else msg_ok "$MODULE_NAME@$MODULE_INSTALLED_VERSION already installed" fi else msg_info "Installing $MODULE_NAME@$MODULE_REQ_VERSION" $STD npm install -g "${MODULE_NAME}@${MODULE_REQ_VERSION}" fi done msg_ok "Node Modules processed" fi } function install_postgresql() { local PG_VERSION="${PG_VERSION:-15}" local CURRENT_PG_VERSION="" local DISTRO local NEED_PG_INSTALL=false DISTRO="$(awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release)" if command -v psql >/dev/null; then CURRENT_PG_VERSION="$(psql -V | grep -oP '\s\K[0-9]+(?=\.)')" if [[ "$CURRENT_PG_VERSION" != "$PG_VERSION" ]]; then msg_info "PostgreSQL Version $CURRENT_PG_VERSION found, replacing with $PG_VERSION" NEED_PG_INSTALL=true fi else msg_info "PostgreSQL not found, installing version $PG_VERSION" NEED_PG_INSTALL=true fi if [[ "$NEED_PG_INSTALL" == true ]]; then msg_info "Stopping PostgreSQL if running" systemctl stop postgresql >/dev/null 2>&1 || true msg_info "Removing conflicting PostgreSQL packages" $STD apt-get purge -y "postgresql*" rm -f /etc/apt/sources.list.d/pgdg.list /etc/apt/trusted.gpg.d/postgresql.gpg msg_info "Setting up PostgreSQL Repository" curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | \ gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg echo "deb https://apt.postgresql.org/pub/repos/apt ${DISTRO}-pgdg main" \ > /etc/apt/sources.list.d/pgdg.list $STD apt-get update $STD apt-get install -y "postgresql-${PG_VERSION}" msg_ok "Installed PostgreSQL ${PG_VERSION}" fi } function install_mariadb() { local MARIADB_VERSION="${MARIADB_VERSION:-10.11}" local CURRENT_VERSION="" local NEED_INSTALL=false if command -v mariadb >/dev/null; then CURRENT_VERSION="$(mariadb --version | grep -oP 'Ver\s+\K[0-9]+\.[0-9]+')" if [[ "$CURRENT_VERSION" != "$MARIADB_VERSION" ]]; then msg_info "MariaDB $CURRENT_VERSION found, replacing with $MARIADB_VERSION" NEED_INSTALL=true else msg_ok "MariaDB $MARIADB_VERSION already installed" fi else msg_info "MariaDB not found, installing version $MARIADB_VERSION" NEED_INSTALL=true fi if [[ "$NEED_INSTALL" == true ]]; then msg_info "Removing conflicting MariaDB packages" $STD systemctl stop mariadb >/dev/null 2>&1 || true $STD apt-get purge -y 'mariadb*' rm -f /etc/apt/sources.list.d/mariadb.list /etc/apt/trusted.gpg.d/mariadb.gpg msg_info "Setting up MariaDB Repository" curl -fsSL "https://mariadb.org/mariadb_release_signing_key.asc" | gpg --dearmor -o /etc/apt/trusted.gpg.d/mariadb.gpg DISTRO_CODENAME="$(awk -F= '/VERSION_CODENAME/ { print $2 }' /etc/os-release)" echo "deb [signed-by=/etc/apt/trusted.gpg.d/mariadb.gpg] http://mirror.mariadb.org/repo/${MARIADB_VERSION}/debian ${DISTRO_CODENAME} main" \ > /etc/apt/sources.list.d/mariadb.list $STD apt-get update $STD apt-get install -y mariadb-server mariadb-client msg_ok "Installed MariaDB $MARIADB_VERSION" fi } function install_mysql() { local MYSQL_VERSION="${MYSQL_VERSION:-8.0}" local CURRENT_VERSION="" local NEED_INSTALL=false if command -v mysql >/dev/null; then CURRENT_VERSION="$(mysql --version | grep -oP 'Distrib\s+\K[0-9]+\.[0-9]+')" if [[ "$CURRENT_VERSION" != "$MYSQL_VERSION" ]]; then msg_info "MySQL $CURRENT_VERSION found, replacing with $MYSQL_VERSION" NEED_INSTALL=true else msg_ok "MySQL $MYSQL_VERSION already installed" fi else msg_info "MySQL not found, installing version $MYSQL_VERSION" NEED_INSTALL=true fi if [[ "$NEED_INSTALL" == true ]]; then msg_info "Removing conflicting MySQL packages" $STD systemctl stop mysql >/dev/null 2>&1 || true $STD apt-get purge -y 'mysql*' rm -f /etc/apt/sources.list.d/mysql.list /etc/apt/trusted.gpg.d/mysql.gpg msg_info "Setting up MySQL APT Repository" DISTRO_CODENAME="$(awk -F= '/VERSION_CODENAME/ { print $2 }' /etc/os-release)" curl -fsSL https://repo.mysql.com/RPM-GPG-KEY-mysql-2022 | 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/debian/ ${DISTRO_CODENAME} mysql-${MYSQL_VERSION}" \ > /etc/apt/sources.list.d/mysql.list $STD apt-get update $STD apt-get install -y mysql-server msg_ok "Installed MySQL $MYSQL_VERSION" fi }