diff --git a/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.md b/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.md index 7c527b7b6..2da3018e1 100644 --- a/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.md +++ b/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.md @@ -107,13 +107,13 @@ Example: ```bash APP="SnipeIT" -var_tags="asset-management;foss" -var_cpu="2" -var_ram="2048" -var_disk="4" -var_os="debian" -var_version="12" -var_unprivileged="1" +var_tags="${var_tags:-asset-management;foss}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-2048}" +var_disk="${var_disk:-4}" +var_os="${var_os:-debian}" +var_version="${var_version:-12}" +var_unprivileged="${var_unprivileged:-1}" ``` ## 2.2 **📋 App output & base settings** diff --git a/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.sh b/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.sh index 066a1c5f9..ea59e7e6e 100644 --- a/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.sh +++ b/.github/CONTRIBUTOR_AND_GUIDES/ct/AppName.sh @@ -6,22 +6,22 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV # Source: [SOURCE_URL] # App Default Values -APP="[APP_NAME]" # Name of the app (e.g. Google, Adventurelog, Apache-Guacamole" -var_tags="[TAGS]" +APP="[APP_NAME]" # Tags for Proxmox VE, maximum 2 pcs., no spaces allowed, separated by a semicolon ; (e.g. database | adblock;dhcp) -var_cpu="[CPU]" +var_tags="${var_tags:-[TAGS]}" # Number of cores (1-X) (e.g. 4) - default are 2 -var_ram="[RAM]" +var_cpu="${var_cpu:-[CPU]}" # Amount of used RAM in MB (e.g. 2048 or 4096) -var_disk="[DISK]" +var_ram="${var_ram:-[RAM]}" # Amount of used disk space in GB (e.g. 4 or 10) -var_os="[OS]" +var_disk="${var_disk:-[DISK]}" # Default OS (e.g. debian, ubuntu, alpine) -var_version="[VERSION]" +var_os="${var_os:-[OS]}" # Default OS version (e.g. 12 for debian, 24.04 for ubuntu, 3.20 for alpine) -var_unprivileged="[UNPRIVILEGED]" +var_version="${var_version:-[VERSION]}" # 1 = unprivileged container, 0 = privileged container +var_unprivileged="${var_unprivileged:-[UNPRIVILEGED]}" header_info "$APP" variables @@ -29,51 +29,51 @@ color catch_errors function update_script() { - header_info - check_container_storage - check_container_resources + header_info + check_container_storage + check_container_resources - # Check if installation is present | -f for file, -d for folder - if [[ ! -f [INSTALLATION_CHECK_PATH] ]]; then - msg_error "No ${APP} Installation Found!" - exit - fi - - # Crawling the new version and checking whether an update is required - RELEASE=$(curl -fsSL [RELEASE_URL] | [PARSE_RELEASE_COMMAND]) - if [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]] || [[ ! -f /opt/${APP}_version.txt ]]; then - # Stopping Services - msg_info "Stopping $APP" - systemctl stop [SERVICE_NAME] - msg_ok "Stopped $APP" - - # Creating Backup - msg_info "Creating Backup" - tar -czf "/opt/${APP}_backup_$(date +%F).tar.gz" [IMPORTANT_PATHS] - msg_ok "Backup Created" - - # Execute Update - msg_info "Updating $APP to v${RELEASE}" - [UPDATE_COMMANDS] - msg_ok "Updated $APP to v${RELEASE}" - - # Starting Services - msg_info "Starting $APP" - systemctl start [SERVICE_NAME] - msg_ok "Started $APP" - - # Cleaning up - msg_info "Cleaning Up" - rm -rf [TEMP_FILES] - msg_ok "Cleanup Completed" - - # Last Action - echo "${RELEASE}" >/opt/${APP}_version.txt - msg_ok "Update Successful" - else - msg_ok "No update required. ${APP} is already at v${RELEASE}" - fi + # Check if installation is present | -f for file, -d for folder + if [[ ! -f [INSTALLATION_CHECK_PATH] ]]; then + msg_error "No ${APP} Installation Found!" exit + fi + + # Crawling the new version and checking whether an update is required + RELEASE=$(curl -fsSL [RELEASE_URL] | [PARSE_RELEASE_COMMAND]) + if [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]] || [[ ! -f /opt/${APP}_version.txt ]]; then + # Stopping Services + msg_info "Stopping $APP" + systemctl stop [SERVICE_NAME] + msg_ok "Stopped $APP" + + # Creating Backup + msg_info "Creating Backup" + tar -czf "/opt/${APP}_backup_$(date +%F).tar.gz" [IMPORTANT_PATHS] + msg_ok "Backup Created" + + # Execute Update + msg_info "Updating $APP to v${RELEASE}" + [UPDATE_COMMANDS] + msg_ok "Updated $APP to v${RELEASE}" + + # Starting Services + msg_info "Starting $APP" + systemctl start [SERVICE_NAME] + msg_ok "Started $APP" + + # Cleaning up + msg_info "Cleaning Up" + rm -rf [TEMP_FILES] + msg_ok "Cleanup Completed" + + # Last Action + echo "${RELEASE}" >/opt/${APP}_version.txt + msg_ok "Update Successful" + else + msg_ok "No update required. ${APP} is already at v${RELEASE}" + fi + exit } start @@ -83,4 +83,4 @@ description msg_ok "Completed Successfully!\n" echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:[PORT]${CL}" \ No newline at end of file +echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:[PORT]${CL}" diff --git a/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.md b/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.md index 241cd99ac..51091093a 100644 --- a/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.md +++ b/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.md @@ -67,6 +67,7 @@ Example: > > - Add your username > - When updating/reworking scripts, add "| Co-Author [YourUserName]" +> - Source is a URL of github repo containting source files of the application you're installing (not URL of your homepage or a blog) ### 1.3 **Variables and function import** @@ -110,11 +111,8 @@ Example: ```bash $STD apt-get install -y \ - curl \ composer \ git \ - sudo \ - mc \ nginx ``` @@ -154,7 +152,7 @@ Example for a git release: ```bash RELEASE=$(curl -fsSL https://api.github.com/repos/snipe/snipe-it/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }') -wget -q "https://github.com/snipe/snipe-it/archive/refs/tags/v${RELEASE}.zip" +curl -fsSL "https://github.com/snipe/snipe-it/archive/refs/tags/v${RELEASE}.zip" -o "v${RELEASE}.zip" ``` ### 5.2 **Save the version for update checks** @@ -165,7 +163,7 @@ wget -q "https://github.com/snipe/snipe-it/archive/refs/tags/v${RELEASE}.zip" Example: ```bash -echo "${RELEASE}" >"/opt/AppName_version.txt" +echo "${RELEASE}" >/opt/${APPLICATION}_version.txt ``` --- @@ -177,6 +175,7 @@ echo "${RELEASE}" >"/opt/AppName_version.txt" - Use standard functions like `msg_info`, `msg_ok` or `msg_error` to print status messages. - Each `msg_info` must be followed with a `msg_ok` before any other output is made. - Display meaningful progress messages at key stages. +- Taking user input with `read -p` must be outside of `msg_info`...`msg_ok` code block Example: @@ -184,6 +183,8 @@ Example: msg_info "Installing Dependencies" $STD apt-get install -y ... msg_ok "Installed Dependencies" + +read -p "${TAB3}Do you wish to enable HTTPS mode? (y/N): " httpschoice ``` ### 6.2 **Verbosity** diff --git a/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.sh b/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.sh index fe506913a..4748ab267 100644 --- a/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.sh +++ b/.github/CONTRIBUTOR_AND_GUIDES/install/AppName-install.sh @@ -6,7 +6,7 @@ # Source: [SOURCE_URL] # Import Functions und Setup -source /dev/stdin <<< "$FUNCTIONS_FILE_PATH" +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" color verb_ip6 catch_errors @@ -34,30 +34,28 @@ $STD mysql -u root -e "CREATE DATABASE $DB_NAME;" $STD mysql -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');" $STD mysql -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;" { - echo "${APPLICATION} Credentials" - echo "Database User: $DB_USER" - echo "Database Password: $DB_PASS" - echo "Database Name: $DB_NAME" -} >> ~/$APP_NAME.creds + echo "${APPLICATION} Credentials" + echo "Database User: $DB_USER" + echo "Database Password: $DB_PASS" + echo "Database Name: $DB_NAME" +} >>~/"$APP_NAME".creds msg_ok "Set up Database" -# Temp - # Setup App msg_info "Setup ${APPLICATION}" RELEASE=$(curl -fsSL https://api.github.com/repos/[REPO]/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }') curl -fsSL -o "${RELEASE}.zip" "https://github.com/[REPO]/archive/refs/tags/${RELEASE}.zip" unzip -q "${RELEASE}.zip" mv "${APPLICATION}-${RELEASE}/" "/opt/${APPLICATION}" -# -# # -echo "${RELEASE}" >/opt/${APPLICATION}_version.txt +# +# +echo "${RELEASE}" >/opt/"${APPLICATION}"_version.txt msg_ok "Setup ${APPLICATION}" # Creating Service (if needed) msg_info "Creating Service" -cat </etc/systemd/system/${APPLICATION}.service +cat </etc/systemd/system/"${APPLICATION}".service [Unit] Description=${APPLICATION} Service After=network.target @@ -69,7 +67,7 @@ Restart=always [Install] WantedBy=multi-user.target EOF -systemctl enable -q --now ${APPLICATION} +systemctl enable -q --now "${APPLICATION}" msg_ok "Created Service" motd_ssh @@ -77,7 +75,7 @@ customize # Cleanup msg_info "Cleaning up" -rm -f ${RELEASE}.zip +rm -f "${RELEASE}".zip $STD apt-get -y autoremove $STD apt-get -y autoclean -msg_ok "Cleaned" \ No newline at end of file +msg_ok "Cleaned" diff --git a/CHANGELOG.md b/CHANGELOG.md index 677fcb368..e66f93a24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,8 +14,65 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit All LXC instances created using this repository come pre-installed with Midnight Commander, which is a command-line tool (`mc`) that offers a user-friendly file and directory management interface for the terminal environment. +## 2025-05-19 + +## 2025-05-18 + +### 🚀 Updated Scripts + + - tools.func - Add function to create self-signed certificates [@tremor021](https://github.com/tremor021) ([#4562](https://github.com/community-scripts/ProxmoxVE/pull/4562)) + + - #### 🐞 Bug Fixes + + - Homarr: fix the build [@CrazyWolf13](https://github.com/CrazyWolf13) ([#4569](https://github.com/community-scripts/ProxmoxVE/pull/4569)) + +### 🌐 Website + + - #### 📝 Script Information + + - Fix Dashy Config Path on Frontend [@CrazyWolf13](https://github.com/CrazyWolf13) ([#4570](https://github.com/community-scripts/ProxmoxVE/pull/4570)) + +## 2025-05-17 + +## 2025-05-16 + +### 🧰 Maintenance + + - #### 💾 Core + + - [core] Refactor Config File function [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#4528](https://github.com/community-scripts/ProxmoxVE/pull/4528)) + - [core] Fix Bridge detection in Advanced Mode [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#4522](https://github.com/community-scripts/ProxmoxVE/pull/4522)) + - [core] Enable SSH_KEY and SSH without password [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#4523](https://github.com/community-scripts/ProxmoxVE/pull/4523)) + + - #### 📂 Github + + - Updates to contributor docs/guide [@tremor021](https://github.com/tremor021) ([#4518](https://github.com/community-scripts/ProxmoxVE/pull/4518)) + +### 🌐 Website + + - Remove bolt.diy script [@tremor021](https://github.com/tremor021) ([#4541](https://github.com/community-scripts/ProxmoxVE/pull/4541)) + ## 2025-05-15 +### 🆕 New Scripts + + - bitmagnet ([#4493](https://github.com/community-scripts/ProxmoxVE/pull/4493)) + +### 🚀 Updated Scripts + + - core: Add TAB3 formatting var to core [@tremor021](https://github.com/tremor021) ([#4496](https://github.com/community-scripts/ProxmoxVE/pull/4496)) +- Update scripts that use "read -p" to properly indent text [@tremor021](https://github.com/tremor021) ([#4498](https://github.com/community-scripts/ProxmoxVE/pull/4498)) + + - #### ✨ New Features + + - tools.func: fix some things & add ruby default function [@MickLesk](https://github.com/MickLesk) ([#4507](https://github.com/community-scripts/ProxmoxVE/pull/4507)) + +### 🧰 Maintenance + + - #### 💾 Core + + - core: fix bridge detection for OVS [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#4495](https://github.com/community-scripts/ProxmoxVE/pull/4495)) + ## 2025-05-14 ### 🆕 New Scripts diff --git a/ct/alpine-bitmagnet.sh b/ct/alpine-bitmagnet.sh new file mode 100644 index 000000000..0b69962d6 --- /dev/null +++ b/ct/alpine-bitmagnet.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) +# Copyright (c) 2021-2025 community-scripts ORG +# Author: Slaviša Arežina (tremor021) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/bitmagnet-io/bitmagnet + +APP="Alpine-bitmagnet" +var_tags="${var_tags:-alpine;torrent}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-1024}" +var_disk="${var_disk:-3}" +var_os="${var_os:-alpine}" +var_version="${var_version:-3.21}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + + if [[ ! -d /opt/bitmagnet ]]; then + msg_error "No ${APP} Installation Found!" + exit 1 + fi + RELEASE=$(curl -fsSL https://api.github.com/repos/bitmagnet-io/bitmagnet/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }') + if [ "${RELEASE}" != "$(cat /opt/bitmagnet_version.txt)" ] || [ ! -f /opt/bitmagnet_version.txt ]; then + msg_info "Backing up database" + rm -f /tmp/backup.sql + $STD sudo -u postgres pg_dump \ + --column-inserts \ + --data-only \ + --on-conflict-do-nothing \ + --rows-per-insert=1000 \ + --table=metadata_sources \ + --table=content \ + --table=content_attributes \ + --table=content_collections \ + --table=content_collections_content \ + --table=torrent_sources \ + --table=torrents \ + --table=torrent_files \ + --table=torrent_hints \ + --table=torrent_contents \ + --table=torrent_tags \ + --table=torrents_torrent_sources \ + --table=key_values \ + bitmagnet \ + >/tmp/backup.sql + mv /tmp/backup.sql /opt/ + msg_ok "Database backed up" + + msg_info "Updating ${APP} from $(cat /opt/bitmagnet_version.txt) to ${RELEASE}" + $STD apk -U upgrade + $STD service bitmagnet stop + [ -f /opt/bitmagnet/.env ] && cp /opt/bitmagnet/.env /opt/ + [ -f /opt/bitmagnet/config.yml ] && cp /opt/bitmagnet/config.yml /opt/ + rm -rf /opt/bitmagnet/* + temp_file=$(mktemp) + curl -fsSL "https://github.com/bitmagnet-io/bitmagnet/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file" + tar zxf "$temp_file" --strip-components=1 -C /opt/bitmagnet + cd /opt/bitmagnet + VREL=v$RELEASE + $STD go build -ldflags "-s -w -X github.com/bitmagnet-io/bitmagnet/internal/version.GitTag=$VREL" + chmod +x bitmagnet + [ -f "/opt/.env" ] && cp "/opt/.env" /opt/bitmagnet/ + [ -f "/opt/config.yml" ] && cp "/opt/config.yml" /opt/bitmagnet/ + rm -f "$temp_file" + echo "${RELEASE}" >/opt/bitmagnet_version.txt + $STD service bitmagnet start + msg_ok "Updated Successfully" + else + msg_ok "No update required. ${APP} is already at ${RELEASE}" + fi + + exit 0 +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW} Access it using the following IP:${CL}" +echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3333${CL}" diff --git a/ct/bitmagnet.sh b/ct/bitmagnet.sh new file mode 100644 index 000000000..f0012ebb1 --- /dev/null +++ b/ct/bitmagnet.sh @@ -0,0 +1,98 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) +# Copyright (c) 2021-2025 community-scripts ORG +# Author: Slaviša Arežina (tremor021) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/bitmagnet/bitmagnet + +APP="Bitmagnet" +var_tags="${var_tags:-os}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-1024}" +var_disk="${var_disk:-4}" +var_os="${var_os:-debian}" +var_version="${var_version:-12}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + if [[ ! -d /opt/bitmagnet ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + RELEASE=$(curl -fsSL https://api.github.com/repos/bitmagnet-io/bitmagnet/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }') + if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then + msg_info "Stopping Service" + systemctl stop bitmagnet-web + msg_ok "Stopped Service" + + msg_info "Backing up database" + rm -f /tmp/backup.sql + $STD sudo -u postgres pg_dump \ + --column-inserts \ + --data-only \ + --on-conflict-do-nothing \ + --rows-per-insert=1000 \ + --table=metadata_sources \ + --table=content \ + --table=content_attributes \ + --table=content_collections \ + --table=content_collections_content \ + --table=torrent_sources \ + --table=torrents \ + --table=torrent_files \ + --table=torrent_hints \ + --table=torrent_contents \ + --table=torrent_tags \ + --table=torrents_torrent_sources \ + --table=key_values \ + bitmagnet \ + >/tmp/backup.sql + mv /tmp/backup.sql /opt/ + msg_ok "Database backed up" + + msg_info "Updating ${APP} to v${RELEASE}" + [ -f /opt/bitmagnet/.env ] && cp /opt/bitmagnet/.env /opt/ + [ -f /opt/bitmagnet/config.yml ] && cp /opt/bitmagnet/config.yml /opt/ + rm -rf /opt/bitmagnet/* + temp_file=$(mktemp) + curl -fsSL "https://github.com/bitmagnet-io/bitmagnet/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file" + tar zxf "$temp_file" --strip-components=1 -C /opt/bitmagnet + cd /opt/bitmagnet + VREL=v$RELEASE + $STD go build -ldflags "-s -w -X github.com/bitmagnet-io/bitmagnet/internal/version.GitTag=$VREL" + chmod +x bitmagnet + [ -f "/opt/.env" ] && cp "/opt/.env" /opt/bitmagnet/ + [ -f "/opt/config.yml" ] && cp "/opt/config.yml" /opt/bitmagnet/ + echo "${RELEASE}" >/opt/${APP}_version.txt + msg_ok "Updated $APP to v${RELEASE}" + + msg_info "Starting Service" + systemctl start bitmagnet-web + msg_ok "Started Service" + + msg_info "Cleaning up" + rm -f "$temp_file" + msg_ok "Cleaned" + msg_ok "Updated Successfully" + else + msg_ok "No update required. ${APP} is already at v${RELEASE}" + fi + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW} Access it using the following URL:${CL}" +echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3333${CL}" diff --git a/ct/boltdiy.sh b/ct/boltdiy.sh deleted file mode 100644 index ebb08aa54..000000000 --- a/ct/boltdiy.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env bash -source <(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/misc/build.func) -# Copyright (c) 2021-2025 community-scripts ORG -# Author: Slaviša Arežina (tremor021) -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Source: https://github.com/stackblitz-labs/bolt.diy/ - -APP="boltdiy" -TAGS="code;ai" -var_cpu="${var_cpu:-2}" -var_ram="${var_ram:-3072}" -var_disk="${var_disk:-6}" -var_os="${var_os:-debian}" -var_version="${var_version:-12}" -var_unprivileged="${var_unprivileged:-1}" - -header_info "$APP" -variables -color -catch_errors - -function update_script() { - header_info - check_container_storage - check_container_resources - if [[ ! -d /opt/bolt.diy ]]; then - msg_error "No ${APP} Installation Found!" - exit - fi - RELEASE=$(curl -fsSL https://api.github.com/repos/stackblitz-labs/bolt.diy/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }') - if [[ "${RELEASE}" != "$(cat /opt/boltdiy_version.txt)" ]] || [[ ! -f /opt/boltdiy_version.txt ]]; then - msg_info "Stopping $APP" - systemctl stop boltdiy - msg_ok "Stopped $APP" - - msg_info "Updating $APP to v${RELEASE}" - temp_dir=$(mktemp -d) - temp_file=$(mktemp) - cd $temp_dir -curl -fsSL "https://github.com/stackblitz-labs/bolt.diy/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file" - tar xzf $temp_file - cp -rf bolt.diy-${RELEASE}/* /opt/bolt.diy - cd /opt/bolt.diy - $STD pnpm install - msg_ok "Updated $APP to v${RELEASE}" - - msg_info "Starting $APP" - systemctl start boltdiy - msg_ok "Started $APP" - - msg_info "Cleaning Up" - rm -rf $temp_file - rm -rf $temp_dir - msg_ok "Cleanup Completed" - - echo "${RELEASE}" >/opt/boltdiy_version.txt - msg_ok "Update Successful" - else - msg_ok "No update required. ${APP} is already at v${RELEASE}" - fi - exit -} - -start -build_container -description - -msg_ok "Completed Successfully!\n" -echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:5173${CL}" \ No newline at end of file diff --git a/ct/go2rtc.sh b/ct/go2rtc.sh index 13bc1fd18..d79378e26 100644 --- a/ct/go2rtc.sh +++ b/ct/go2rtc.sh @@ -6,7 +6,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/asylumexp/Proxmox/main/mis # Source: https://github.com/AlexxIT/go2rtc APP="go2rtc" -var_tags="${var_tags:-recorder;video}" +var_tags="${var_tags:-streaming;video}" var_cpu="${var_cpu:-2}" var_ram="${var_ram:-2048}" var_disk="${var_disk:-4}" @@ -20,22 +20,22 @@ color catch_errors function update_script() { - header_info - check_container_storage - check_container_resources - if [[ ! -d /opt/go2rtc ]]; then - msg_error "No ${APP} Installation Found!" - exit - fi - msg_info "Updating $APP" - systemctl stop go2rtc - cd /opt/go2rtc - rm go2rtc_linux_amd64 - curl -fsSL "https://github.com/AlexxIT/go2rtc/releases/latest/download/go2rtc_linux_amd64" -o $(basename "https://github.com/AlexxIT/go2rtc/releases/latest/download/go2rtc_linux_amd64") - chmod +x go2rtc_linux_amd64 - systemctl start go2rtc - msg_ok "Updated $APP" + header_info + check_container_storage + check_container_resources + if [[ ! -d /opt/go2rtc ]]; then + msg_error "No ${APP} Installation Found!" exit + fi + msg_info "Updating $APP" + systemctl stop go2rtc + cd /opt/go2rtc + rm go2rtc_linux_amd64 + curl -fsSL "https://github.com/AlexxIT/go2rtc/releases/latest/download/go2rtc_linux_amd64" -o $(basename "https://github.com/AlexxIT/go2rtc/releases/latest/download/go2rtc_linux_amd64") + chmod +x go2rtc_linux_amd64 + systemctl start go2rtc + msg_ok "Updated $APP" + exit } start diff --git a/ct/headers/alpine-bitmagnet b/ct/headers/alpine-bitmagnet new file mode 100644 index 000000000..20b69a682 --- /dev/null +++ b/ct/headers/alpine-bitmagnet @@ -0,0 +1,6 @@ + ___ __ _ __ _ __ __ + / | / /___ (_)___ ___ / /_ (_) /_____ ___ ____ _____ _____ ___ / /_ + / /| | / / __ \/ / __ \/ _ \______/ __ \/ / __/ __ `__ \/ __ `/ __ `/ __ \/ _ \/ __/ + / ___ |/ / /_/ / / / / / __/_____/ /_/ / / /_/ / / / / / /_/ / /_/ / / / / __/ /_ +/_/ |_/_/ .___/_/_/ /_/\___/ /_.___/_/\__/_/ /_/ /_/\__,_/\__, /_/ /_/\___/\__/ + /_/ /____/ diff --git a/ct/headers/bitmagnet b/ct/headers/bitmagnet new file mode 100644 index 000000000..b508b34a0 --- /dev/null +++ b/ct/headers/bitmagnet @@ -0,0 +1,6 @@ + ____ _ __ __ + / __ )(_) /_____ ___ ____ _____ _____ ___ / /_ + / __ / / __/ __ `__ \/ __ `/ __ `/ __ \/ _ \/ __/ + / /_/ / / /_/ / / / / / /_/ / /_/ / / / / __/ /_ +/_____/_/\__/_/ /_/ /_/\__,_/\__, /_/ /_/\___/\__/ + /____/ diff --git a/ct/headers/boltdiy b/ct/headers/boltdiy deleted file mode 100644 index be687dd08..000000000 --- a/ct/headers/boltdiy +++ /dev/null @@ -1,6 +0,0 @@ - __ ____ ___ - / /_ ____ / / /_____/ (_)_ __ - / __ \/ __ \/ / __/ __ / / / / / - / /_/ / /_/ / / /_/ /_/ / / /_/ / -/_.___/\____/_/\__/\__,_/_/\__, / - /____/ diff --git a/ct/homarr.sh b/ct/homarr.sh index 4b75b9afe..e2ea3d1ef 100644 --- a/ct/homarr.sh +++ b/ct/homarr.sh @@ -125,7 +125,7 @@ EOF fetch_and_deploy_gh_release "homarr-labs/homarr" mv /opt/homarr-data-backup/.env /opt/homarr/.env cd /opt/homarr - $STD pnpm install + $STD pnpm install --recursive --frozen-lockfile --shamefully-hoist $STD pnpm build cp /opt/homarr/apps/nextjs/next.config.ts . cp /opt/homarr/apps/nextjs/package.json . @@ -151,7 +151,7 @@ EOF systemctl start homarr msg_ok "Started Services" msg_ok "Updated Successfully" - read -p "It's recommended to reboot the LXC after an update, would you like to reboot the LXC now ? (y/n): " choice + read -p "${TAB3}It's recommended to reboot the LXC after an update, would you like to reboot the LXC now ? (y/n): " choice if [[ "$choice" =~ ^[Yy]$ ]]; then reboot fi diff --git a/ct/homeassistant-core.sh b/ct/homeassistant-core.sh index 2d3f786b8..b06308c67 100644 --- a/ct/homeassistant-core.sh +++ b/ct/homeassistant-core.sh @@ -114,7 +114,7 @@ function update_script() { if [ "$UPD" == "3" ]; then set +Eeuo pipefail - read -r -p "Would you like to use No Authentication? " prompt + read -r -p "${TAB3}Would you like to use No Authentication? " prompt msg_info "Installing FileBrowser" RELEASE=$(curl -fsSL https://api.github.com/repos/filebrowser/filebrowser/releases/latest | grep -o '"tag_name": ".*"' | sed 's/"//g' | sed 's/tag_name: //g') $STD curl -fsSL https://github.com/filebrowser/filebrowser/releases/download/$RELEASE/linux-amd64-filebrowser.tar.gz | tar -xzv -C /usr/local/bin diff --git a/frontend/public/json/bitmagnet.json b/frontend/public/json/bitmagnet.json new file mode 100644 index 000000000..7f89a4826 --- /dev/null +++ b/frontend/public/json/bitmagnet.json @@ -0,0 +1,51 @@ +{ + "name": "Bitmagnet", + "slug": "bitmagnet", + "categories": [ + 11 + ], + "date_created": "2025-05-15", + "type": "ct", + "updateable": true, + "privileged": false, + "interface_port": 3333, + "documentation": "https://bitmagnet.io/setup.html", + "website": "https://bitmagnet.io/", + "logo": "https://raw.githubusercontent.com/selfhst/icons/refs/heads/main/webp/bitmagnet.webp", + "config_path": "`/opt/bitmagnet/config.yml` or `/opt/bitmagnet/.env`", + "description": "A self-hosted BitTorrent indexer, DHT crawler, content classifier and torrent search engine with web UI, GraphQL API and Servarr stack integration.", + "install_methods": [ + { + "type": "default", + "script": "ct/bitmagnet.sh", + "resources": { + "cpu": 2, + "ram": 1024, + "hdd": 4, + "os": "debian", + "version": "12" + } + }, + { + "type": "alpine", + "script": "ct/alpine-bitmagnet.sh", + "resources": { + "cpu": 2, + "ram": 1024, + "hdd": 3, + "os": "alpine", + "version": "3.21" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [ + { + "text": "During installation you will be asked to enter your TMDB API key, if you wanna use it. Make sure you have it ready.", + "type": "info" + } + ] +} diff --git a/frontend/public/json/boltdiy.json b/frontend/public/json/boltdiy.json deleted file mode 100644 index 5997cc6f2..000000000 --- a/frontend/public/json/boltdiy.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "bolt.diy", - "slug": "boltdiy", - "categories": [ - 20 - ], - "date_created": "2025-02-23", - "type": "ct", - "updateable": true, - "privileged": false, - "interface_port": 5173, - "documentation": "https://stackblitz-labs.github.io/bolt.diy/", - "website": "https://github.com/stackblitz-labs/bolt.diy", - "logo": "https://github.com/stackblitz-labs/bolt.diy/raw/refs/heads/main/icons/logo-text.svg", - "config_path": "/opt/bolt.diy/.env.local", - "description": "The official open source version of Bolt.new (previously known as oTToDev and bolt.new ANY LLM), which allows you to choose the LLM that you use for each prompt! Currently, you can use OpenAI, Anthropic, Ollama, OpenRouter, Gemini, LMStudio, Mistral, xAI, HuggingFace, DeepSeek, or Groq models - and it is easily extended to use any other model supported by the Vercel AI SDK!", - "install_methods": [ - { - "type": "default", - "script": "ct/boltdiy.sh", - "resources": { - "cpu": 2, - "ram": 3072, - "hdd": 6, - "os": "debian", - "version": "12" - } - } - ], - "default_credentials": { - "username": null, - "password": null - }, - "notes": [] -} diff --git a/frontend/public/json/dashy.json b/frontend/public/json/dashy.json index dd907f5b5..98f16e416 100644 --- a/frontend/public/json/dashy.json +++ b/frontend/public/json/dashy.json @@ -12,7 +12,7 @@ "documentation": null, "website": "https://dashy.to/", "logo": "https://github.com/Lissy93/dashy/raw/master/public/web-icons/dashy-logo.png", - "config_path": "/opt/dashy/public/conf.yml", + "config_path": "/opt/dashy/user-data/conf.yml", "description": "Dashy is a solution that helps you organize your self-hosted services by centralizing access to them through a single interface.", "install_methods": [ { diff --git a/frontend/public/json/versions.json b/frontend/public/json/versions.json index f3b22aedc..40d2e78c6 100644 --- a/frontend/public/json/versions.json +++ b/frontend/public/json/versions.json @@ -1,8 +1,233 @@ [ + { + "name": "MediaBrowser/Emby.Releases", + "version": "4.8.11.0", + "date": "2025-03-10T06:39:11Z" + }, + { + "name": "Part-DB/Part-DB-server", + "version": "v1.17.1", + "date": "2025-05-18T21:06:41Z" + }, + { + "name": "sbondCo/Watcharr", + "version": "v2.1.0", + "date": "2025-05-18T18:20:43Z" + }, + { + "name": "rogerfar/rdt-client", + "version": "v2.0.112", + "date": "2025-05-18T17:44:52Z" + }, + { + "name": "YunoHost/yunohost", + "version": "debian/12.1.6.1", + "date": "2025-05-18T17:01:42Z" + }, + { + "name": "clusterzx/paperless-ai", + "version": "v3.0.0", + "date": "2025-05-18T15:32:52Z" + }, + { + "name": "kimai/kimai", + "version": "2.34.0", + "date": "2025-05-18T13:22:17Z" + }, + { + "name": "runtipi/runtipi", + "version": "v4.1.1", + "date": "2025-05-16T17:37:30Z" + }, + { + "name": "hansmi/prometheus-paperless-exporter", + "version": "v0.0.8", + "date": "2025-05-18T11:37:31Z" + }, + { + "name": "Prowlarr/Prowlarr", + "version": "v1.35.1.5034", + "date": "2025-04-30T11:02:36Z" + }, + { + "name": "Jackett/Jackett", + "version": "v0.22.1917", + "date": "2025-05-18T05:59:41Z" + }, + { + "name": "theonedev/onedev", + "version": "v11.9.8", + "date": "2025-05-18T01:27:37Z" + }, + { + "name": "inventree/InvenTree", + "version": "0.17.12", + "date": "2025-05-17T19:16:00Z" + }, + { + "name": "crafty-controller/crafty-4", + "version": "v4.4.8", + "date": "2025-05-17T18:47:36Z" + }, + { + "name": "Radarr/Radarr", + "version": "v5.23.3.9987", + "date": "2025-05-17T12:55:29Z" + }, + { + "name": "bastienwirtz/homer", + "version": "v25.05.2", + "date": "2025-05-17T12:53:29Z" + }, + { + "name": "BookStackApp/BookStack", + "version": "v25.02.5", + "date": "2025-05-17T11:24:01Z" + }, + { + "name": "Paymenter/Paymenter", + "version": "v1.1.1", + "date": "2025-05-17T10:10:36Z" + }, + { + "name": "evcc-io/evcc", + "version": "0.203.6", + "date": "2025-05-17T07:30:49Z" + }, + { + "name": "prometheus/prometheus", + "version": "v0.304.0", + "date": "2025-05-17T07:29:09Z" + }, + { + "name": "cross-seed/cross-seed", + "version": "v6.12.5", + "date": "2025-05-17T02:52:33Z" + }, + { + "name": "syncthing/syncthing", + "version": "v1.29.6", + "date": "2025-05-06T07:57:02Z" + }, { "name": "advplyr/audiobookshelf", - "version": "v2.22.0", - "date": "2025-05-14T22:30:59Z" + "version": "v2.23.0", + "date": "2025-05-16T22:13:53Z" + }, + { + "name": "home-assistant/core", + "version": "2025.5.2", + "date": "2025-05-16T21:09:45Z" + }, + { + "name": "homarr-labs/homarr", + "version": "v1.20.0", + "date": "2025-05-16T19:18:10Z" + }, + { + "name": "NodeBB/NodeBB", + "version": "v4.4.1", + "date": "2025-05-16T16:37:51Z" + }, + { + "name": "influxdata/influxdb", + "version": "v3.0.3", + "date": "2025-05-16T15:41:16Z" + }, + { + "name": "wavelog/wavelog", + "version": "2.0.4", + "date": "2025-05-16T15:09:53Z" + }, + { + "name": "keycloak/keycloak", + "version": "26.0.12", + "date": "2025-05-15T14:06:52Z" + }, + { + "name": "emqx/emqx", + "version": "e5.10.0-alpha.1", + "date": "2025-05-16T13:30:53Z" + }, + { + "name": "wazuh/wazuh", + "version": "coverity-w20-4.13.0", + "date": "2025-05-14T12:06:20Z" + }, + { + "name": "gotson/komga", + "version": "1.21.3", + "date": "2025-05-16T04:31:05Z" + }, + { + "name": "mattermost/mattermost", + "version": "server/public/v0.1.13", + "date": "2025-05-16T03:44:25Z" + }, + { + "name": "ipfs/kubo", + "version": "v0.34.1", + "date": "2025-03-25T18:11:12Z" + }, + { + "name": "coder/code-server", + "version": "v4.100.2", + "date": "2025-05-15T23:02:46Z" + }, + { + "name": "goauthentik/authentik", + "version": "version/2025.4.1", + "date": "2025-05-15T17:48:29Z" + }, + { + "name": "cloudflare/cloudflared", + "version": "2025.5.0", + "date": "2025-05-15T17:09:50Z" + }, + { + "name": "apache/cassandra", + "version": "4.1.9-tentative", + "date": "2025-05-15T15:52:53Z" + }, + { + "name": "VictoriaMetrics/VictoriaMetrics", + "version": "pmm-6401-v1.117.1", + "date": "2025-05-15T15:45:22Z" + }, + { + "name": "ellite/Wallos", + "version": "v3.1.1", + "date": "2025-05-15T15:17:57Z" + }, + { + "name": "bunkerity/bunkerweb", + "version": "v1.6.1", + "date": "2025-03-15T17:29:17Z" + }, + { + "name": "Checkmk/checkmk", + "version": "v2.4.0p1", + "date": "2025-05-15T12:41:12Z" + }, + { + "name": "zwave-js/zwave-js-ui", + "version": "v10.5.1", + "date": "2025-05-15T09:59:28Z" + }, + { + "name": "morpheus65535/bazarr", + "version": "v1.5.2", + "date": "2025-05-11T16:40:55Z" + }, + { + "name": "FlowiseAI/Flowise", + "version": "flowise@3.0.0", + "date": "2025-05-15T01:49:47Z" + }, + { + "name": "ollama/ollama", + "version": "v0.7.0", + "date": "2025-05-14T23:42:30Z" }, { "name": "glanceapp/glance", @@ -19,31 +244,11 @@ "version": "3.0.2", "date": "2025-05-14T20:38:06Z" }, - { - "name": "NodeBB/NodeBB", - "version": "v4.4.0", - "date": "2025-05-14T20:36:37Z" - }, { "name": "esphome/esphome", "version": "2025.4.2", "date": "2025-05-11T22:18:43Z" }, - { - "name": "coder/code-server", - "version": "v4.100.1", - "date": "2025-05-14T18:08:16Z" - }, - { - "name": "MediaBrowser/Emby.Releases", - "version": "4.8.11.0", - "date": "2025-03-10T06:39:11Z" - }, - { - "name": "Checkmk/checkmk", - "version": "v2.3.0p32+security", - "date": "2025-05-14T15:37:55Z" - }, { "name": "Athou/commafeed", "version": "5.9.0", @@ -64,11 +269,6 @@ "version": "0.42.1", "date": "2020-06-07T07:27:04Z" }, - { - "name": "zwave-js/zwave-js-ui", - "version": "v10.5.0", - "date": "2025-05-14T13:21:21Z" - }, { "name": "firefly-iii/firefly-iii", "version": "v6.2.12", @@ -84,41 +284,16 @@ "version": "v25.0", "date": "2025-05-12T09:12:04Z" }, - { - "name": "wazuh/wazuh", - "version": "coverity-w20-4.13.0", - "date": "2025-05-14T12:06:20Z" - }, { "name": "blakeblackshear/frigate", "version": "v0.14.1", "date": "2024-08-29T22:32:51Z" }, - { - "name": "morpheus65535/bazarr", - "version": "v1.5.2", - "date": "2025-05-11T16:40:55Z" - }, - { - "name": "Jackett/Jackett", - "version": "v0.22.1895", - "date": "2025-05-14T05:59:00Z" - }, { "name": "TandoorRecipes/recipes", "version": "2.0.0-alpha-4", "date": "2025-05-14T05:01:45Z" }, - { - "name": "ollama/ollama", - "version": "v0.6.9-rc0", - "date": "2025-05-10T18:57:30Z" - }, - { - "name": "cross-seed/cross-seed", - "version": "v6.12.4", - "date": "2025-05-11T11:41:32Z" - }, { "name": "netbox-community/netbox", "version": "v4.3.1", @@ -129,11 +304,6 @@ "version": "v0.28.1", "date": "2025-05-13T18:45:47Z" }, - { - "name": "keycloak/keycloak", - "version": "26.2.4", - "date": "2025-05-08T09:10:10Z" - }, { "name": "OctoPrint/OctoPrint", "version": "1.11.1", @@ -144,11 +314,6 @@ "version": "8.0.1", "date": "2025-05-13T13:31:53Z" }, - { - "name": "theonedev/onedev", - "version": "v11.9.6", - "date": "2025-05-13T12:16:17Z" - }, { "name": "element-hq/synapse", "version": "v1.129.0", @@ -184,11 +349,6 @@ "version": "v2.1.0.118-2.1.0.118_canary_2025-05-12", "date": "2025-05-12T18:50:44Z" }, - { - "name": "runtipi/runtipi", - "version": "nightly", - "date": "2025-05-12T18:39:33Z" - }, { "name": "neo4j/neo4j", "version": "4.4.43", @@ -204,26 +364,11 @@ "version": "n8n@1.91.3", "date": "2025-05-08T12:25:10Z" }, - { - "name": "Paymenter/Paymenter", - "version": "v1.1.0", - "date": "2025-05-12T14:40:27Z" - }, - { - "name": "VictoriaMetrics/VictoriaMetrics", - "version": "pmm-6401-v1.117.0", - "date": "2025-05-12T13:24:20Z" - }, { "name": "apache/tika", "version": "3.2.0-rc1", "date": "2025-05-12T13:06:47Z" }, - { - "name": "mattermost/mattermost", - "version": "v10.7.2", - "date": "2025-05-12T10:42:32Z" - }, { "name": "dgtlmoon/changedetection.io", "version": "0.49.17", @@ -249,21 +394,11 @@ "version": "v3.5.3", "date": "2025-05-11T15:17:13Z" }, - { - "name": "Prowlarr/Prowlarr", - "version": "v1.35.1.5034", - "date": "2025-04-30T11:02:36Z" - }, { "name": "authelia/authelia", "version": "v4.39.3", "date": "2025-05-11T11:12:15Z" }, - { - "name": "Radarr/Radarr", - "version": "v5.22.4.9896", - "date": "2025-04-23T18:51:12Z" - }, { "name": "owncast/owncast", "version": "v0.2.3", @@ -289,16 +424,6 @@ "version": "v1.0.0-beta21", "date": "2025-05-09T23:14:23Z" }, - { - "name": "homarr-labs/homarr", - "version": "v1.19.1", - "date": "2025-05-09T19:15:10Z" - }, - { - "name": "home-assistant/core", - "version": "2025.5.1", - "date": "2025-05-09T15:05:54Z" - }, { "name": "crowdsecurity/crowdsec", "version": "v1.6.8", @@ -309,16 +434,6 @@ "version": "v0.53.0", "date": "2025-05-08T19:56:55Z" }, - { - "name": "ellite/Wallos", - "version": "v3.1.0", - "date": "2025-05-08T15:33:17Z" - }, - { - "name": "BookStackApp/BookStack", - "version": "v25.02.4", - "date": "2025-05-08T15:03:17Z" - }, { "name": "apache/tomcat", "version": "10.1.41", @@ -339,11 +454,6 @@ "version": "v5.36.3", "date": "2025-05-07T17:22:07Z" }, - { - "name": "ipfs/kubo", - "version": "v0.34.1", - "date": "2025-03-25T18:11:12Z" - }, { "name": "donaldzou/WGDashboard", "version": "v4.2.3", @@ -394,11 +504,6 @@ "version": "@jupyter-notebook/ui-components@7.5.0-alpha.0", "date": "2025-05-07T09:12:08Z" }, - { - "name": "influxdata/influxdb", - "version": "v1.12.1rc0", - "date": "2025-05-06T20:56:30Z" - }, { "name": "sysadminsmedia/homebox", "version": "v0.19.0", @@ -419,11 +524,6 @@ "version": "v0.107.61", "date": "2025-04-22T12:42:26Z" }, - { - "name": "syncthing/syncthing", - "version": "v1.29.6", - "date": "2025-05-06T07:57:02Z" - }, { "name": "linkwarden/linkwarden", "version": "v2.10.2", @@ -469,21 +569,11 @@ "version": "v3.4.0", "date": "2025-05-05T13:59:23Z" }, - { - "name": "evcc-io/evcc", - "version": "0.203.5", - "date": "2025-05-05T06:41:02Z" - }, { "name": "moghtech/komodo", "version": "v1.17.5", "date": "2025-05-04T22:17:06Z" }, - { - "name": "YunoHost/yunohost", - "version": "debian/12.0.16", - "date": "2025-05-04T22:06:15Z" - }, { "name": "Lidarr/Lidarr", "version": "v2.11.2.4629", @@ -494,11 +584,6 @@ "version": "v2.0.0.4645", "date": "2017-03-07T18:56:06Z" }, - { - "name": "bastienwirtz/homer", - "version": "v25.05.1", - "date": "2025-05-04T12:17:00Z" - }, { "name": "FreshRSS/FreshRSS", "version": "1.26.2", @@ -509,26 +594,11 @@ "version": "v25.5.0", "date": "2025-05-03T19:03:17Z" }, - { - "name": "rogerfar/rdt-client", - "version": "v2.0.111", - "date": "2025-05-03T16:25:30Z" - }, - { - "name": "kimai/kimai", - "version": "2.33.0", - "date": "2025-05-03T10:33:49Z" - }, { "name": "documenso/documenso", "version": "v1.10.3", "date": "2025-05-02T23:23:25Z" }, - { - "name": "prometheus/prometheus", - "version": "v0.304.0-rc.0", - "date": "2025-05-02T17:29:18Z" - }, { "name": "forgejo/forgejo", "version": "v11.0.1", @@ -544,11 +614,6 @@ "version": "v3.5.4", "date": "2025-05-02T13:42:06Z" }, - { - "name": "emqx/emqx", - "version": "e5.9.0", - "date": "2025-05-02T11:07:10Z" - }, { "name": "Koenkk/zigbee2mqtt", "version": "2.3.0", @@ -564,21 +629,11 @@ "version": "1.6.13", "date": "2025-04-30T16:38:35Z" }, - { - "name": "cloudflare/cloudflared", - "version": "2025.4.2", - "date": "2025-04-30T14:16:11Z" - }, { "name": "docmost/docmost", "version": "v0.20.4", "date": "2025-04-30T14:15:16Z" }, - { - "name": "goauthentik/authentik", - "version": "version/2025.4.0", - "date": "2025-04-30T12:34:14Z" - }, { "name": "hivemq/hivemq-community-edition", "version": "2025.3", @@ -614,11 +669,6 @@ "version": "v1.132.3", "date": "2025-04-28T14:11:06Z" }, - { - "name": "FlowiseAI/Flowise", - "version": "flowise@2.2.8", - "date": "2025-04-28T08:27:00Z" - }, { "name": "karakeep-app/karakeep", "version": "v0.24.1", @@ -664,11 +714,6 @@ "version": "release-1.23.0", "date": "2025-04-24T08:07:21Z" }, - { - "name": "inventree/InvenTree", - "version": "0.17.11", - "date": "2025-04-24T05:25:55Z" - }, { "name": "minio/minio", "version": "RELEASE.2025-04-22T22-12-26Z", @@ -764,11 +809,6 @@ "version": "4.5.1", "date": "2025-04-11T09:57:47Z" }, - { - "name": "apache/cassandra", - "version": "cassandra-5.0.4", - "date": "2025-04-10T16:32:00Z" - }, { "name": "Threadfin/Threadfin", "version": "1.2.32", @@ -784,11 +824,6 @@ "version": "21.0.1", "date": "2025-04-06T19:22:59Z" }, - { - "name": "wavelog/wavelog", - "version": "2.0.3", - "date": "2025-04-06T17:35:41Z" - }, { "name": "jellyfin/jellyfin", "version": "v10.10.7", @@ -839,11 +874,6 @@ "version": "v6.0.6", "date": "2025-03-30T16:59:06Z" }, - { - "name": "Part-DB/Part-DB-server", - "version": "v1.17.0", - "date": "2025-03-30T14:21:53Z" - }, { "name": "aceberg/WatchYourLAN", "version": "2.1.2-alpine", @@ -854,11 +884,6 @@ "version": "v4.7.0", "date": "2025-03-29T03:50:50Z" }, - { - "name": "bunkerity/bunkerweb", - "version": "v1.6.1", - "date": "2025-03-15T17:29:17Z" - }, { "name": "grocy/grocy", "version": "v4.5.0", @@ -879,11 +904,6 @@ "version": "v1.34.0", "date": "2025-03-26T08:48:34Z" }, - { - "name": "hansmi/prometheus-paperless-exporter", - "version": "v0.0.7", - "date": "2025-03-25T15:11:18Z" - }, { "name": "nextcloud/nextcloudpi", "version": "v1.55.4", @@ -899,11 +919,6 @@ "version": "v4.3.1", "date": "2025-03-23T09:02:54Z" }, - { - "name": "clusterzx/paperless-ai", - "version": "v2.7.6", - "date": "2025-03-21T19:24:53Z" - }, { "name": "seanmorley15/AdventureLog", "version": "v0.9.0", @@ -929,11 +944,6 @@ "version": "4.0.1-beta.1", "date": "2024-12-13T00:16:24Z" }, - { - "name": "gotson/komga", - "version": "1.21.2", - "date": "2025-03-12T04:19:30Z" - }, { "name": "excalidraw/excalidraw", "version": "v0.18.0", @@ -1019,11 +1029,6 @@ "version": "v28.0", "date": "2025-02-18T15:49:57Z" }, - { - "name": "sbondCo/Watcharr", - "version": "v2.0.2", - "date": "2025-02-16T21:34:29Z" - }, { "name": "recyclarr/recyclarr", "version": "v7.4.1", @@ -1079,11 +1084,6 @@ "version": "1.1.14", "date": "2025-01-25T12:48:28Z" }, - { - "name": "crafty-controller/crafty-4", - "version": "v4.4.7", - "date": "2025-01-20T15:45:06Z" - }, { "name": "0xERR0R/blocky", "version": "v0.25", diff --git a/install/alpine-bitmagnet-install.sh b/install/alpine-bitmagnet-install.sh new file mode 100644 index 000000000..0a88b507d --- /dev/null +++ b/install/alpine-bitmagnet-install.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2025 community-scripts ORG +# Author: Slaviša Arežina (tremor021) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/bitmagnet-io/bitmagnet + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing dependencies" +$STD apk add --no-cache \ + gcc \ + musl-dev \ + git \ + iproute2-ss \ + sudo +$STD apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community go +msg_ok "Installed dependencies" + +msg_info "Installing PostgreSQL" +$STD apk add --no-cache \ + postgresql16 \ + postgresql16-contrib \ + postgresql16-openrc +$STD rc-update add postgresql +$STD rc-service postgresql start +msg_ok "Installed PostreSQL" + +RELEASE=$(curl -fsSL https://api.github.com/repos/bitmagnet-io/bitmagnet/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }') + +msg_info "Installing bitmagnet v${RELEASE}" +mkdir -p /opt/bitmagnet +temp_file=$(mktemp) +curl -fsSL "https://github.com/bitmagnet-io/bitmagnet/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file" +tar zxf "$temp_file" --strip-components=1 -C /opt/bitmagnet +cd /opt/bitmagnet +VREL=v$RELEASE +$STD go build -ldflags "-s -w -X github.com/bitmagnet-io/bitmagnet/internal/version.GitTag=$VREL" +chmod +x bitmagnet +$STD su - postgres -c "psql -c 'CREATE DATABASE bitmagnet;'" +echo "${RELEASE}" >/opt/bitmagnet_version.txt +msg_ok "Installed bitmagnet v${RELEASE}" + +read -rp "${TAB3}Enter your TMDB API key if you have one: " tmdbapikey + +msg_info "Enabling bitmagnet Service" +cat </etc/init.d/bitmagnet +#!/sbin/openrc-run +description="bitmagnet Service" +directory="/opt/bitmagnet" +command="/opt/bitmagnet/bitmagnet" +command_args="worker run --all" +command_background="true" +command_user="root" +pidfile="/var/run/bitmagnet.pid" + +depend() { + use net +} + +start_pre() { + export TMDB_API_KEY="$tmdbapikey" +} +EOF +chmod +x /etc/init.d/bitmagnet +$STD rc-update add bitmagnet default +msg_ok "Enabled bitmagnet Service" + +msg_info "Starting bitmagnet" +$STD service bitmagnet start +msg_ok "Started bitmagnet" + +motd_ssh +customize + +msg_info "Cleaning up" +rm -f "$temp_file" +$STD apk cache clean +msg_ok "Cleaned" diff --git a/install/alpine-docker-install.sh b/install/alpine-docker-install.sh index c7e5f3ba0..c22119d5d 100644 --- a/install/alpine-docker-install.sh +++ b/install/alpine-docker-install.sh @@ -24,13 +24,13 @@ $STD rc-update add docker default msg_ok "Installed Docker" get_latest_release() { - curl -fsSL https://api.github.com/repos/$1/releases/latest | grep '"tag_name":' | cut -d'"' -f4 + curl -fsSL https://api.github.com/repos/"$1"/releases/latest | grep '"tag_name":' | cut -d'"' -f4 } PORTAINER_LATEST_VERSION=$(get_latest_release "portainer/portainer") DOCKER_COMPOSE_LATEST_VERSION=$(get_latest_release "docker/compose") PORTAINER_AGENT_LATEST_VERSION=$(get_latest_release "portainer/agent") -read -r -p "Would you like to add Portainer? " prompt +read -r -p "${TAB3}Would you like to add Portainer? " prompt if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then msg_info "Installing Portainer $PORTAINER_LATEST_VERSION" docker volume create portainer_data >/dev/null @@ -44,7 +44,7 @@ if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then portainer/portainer-ce:latest msg_ok "Installed Portainer $PORTAINER_LATEST_VERSION" else - read -r -p "Would you like to add the Portainer Agent? " prompt + read -r -p "${TAB3}Would you like to add the Portainer Agent? " prompt if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then msg_info "Installing Portainer agent $PORTAINER_AGENT_LATEST_VERSION" $STD docker run -d \ @@ -57,13 +57,13 @@ else msg_ok "Installed Portainer Agent $PORTAINER_AGENT_LATEST_VERSION" fi fi -read -r -p "Would you like to add Docker Compose? " prompt +read -r -p "${TAB3}Would you like to add Docker Compose? " prompt if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then msg_info "Installing Docker Compose $DOCKER_COMPOSE_LATEST_VERSION" DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker} - mkdir -p $DOCKER_CONFIG/cli-plugins - curl -fsSL https://github.com/docker/compose/releases/download/$DOCKER_COMPOSE_LATEST_VERSION/docker-compose-linux-aarch64 -o ~/.docker/cli-plugins/docker-compose - chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose + mkdir -p "$DOCKER_CONFIG"/cli-plugins + curl -fsSL https://github.com/docker/compose/releases/download/"$DOCKER_COMPOSE_LATEST_VERSION"/docker-compose-linux-aarch64 -o ~/.docker/cli-plugins/docker-compose + chmod +x "$DOCKER_CONFIG"/cli-plugins/docker-compose msg_ok "Installed Docker Compose $DOCKER_COMPOSE_LATEST_VERSION" fi diff --git a/install/alpine-komodo-install.sh b/install/alpine-komodo-install.sh index b9681f3de..e87bf6876 100644 --- a/install/alpine-komodo-install.sh +++ b/install/alpine-komodo-install.sh @@ -26,11 +26,11 @@ $STD rc-update add docker boot $STD service docker start msg_ok "Enabled Docker Service" -echo "Choose the database for Komodo installation:" -echo "1) MongoDB (recommended)" -echo "2) SQLite" -echo "3) PostgreSQL" -read -rp "Enter your choice (default: 1): " DB_CHOICE +echo "${TAB3}Choose the database for Komodo installation:" +echo "${TAB3}1) MongoDB (recommended)" +echo "${TAB3}2) SQLite" +echo "${TAB3}3) PostgreSQL" +read -rp "${TAB3}Enter your choice (default: 1): " DB_CHOICE DB_CHOICE=${DB_CHOICE:-1} case $DB_CHOICE in diff --git a/install/alpine-mariadb-install.sh b/install/alpine-mariadb-install.sh index 572046575..89b76318e 100644 --- a/install/alpine-mariadb-install.sh +++ b/install/alpine-mariadb-install.sh @@ -29,7 +29,7 @@ mysql_install_db --user=mysql --basedir=/usr --datadir=/var/lib/mysql >/dev/null $STD rc-service mariadb start msg_ok "MariaDB Configured" -read -r -p "Would you like to install Adminer with lighttpd? : " prompt +read -r -p "${TAB3}Would you like to install Adminer with lighttpd? : " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_info "Installing Adminer and dependencies" $STD apk add --no-cache \ diff --git a/install/alpine-postgresql-install.sh b/install/alpine-postgresql-install.sh index b8cf02103..43532f9f9 100644 --- a/install/alpine-postgresql-install.sh +++ b/install/alpine-postgresql-install.sh @@ -33,7 +33,7 @@ sed -i '/^host\s\+all\s\+all\s\+127.0.0.1\/32\s\+md5/ s/.*/host all all 0.0.0.0\ $STD rc-service postgresql restart msg_ok "Configured and Restarted PostgreSQL" -read -r -p "Would you like to install Adminer with lighttpd? : " prompt +read -r -p "${TAB3}Would you like to install Adminer with lighttpd? : " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_info "Installing Adminer and dependencies" $STD apk add --no-cache \ diff --git a/install/alpine-traefik-install.sh b/install/alpine-traefik-install.sh index cdd2f5b4a..aa3abb871 100644 --- a/install/alpine-traefik-install.sh +++ b/install/alpine-traefik-install.sh @@ -21,7 +21,7 @@ msg_info "Installing Traefik" $STD apk add traefik --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community msg_ok "Installed Traefik" -read -p "Enable Traefik WebUI (Port 8080)? [y/N]: " enable_webui +read -p "${TAB3}Enable Traefik WebUI (Port 8080)? [y/N]: " enable_webui if [[ "$enable_webui" =~ ^[Yy]$ ]]; then msg_info "Configuring Traefik WebUI" mkdir -p /etc/traefik/config diff --git a/install/alpine-transmission-install.sh b/install/alpine-transmission-install.sh index d1f55f48a..10a06db53 100644 --- a/install/alpine-transmission-install.sh +++ b/install/alpine-transmission-install.sh @@ -16,6 +16,7 @@ update_os msg_info "Installing Transmission" $STD apk add --no-cache transmission-cli transmission-daemon $STD rc-service transmission-daemon start +sleep 5 $STD rc-service transmission-daemon stop sed -i '{s/"rpc-whitelist-enabled": true/"rpc-whitelist-enabled": false/g; s/"rpc-host-whitelist-enabled": true,/"rpc-host-whitelist-enabled": false,/g}' /var/lib/transmission/config/settings.json msg_ok "Installed Transmission" diff --git a/install/alpine-wireguard-install.sh b/install/alpine-wireguard-install.sh index fb770d542..276d308f2 100644 --- a/install/alpine-wireguard-install.sh +++ b/install/alpine-wireguard-install.sh @@ -46,7 +46,7 @@ $STD rc-update add sysctl $STD sysctl -p /etc/sysctl.conf msg_ok "Installed WireGuard" -read -rp "Do you want to install WGDashboard? (y/N): " INSTALL_WGD +read -rp "${TAB3}Do you want to install WGDashboard? (y/N): " INSTALL_WGD if [[ "$INSTALL_WGD" =~ ^[Yy]$ ]]; then msg_info "Installing additional dependencies for WGDashboard" $STD apk add --no-cache \ diff --git a/install/apache-tomcat-install.sh b/install/apache-tomcat-install.sh index 2266ee9ed..8f5b696d9 100644 --- a/install/apache-tomcat-install.sh +++ b/install/apache-tomcat-install.sh @@ -15,10 +15,10 @@ update_os msg_info "Installing Dependencies" $STD apt-get install -y \ - gnupg2 \ - lsb-release \ - gpg \ - apt-transport-https + gnupg2 \ + lsb-release \ + gpg \ + apt-transport-https msg_ok "Installed Dependencies" msg_info "Setting up Adoptium Repository" @@ -28,90 +28,90 @@ echo "deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_COD $STD apt-get update msg_ok "Set up Adoptium Repository" -read -r -p "Which Tomcat version would you like to install? (9, 10.1, 11): " version +read -r -p "${TAB3}Which Tomcat version would you like to install? (9, 10.1, 11): " version case $version in 9) - TOMCAT_VERSION="9" - echo "Which LTS Java version would you like to use? (8, 11, 17, 21): " - read -r jdk_version - case $jdk_version in - 8) - msg_info "Installing Temurin JDK 8 (LTS) for Tomcat $TOMCAT_VERSION" - $STD apt-get install -y temurin-8-jdk - msg_ok "Setup Temurin JDK 8 (LTS)" - ;; - 11) - msg_info "Installing Temurin JDK 11 (LTS) for Tomcat $TOMCAT_VERSION" - $STD apt-get install -y temurin-11-jdk - msg_ok "Setup Temurin JDK 11 (LTS)" - ;; - 17) - msg_info "Installing Temurin JDK 17 (LTS) for Tomcat $TOMCAT_VERSION" - $STD apt-get install -qqy temurin-17-jdk - msg_ok "Setup Temurin JDK 17 (LTS)" - ;; - 21) - msg_info "Installing Temurin JDK 21 (LTS) for Tomcat $TOMCAT_VERSION" - $STD apt-get install -y temurin-21-jdk - msg_ok "Setup Temurin JDK 21 (LTS)" - ;; - *) - msg_error "Invalid JDK version selected. Please enter 8, 11, 17 or 21." - exit 1 - ;; - esac + TOMCAT_VERSION="9" + echo "Which LTS Java version would you like to use? (8, 11, 17, 21): " + read -r jdk_version + case $jdk_version in + 8) + msg_info "Installing Temurin JDK 8 (LTS) for Tomcat $TOMCAT_VERSION" + $STD apt-get install -y temurin-8-jdk + msg_ok "Setup Temurin JDK 8 (LTS)" ;; -10 | 10.1) - TOMCAT_VERSION="10" - echo "Which LTS Java version would you like to use? (11, 17): " - read -r jdk_version - case $jdk_version in - 11) - msg_info "Installing Temurin JDK 11 (LTS) for Tomcat $TOMCAT_VERSION" - $STD apt-get install -y temurin-11-jdk - msg_ok "Setup Temurin JDK 11" - ;; - 17) - msg_info "Installing Temurin JDK 17 (LTS) for Tomcat $TOMCAT_VERSION" - $STD apt-get install -y temurin-17-jdk - msg_ok "Setup Temurin JDK 17" - ;; - 21) - msg_info "Installing Temurin JDK 21 (LTS) for Tomcat $TOMCAT_VERSION" - $STD apt-get install -y temurin-21-jdk - msg_ok "Setup Temurin JDK 21 (LTS)" - ;; - *) - msg_error "Invalid JDK version selected. Please enter 11 or 17." - exit 1 - ;; - esac + 11) + msg_info "Installing Temurin JDK 11 (LTS) for Tomcat $TOMCAT_VERSION" + $STD apt-get install -y temurin-11-jdk + msg_ok "Setup Temurin JDK 11 (LTS)" ;; -11) - TOMCAT_VERSION="11" - echo "Which LTS Java version would you like to use? (17, 21): " - read -r jdk_version - case $jdk_version in - 17) - msg_info "Installing Temurin JDK 17 (LTS) for Tomcat $TOMCAT_VERSION" - $STD apt-get install -qqy temurin-17-jdk - msg_ok "Setup Temurin JDK 17" - ;; - 21) - msg_info "Installing Temurin JDK 21 (LTS) for Tomcat $TOMCAT_VERSION" - $STD apt-get install -y temurin-21-jdk - msg_ok "Setup Temurin JDK 21 (LTS)" - ;; - *) - msg_error "Invalid JDK version selected. Please enter 17 or 21." - exit 1 - ;; - esac + 17) + msg_info "Installing Temurin JDK 17 (LTS) for Tomcat $TOMCAT_VERSION" + $STD apt-get install -qqy temurin-17-jdk + msg_ok "Setup Temurin JDK 17 (LTS)" ;; -*) - msg_error "Invalid Tomcat version selected. Please enter 9, 10.1 or 11." + 21) + msg_info "Installing Temurin JDK 21 (LTS) for Tomcat $TOMCAT_VERSION" + $STD apt-get install -y temurin-21-jdk + msg_ok "Setup Temurin JDK 21 (LTS)" + ;; + *) + msg_error "Invalid JDK version selected. Please enter 8, 11, 17 or 21." exit 1 ;; + esac + ;; +10 | 10.1) + TOMCAT_VERSION="10" + echo "Which LTS Java version would you like to use? (11, 17): " + read -r jdk_version + case $jdk_version in + 11) + msg_info "Installing Temurin JDK 11 (LTS) for Tomcat $TOMCAT_VERSION" + $STD apt-get install -y temurin-11-jdk + msg_ok "Setup Temurin JDK 11" + ;; + 17) + msg_info "Installing Temurin JDK 17 (LTS) for Tomcat $TOMCAT_VERSION" + $STD apt-get install -y temurin-17-jdk + msg_ok "Setup Temurin JDK 17" + ;; + 21) + msg_info "Installing Temurin JDK 21 (LTS) for Tomcat $TOMCAT_VERSION" + $STD apt-get install -y temurin-21-jdk + msg_ok "Setup Temurin JDK 21 (LTS)" + ;; + *) + msg_error "Invalid JDK version selected. Please enter 11 or 17." + exit 1 + ;; + esac + ;; +11) + TOMCAT_VERSION="11" + echo "Which LTS Java version would you like to use? (17, 21): " + read -r jdk_version + case $jdk_version in + 17) + msg_info "Installing Temurin JDK 17 (LTS) for Tomcat $TOMCAT_VERSION" + $STD apt-get install -qqy temurin-17-jdk + msg_ok "Setup Temurin JDK 17" + ;; + 21) + msg_info "Installing Temurin JDK 21 (LTS) for Tomcat $TOMCAT_VERSION" + $STD apt-get install -y temurin-21-jdk + msg_ok "Setup Temurin JDK 21 (LTS)" + ;; + *) + msg_error "Invalid JDK version selected. Please enter 17 or 21." + exit 1 + ;; + esac + ;; +*) + msg_error "Invalid Tomcat version selected. Please enter 9, 10.1 or 11." + exit 1 + ;; esac msg_info "Installing Tomcat $TOMCAT_VERSION" diff --git a/install/aria2-install.sh b/install/aria2-install.sh index 8bd81310d..0b5de5e95 100644 --- a/install/aria2-install.sh +++ b/install/aria2-install.sh @@ -17,7 +17,7 @@ msg_info "Installing Aria2" $STD apt-get install -y aria2 msg_ok "Installed Aria2" -read -r -p "Would you like to add AriaNG? " prompt +read -r -p "${TAB3}Would you like to add AriaNG? " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_info "Installing AriaNG" $STD apt-get install -y nginx diff --git a/install/authelia-install.sh b/install/authelia-install.sh index 2e39caaba..bede0dad9 100644 --- a/install/authelia-install.sh +++ b/install/authelia-install.sh @@ -19,7 +19,7 @@ curl -fsSL "https://github.com/authelia/authelia/releases/download/${RELEASE}/au $STD dpkg -i "authelia_${RELEASE}_arm64.deb" msg_ok "Install Authelia completed" -read -p "Enter your domain (ex. example.com): " DOMAIN +read -p "${TAB3}Enter your domain (ex. example.com): " DOMAIN msg_info "Setting Authelia up" touch /etc/authelia/emails.txt diff --git a/install/bitmagnet-install.sh b/install/bitmagnet-install.sh new file mode 100644 index 000000000..7ccdb8c67 --- /dev/null +++ b/install/bitmagnet-install.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2025 community-scripts ORG +# Author: Slaviša Arežina (tremor021) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/bitmagnet-io/bitmagnet + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Dependencies" +$STD apt-get install -y \ + iproute2 \ + gcc \ + musl-dev +msg_ok "Installed Dependencies" + +PG_VERSION="16" install_postgresql +install_go +RELEASE=$(curl -fsSL https://api.github.com/repos/bitmagnet-io/bitmagnet/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }') + +msg_info "Installing bitmagnet v${RELEASE}" +mkdir -p /opt/bitmagnet +temp_file=$(mktemp) +curl -fsSL "https://github.com/bitmagnet-io/bitmagnet/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file" +tar zxf "$temp_file" --strip-components=1 -C /opt/bitmagnet +cd /opt/bitmagnet +VREL=v$RELEASE +$STD go build -ldflags "-s -w -X github.com/bitmagnet-io/bitmagnet/internal/version.GitTag=$VREL" +chmod +x bitmagnet +POSTGRES_PASSWORD=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13) +$STD sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD '$POSTGRES_PASSWORD';" +$STD sudo -u postgres psql -c "CREATE DATABASE bitmagnet;" +{ + echo "PostgreSQL Credentials" + echo "" + echo "postgres user password: $POSTGRES_PASSWORD" +} >>~/postgres.creds +echo "${RELEASE}" >/opt/bitmagnet_version.txt +msg_ok "Installed bitmagnet v${RELEASE}" + +read -r -p "${TAB3}Enter your TMDB API key if you have one: " tmdbapikey + +msg_info "Creating Service" +cat </etc/systemd/system/bitmagnet-web.service +[Unit] +Description=bitmagnet Web GUI +After=network-online.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/bitmagnet +ExecStart=/opt/bitmagnet/bitmagnet worker run --all +Environment=POSTGRES_HOST=localhost +Environment=POSTGRES_PASSWORD=$POSTGRES_PASSWORD +Environment=TMDB_API_KEY=$tmdbapikey +Restart=on-failure + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now bitmagnet-web +msg_ok "Created Service" + +motd_ssh +customize + +msg_info "Cleaning up" +rm -f "$temp_file" +$STD apt-get -y autoremove +$STD apt-get -y autoclean +msg_ok "Cleaned" diff --git a/install/boltdiy-install.sh b/install/boltdiy-install.sh deleted file mode 100644 index b007320cc..000000000 --- a/install/boltdiy-install.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (c) 2021-2025 community-scripts ORG -# Author: Slaviša Arežina (tremor021) -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Source: https://github.com/stackblitz-labs/bolt.diy/ - -source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" -color -verb_ip6 -catch_errors -setting_up_container -network_check -update_os - -msg_info "Installing Dependencies" -$STD apt-get install -y \ - gnupg \ - git -msg_ok "Installed Dependencies" - -msg_info "Setup Node.js Repository" -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_22.x nodistro main" >/etc/apt/sources.list.d/nodesource.list -msg_ok "Setup Node.js Repository" - -msg_info "Setup Node.js" -$STD apt-get update -$STD apt-get install -y nodejs -$STD npm install -g pnpm -msg_ok "Setup Node.js" - -msg_info "Setup bolt.diy" -temp_file=$(mktemp) -RELEASE=$(curl -fsSL https://api.github.com/repos/stackblitz-labs/bolt.diy/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }') -curl -fsSL "https://github.com/stackblitz-labs/bolt.diy/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file" -tar xzf $temp_file -mv bolt.diy-${RELEASE} /opt/bolt.diy -cd /opt/bolt.diy -$STD pnpm install -echo "${RELEASE}" >/opt/${APPLICATION}_version.txt -msg_ok "Setup bolt.diy" - -msg_info "Creating Service" -cat </etc/systemd/system/boltdiy.service -[Unit] -Description=bolt.diy Service -After=network.target - -[Service] -Type=simple -User=root -WorkingDirectory=/opt/bolt.diy -ExecStart=/usr/bin/pnpm run dev --host -Restart=always - -[Install] -WantedBy=multi-user.target -EOF -systemctl enable -q --now boltdiy -msg_ok "Created Service" - -motd_ssh -customize - -msg_info "Cleaning up" -rm -f $temp_file -$STD apt-get -y autoremove -$STD apt-get -y autoclean -msg_ok "Cleaned" diff --git a/install/bytestash-install.sh b/install/bytestash-install.sh index 29f2bfedd..e668982ca 100644 --- a/install/bytestash-install.sh +++ b/install/bytestash-install.sh @@ -14,7 +14,8 @@ network_check update_os msg_info "Installing Dependencies" -$STD apt-get install -y gnupg +$STD apt-get install -y \ + gnupg msg_ok "Installed Dependencies" msg_info "Setting up Node.js Repository" @@ -42,7 +43,7 @@ $STD npm install echo "${RELEASE}" >"/opt/${APPLICATION}_version.txt" msg_ok "Installed ByteStash" -read -p "Do you want to allow registration of multiple accounts? [y/n]: " allowreg +read -p "${TAB3}Do you want to allow registration of multiple accounts? [y/n]: " allowreg msg_info "Creating Service" cat </etc/systemd/system/bytestash-backend.service @@ -61,7 +62,7 @@ WantedBy=multi-user.target EOF if [[ "$allowreg" =~ ^[Yy]$ ]]; then - sed -i '8i\Environment=ALLOW_NEW_ACCOUNTS=true' /etc/systemd/system/bytestash-backend.service + sed -i '8i\Environment=ALLOW_NEW_ACCOUNTS=true' /etc/systemd/system/bytestash-backend.service fi cat </etc/systemd/system/bytestash-frontend.service diff --git a/install/caddy-install.sh b/install/caddy-install.sh index bd01550de..2b7dcad74 100644 --- a/install/caddy-install.sh +++ b/install/caddy-install.sh @@ -28,7 +28,7 @@ $STD apt-get update $STD apt-get install -y caddy msg_ok "Installed Caddy" -read -r -p "Would you like to install xCaddy Addon? " prompt +read -r -p "${TAB3}Would you like to install xCaddy Addon? " prompt if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then msg_info "Installing Golang" set +o pipefail @@ -46,7 +46,7 @@ if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then cd /opt RELEASE=$(curl -fsSL https://api.github.com/repos/caddyserver/xcaddy/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }') curl -fsSL "https://github.com/caddyserver/xcaddy/releases/download/${RELEASE}/xcaddy_${RELEASE:1}_linux_arm64.deb" -o $(basename "https://github.com/caddyserver/xcaddy/releases/download/${RELEASE}/xcaddy_${RELEASE:1}_linux_arm64.deb") - $STD dpkg -i xcaddy_${RELEASE:1}_linux_arm64.deb + $STD dpkg -i xcaddy_"${RELEASE:1}"_linux_arm64.deb rm -rf /opt/xcaddy* $STD xcaddy build msg_ok "Setup xCaddy" diff --git a/install/cloudflared-install.sh b/install/cloudflared-install.sh index be2fe4e76..9551f66c1 100644 --- a/install/cloudflared-install.sh +++ b/install/cloudflared-install.sh @@ -22,7 +22,7 @@ $STD apt-get update $STD apt-get install -y cloudflared msg_ok "Installed Cloudflared" -read -r -p "Would you like to configure cloudflared as a DNS-over-HTTPS (DoH) proxy? " prompt +read -r -p "${TAB3}Would you like to configure cloudflared as a DNS-over-HTTPS (DoH) proxy? " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_info "Creating Service" cat </usr/local/etc/cloudflared/config.yml diff --git a/install/cryptpad-install.sh b/install/cryptpad-install.sh index e19dee82d..81bd24c4c 100644 --- a/install/cryptpad-install.sh +++ b/install/cryptpad-install.sh @@ -15,8 +15,8 @@ update_os msg_info "Installing Dependencies" $STD apt-get install -y \ - gnupg \ - git + gnupg \ + git msg_ok "Installed Dependencies" msg_info "Setting up Node.js Repository" @@ -30,7 +30,7 @@ $STD apt-get update $STD apt-get install -y nodejs msg_ok "Setup Node.js" -read -p "Install OnlyOffice components instead of CKEditor? (Y/N): " onlyoffice +read -p "${TAB3}Install OnlyOffice components instead of CKEditor? (Y/N): " onlyoffice msg_info "Setup ${APPLICATION}" temp_file=$(mktemp) @@ -47,7 +47,7 @@ IP=$(hostname -I | awk '{print $1}') sed -i "51s/localhost/${IP}/g" /opt/cryptpad/config/config.js sed -i "80s#//httpAddress: 'localhost'#httpAddress: '0.0.0.0'#g" /opt/cryptpad/config/config.js if [[ "$onlyoffice" =~ ^[Yy]$ ]]; then - $STD bash -c "./install-onlyoffice.sh --accept-license" + $STD bash -c "./install-onlyoffice.sh --accept-license" fi echo "${RELEASE}" >/opt/${APPLICATION}_version.txt msg_ok "Setup ${APPLICATION}" diff --git a/install/docker-install.sh b/install/docker-install.sh index 3b052c063..9617ba3fb 100644 --- a/install/docker-install.sh +++ b/install/docker-install.sh @@ -14,7 +14,7 @@ network_check update_os get_latest_release() { - curl -fsSL https://api.github.com/repos/$1/releases/latest | grep '"tag_name":' | cut -d'"' -f4 + curl -fsSL https://api.github.com/repos/"$1"/releases/latest | grep '"tag_name":' | cut -d'"' -f4 } DOCKER_LATEST_VERSION=$(get_latest_release "moby/moby") @@ -29,7 +29,7 @@ echo -e '{\n "log-driver": "journald"\n}' >/etc/docker/daemon.json $STD sh <(curl -fsSL https://get.docker.com) msg_ok "Installed Docker $DOCKER_LATEST_VERSION" -read -r -p "Would you like to add Portainer? " prompt +read -r -p "${TAB3}Would you like to add Portainer? " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_info "Installing Portainer $PORTAINER_LATEST_VERSION" docker volume create portainer_data >/dev/null @@ -43,7 +43,7 @@ if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then portainer/portainer-ce:latest msg_ok "Installed Portainer $PORTAINER_LATEST_VERSION" else - read -r -p "Would you like to add the Portainer Agent? " prompt + read -r -p "${TAB3}Would you like to add the Portainer Agent? " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_info "Installing Portainer agent $PORTAINER_AGENT_LATEST_VERSION" $STD docker run -d \ diff --git a/install/dockge-install.sh b/install/dockge-install.sh index 749713e65..ccfa62aa5 100644 --- a/install/dockge-install.sh +++ b/install/dockge-install.sh @@ -41,7 +41,7 @@ cd /opt/dockge $STD docker compose up -d msg_ok "Installed Dockge" -read -r -p "Would you like to add Immich? " prompt +read -r -p "${TAB3}Would you like to add Immich? " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_info "Adding Immich compose.yaml" mkdir -p /opt/stacks/immich @@ -50,7 +50,7 @@ if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_ok "Added Immich compose.yaml" fi -read -r -p "Would you like to add Home Assistant? " prompt +read -r -p "${TAB3}Would you like to add Home Assistant? " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_info "Adding Home Assistant compose.yaml" mkdir -p /opt/stacks/homeassistant diff --git a/install/dotnetaspwebapi-install.sh b/install/dotnetaspwebapi-install.sh index f06db6e11..191395b03 100644 --- a/install/dotnetaspwebapi-install.sh +++ b/install/dotnetaspwebapi-install.sh @@ -28,7 +28,7 @@ msg_ok "Installed Dependencies" msg_info "Configure Application" var_project_name="default" -read -r -p "Type the assembly name of the project: " var_project_name +read -r -p "${TAB3}Type the assembly name of the project: " var_project_name echo "Target assembly: '${var_project_name}'" msg_ok "Application Configured" diff --git a/install/elementsynapse-install.sh b/install/elementsynapse-install.sh index 6e33445c0..285419c20 100644 --- a/install/elementsynapse-install.sh +++ b/install/elementsynapse-install.sh @@ -33,7 +33,7 @@ $STD apt-get install -y nodejs $STD npm install -g yarn msg_ok "Installed Node.js" -read -p "Please enter the name for your server: " servername +read -p "${TAB3}Please enter the name for your server: " servername msg_info "Installing Element Synapse" curl -fsSL "https://packages.matrix.org/debian/matrix-org-archive-keyring.gpg" -o "/usr/share/keyrings/matrix-org-archive-keyring.gpg" diff --git a/install/fileflows-install.sh b/install/fileflows-install.sh index 1eba6db18..0b53a8c1a 100644 --- a/install/fileflows-install.sh +++ b/install/fileflows-install.sh @@ -21,7 +21,6 @@ $STD apt-get install -y \ imagemagick msg_ok "Installed Dependencies" - msg_info "Installing Hardware Acceleration" $STD apt-get -y install {va-driver-all,ocl-icd-libopencl1,vainfo} msg_ok "Installed and Set Up Hardware Acceleration" diff --git a/install/homarr-install.sh b/install/homarr-install.sh index fcf7f32f5..bafc31c89 100644 --- a/install/homarr-install.sh +++ b/install/homarr-install.sh @@ -47,7 +47,7 @@ TURBO_TELEMETRY_DISABLED=1 AUTH_PROVIDERS='credentials' NODE_ENV='production' EOF -$STD pnpm install +$STD pnpm install --recursive --frozen-lockfile --shamefully-hoist $STD pnpm build msg_ok "Installed Homarr" @@ -67,7 +67,6 @@ echo $'#!/bin/bash\ncd /opt/homarr/apps/cli && node ./cli.cjs "$@"' >/usr/bin/ho chmod +x /usr/bin/homarr mkdir /opt/homarr/build cp ./node_modules/better-sqlite3/build/Release/better_sqlite3.node ./build/better_sqlite3.node -echo "${RELEASE}" >"/opt/${APPLICATION}_version.txt" msg_ok "Finished copying" msg_info "Creating Services" @@ -115,7 +114,6 @@ motd_ssh customize msg_info "Cleaning up" -rm -rf /opt/v${RELEASE}.zip $STD apt-get -y autoremove $STD apt-get -y autoclean msg_ok "Cleaned" diff --git a/install/influxdb-install.sh b/install/influxdb-install.sh index 947a252f0..8745d4bff 100644 --- a/install/influxdb-install.sh +++ b/install/influxdb-install.sh @@ -24,7 +24,7 @@ curl -fsSL "https://repos.influxdata.com/influxdata-archive_compat.key" | gpg -- echo "deb [signed-by=/etc/apt/trusted.gpg.d/influxdata-archive_compat.gpg] https://repos.influxdata.com/debian stable main" >/etc/apt/sources.list.d/influxdata.list msg_ok "Set up InfluxDB Repository" -read -r -p "Which version of InfluxDB to install? (1 or 2) " prompt +read -r -p "${TAB3}Which version of InfluxDB to install? (1 or 2) " prompt if [[ $prompt == "2" ]]; then INFLUX="2" else @@ -43,7 +43,7 @@ fi $STD systemctl enable --now influxdb msg_ok "Installed InfluxDB" -read -r -p "Would you like to add Telegraf? " prompt +read -r -p "${TAB3}Would you like to add Telegraf? " prompt if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then msg_info "Installing Telegraf" $STD apt-get install -y telegraf diff --git a/install/kometa-install.sh b/install/kometa-install.sh index 5a3378792..8c9634188 100644 --- a/install/kometa-install.sh +++ b/install/kometa-install.sh @@ -21,9 +21,9 @@ msg_ok "Setup Python 3" msg_info "Setup Kometa" temp_file=$(mktemp) RELEASE=$(curl -fsSL https://api.github.com/repos/Kometa-Team/Kometa/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }') -curl -fsSL "https://github.com/Kometa-Team/Kometa/archive/refs/tags/v${RELEASE}.tar.gz" -o ""$temp_file"" +curl -fsSL "https://github.com/Kometa-Team/Kometa/archive/refs/tags/v${RELEASE}.tar.gz" -o """$temp_file""" tar -xzf "$temp_file" -mv Kometa-${RELEASE} /opt/kometa +mv Kometa-"${RELEASE}" /opt/kometa cd /opt/kometa $STD pip install -r requirements.txt --ignore-installed mkdir -p config/assets @@ -31,10 +31,10 @@ cp config/config.yml.template config/config.yml echo "${RELEASE}" >/opt/kometa_version.txt msg_ok "Setup Kometa" -read -p "Enter your TMDb API key: " TMDBKEY -read -p "Enter your Plex URL: " PLEXURL -read -p "Enter your Plex token: " PLEXTOKEN -sed -i -e "s#url: http://192.168.1.12:32400#url: $PLEXURL#g" /opt/kometa/config/config.yml +read -p "${TAB3}nter your TMDb API key: " TMDBKEY +read -p "${TAB3}Enter your Plex URL: " PLEXURL +read -p "${TAB3}Enter your Plex token: " PLEXTOKEN +sed -i -e "s#url: http://192.168.1.12:32400#url: $PLEXURL #g" /opt/kometa/config/config.yml sed -i -e "s/token: ####################/token: $PLEXTOKEN/g" /opt/kometa/config/config.yml sed -i -e "s/apikey: ################################/apikey: $TMDBKEY/g" /opt/kometa/config/config.yml @@ -61,7 +61,7 @@ motd_ssh customize msg_info "Cleaning up" -rm -f $temp_file +rm -f "$temp_file" $STD apt-get -y autoremove $STD apt-get -y autoclean msg_ok "Cleaned" diff --git a/install/komodo-install.sh b/install/komodo-install.sh index 8ce70224c..f6fef282a 100644 --- a/install/komodo-install.sh +++ b/install/komodo-install.sh @@ -37,11 +37,11 @@ $STD apt-get install -y \ docker-compose-plugin msg_ok "Installed Docker" -echo "Choose the database for Komodo installation:" -echo "1) MongoDB (recommended)" -echo "2) SQLite" -echo "3) PostgreSQL" -read -rp "Enter your choice (default: 1): " DB_CHOICE +echo "${TAB3}Choose the database for Komodo installation:" +echo "${TAB3}1) MongoDB (recommended)" +echo "${TAB3}2) SQLite" +echo "${TAB3}3) PostgreSQL" +read -rp "${TAB3}Enter your choice (default: 1): " DB_CHOICE DB_CHOICE=${DB_CHOICE:-1} case $DB_CHOICE in diff --git a/install/linkwarden-install.sh b/install/linkwarden-install.sh index e54550f1a..4a2501428 100644 --- a/install/linkwarden-install.sh +++ b/install/linkwarden-install.sh @@ -31,7 +31,7 @@ install_postgresql msg_info "Installing Rust" curl -fsSL https://sh.rustup.rs -o rustup-init.sh $STD bash rustup-init.sh -y --profile minimal -echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> ~/.bashrc +echo 'export PATH="$HOME/.cargo/bin:$PATH"' >>~/.bashrc export PATH="$HOME/.cargo/bin:$PATH" rm rustup-init.sh $STD cargo install monolith @@ -56,7 +56,7 @@ $STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET timezone TO 'UTC';" } >>~/linkwarden.creds msg_ok "Set up PostgreSQL DB" -read -r -p "Would you like to add Adminer? " prompt +read -r -p "${TAB3}Would you like to add Adminer? " prompt if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then msg_info "Installing Adminer" $STD apt install -y adminer diff --git a/install/mariadb-install.sh b/install/mariadb-install.sh index 43ad4fc37..352599605 100644 --- a/install/mariadb-install.sh +++ b/install/mariadb-install.sh @@ -23,7 +23,7 @@ sed -i 's/^# *\(port *=.*\)/\1/' /etc/mysql/my.cnf sed -i 's/^bind-address/#bind-address/g' /etc/mysql/mariadb.conf.d/50-server.cnf msg_ok "Installed MariaDB" -read -r -p "Would you like to add PhpMyAdmin? " prompt +read -r -p "${TAB3}Would you like to add PhpMyAdmin? " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_info "Installing phpMyAdmin" $STD apt-get install -y \ diff --git a/install/meilisearch-install.sh b/install/meilisearch-install.sh index 0b7588b13..a25a20360 100644 --- a/install/meilisearch-install.sh +++ b/install/meilisearch-install.sh @@ -14,7 +14,8 @@ network_check update_os msg_info "Installing Dependencies" -$STD apt-get install -y gnupg +$STD apt-get install -y \ + gnupg msg_ok "Installed Dependencies" msg_info "Setup ${APPLICATION}" @@ -26,49 +27,49 @@ curl -fsSL https://raw.githubusercontent.com/meilisearch/meilisearch/latest/conf MASTER_KEY=$(openssl rand -base64 12) LOCAL_IP="$(hostname -I | awk '{print $1}')" sed -i \ - -e 's|^env =.*|env = "production"|' \ - -e "s|^# master_key =.*|master_key = \"$MASTER_KEY\"|" \ - -e 's|^db_path =.*|db_path = "/var/lib/meilisearch/data"|' \ - -e 's|^dump_dir =.*|dump_dir = "/var/lib/meilisearch/dumps"|' \ - -e 's|^snapshot_dir =.*|snapshot_dir = "/var/lib/meilisearch/snapshots"|' \ - -e 's|^# no_analytics = true|no_analytics = true|' \ - -e 's|^http_addr =.*|http_addr = "0.0.0.0:7700"|' \ - /etc/meilisearch.toml + -e 's|^env =.*|env = "production"|' \ + -e "s|^# master_key =.*|master_key = \"$MASTER_KEY\"|" \ + -e 's|^db_path =.*|db_path = "/var/lib/meilisearch/data"|' \ + -e 's|^dump_dir =.*|dump_dir = "/var/lib/meilisearch/dumps"|' \ + -e 's|^snapshot_dir =.*|snapshot_dir = "/var/lib/meilisearch/snapshots"|' \ + -e 's|^# no_analytics = true|no_analytics = true|' \ + -e 's|^http_addr =.*|http_addr = "0.0.0.0:7700"|' \ + /etc/meilisearch.toml echo "${RELEASE}" >/opt/${APPLICATION}_version.txt msg_ok "Setup ${APPLICATION}" -read -r -p "Do you want add meilisearch-ui? [y/n]: " prompt +read -r -p "${TAB3}Do you want add meilisearch-ui? [y/n]: " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then - msg_info "Setting up Node.js Repository" - 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_22.x nodistro main" >/etc/apt/sources.list.d/nodesource.list - msg_ok "Set up Node.js Repository" + msg_info "Setting up Node.js Repository" + 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_22.x nodistro main" >/etc/apt/sources.list.d/nodesource.list + msg_ok "Set up Node.js Repository" - msg_info "Installing Node.js" - $STD apt-get update - $STD apt-get install -y nodejs - $STD npm install -g pnpm - msg_ok "Installed Node.js" + msg_info "Installing Node.js" + $STD apt-get update + $STD apt-get install -y nodejs + $STD npm install -g pnpm + msg_ok "Installed Node.js" - msg_info "Setup ${APPLICATION}-ui" - tmp_file=$(mktemp) - tmp_dir=$(mktemp -d) - mkdir -p /opt/meilisearch-ui - RELEASE_UI=$(curl -s https://api.github.com/repos/riccox/meilisearch-ui/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }') - curl -fsSL "https://github.com/riccox/meilisearch-ui/archive/refs/tags/${RELEASE_UI}.zip" -o $tmp_file - unzip -q "$tmp_file" -d "$tmp_dir" - mv "$tmp_dir"/*/* /opt/meilisearch-ui/ - cd /opt/meilisearch-ui - sed -i 's|const hash = execSync("git rev-parse HEAD").toString().trim();|const hash = "unknown";|' /opt/meilisearch-ui/vite.config.ts - $STD pnpm install - cat < /opt/meilisearch-ui/.env.local + msg_info "Setup ${APPLICATION}-ui" + tmp_file=$(mktemp) + tmp_dir=$(mktemp -d) + mkdir -p /opt/meilisearch-ui + RELEASE_UI=$(curl -s https://api.github.com/repos/riccox/meilisearch-ui/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }') + curl -fsSL "https://github.com/riccox/meilisearch-ui/archive/refs/tags/${RELEASE_UI}.zip" -o "$tmp_file" + unzip -q "$tmp_file" -d "$tmp_dir" + mv "$tmp_dir"/*/* /opt/meilisearch-ui/ + cd /opt/meilisearch-ui + sed -i 's|const hash = execSync("git rev-parse HEAD").toString().trim();|const hash = "unknown";|' /opt/meilisearch-ui/vite.config.ts + $STD pnpm install + cat </opt/meilisearch-ui/.env.local VITE_SINGLETON_MODE=true VITE_SINGLETON_HOST=http://${LOCAL_IP}:7700 VITE_SINGLETON_API_KEY=${MASTER_KEY} EOF - echo "${RELEASE_UI}" >/opt/${APPLICATION}-ui_version.txt - msg_ok "Setup ${APPLICATION}-ui" + echo "${RELEASE_UI}" >/opt/${APPLICATION}-ui_version.txt + msg_ok "Setup ${APPLICATION}-ui" fi msg_info "Setting up Services" @@ -87,7 +88,7 @@ EOF systemctl enable -q --now meilisearch if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then -cat < /etc/systemd/system/meilisearch-ui.service + cat </etc/systemd/system/meilisearch-ui.service [Unit] Description=Meilisearch UI Service After=network.target meilisearch.service @@ -106,12 +107,11 @@ SyslogIdentifier=meilisearch-ui [Install] WantedBy=multi-user.target EOF -systemctl enable -q --now meilisearch-ui + systemctl enable -q --now meilisearch-ui fi msg_ok "Set up Services" - motd_ssh customize diff --git a/install/mongodb-install.sh b/install/mongodb-install.sh index b7cde7598..a16f8dc56 100644 --- a/install/mongodb-install.sh +++ b/install/mongodb-install.sh @@ -24,7 +24,7 @@ msg_info "Installing Dependencies" $STD apt-get install -y gnupg msg_ok "Installed Dependencies" -read -p "Do you want to install MongoDB 8.0 instead of 7.0? [y/N]: " install_mongodb_8 +read -p "${TAB3}Do you want to install MongoDB 8.0 instead of 7.0? [y/N]: " install_mongodb_8 if [[ "$install_mongodb_8" =~ ^[Yy]$ ]]; then MONGODB_VERSION="8.0" else diff --git a/install/mysql-install.sh b/install/mysql-install.sh index 4df9822f2..2d4fc5e2e 100644 --- a/install/mysql-install.sh +++ b/install/mysql-install.sh @@ -22,7 +22,7 @@ msg_ok "Installed Dependencies" RELEASE_REPO="mysql-8.0" RELEASE_AUTH="mysql_native_password" -read -r -p "Would you like to install the MySQL 8.4 LTS release instead of MySQL 8.0 (bug fix track; EOL April-2026)? " prompt +read -r -p "${TAB3}Would you like to install the MySQL 8.4 LTS release instead of MySQL 8.0 (bug fix track; EOL April-2026)? " prompt if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then RELEASE_REPO="mysql-8.4-lts" RELEASE_AUTH="caching_sha2_password" @@ -50,7 +50,7 @@ echo -e "MySQL user: root" >>~/mysql.creds echo -e "MySQL password: $ADMIN_PASS" >>~/mysql.creds msg_ok "MySQL Server configured" -read -r -p "Would you like to add PhpMyAdmin? " prompt +read -r -p "${TAB3}Would you like to add PhpMyAdmin? " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_info "Installing phpMyAdmin" $STD apt-get install -y \ diff --git a/install/navidrome-install.sh b/install/navidrome-install.sh index f9d2bad54..6bb587a61 100644 --- a/install/navidrome-install.sh +++ b/install/navidrome-install.sh @@ -15,7 +15,7 @@ update_os msg_info "Installing Dependencies (Patience)" $STD apt-get install -y \ - ffmpeg + ffmpeg msg_ok "Installed Dependencies" msg_info "Installing Navidrome" @@ -27,9 +27,9 @@ systemctl enable -q --now navidrome echo "${RELEASE}" >/opt/Navidrome_version.txt msg_ok "Installed Navidrome" -read -p "Do you want to install filebrowser addon? (y/n) " -n 1 -r +read -p "${TAB3}Do you want to install filebrowser addon? (y/n) " -n 1 -r if [[ $REPLY =~ ^[Yy]$ ]]; then - bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/filebrowser.sh)" + bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/filebrowser.sh)" fi motd_ssh diff --git a/install/nginxproxymanager-install.sh b/install/nginxproxymanager-install.sh index e1077b2b8..d2d2877f4 100644 --- a/install/nginxproxymanager-install.sh +++ b/install/nginxproxymanager-install.sh @@ -63,7 +63,7 @@ RELEASE=$(curl -fsSL https://api.github.com/repos/NginxProxyManager/nginx-proxy- grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }') -read -r -p "Would you like to install an older version (v2.10.4)? " prompt +read -r -p "${TAB3}Would you like to install an older version (v2.10.4)? " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_info "Downloading Nginx Proxy Manager v2.10.4" curl -fsSL "https://codeload.github.com/NginxProxyManager/nginx-proxy-manager/tar.gz/v2.10.4" | tar -xz @@ -72,7 +72,7 @@ if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then else msg_info "Downloading Nginx Proxy Manager v${RELEASE}" curl -fsSL "https://codeload.github.com/NginxProxyManager/nginx-proxy-manager/tar.gz/v${RELEASE}" | tar -xz - cd ./nginx-proxy-manager-${RELEASE} + cd ./nginx-proxy-manager-"${RELEASE}" msg_ok "Downloaded Nginx Proxy Manager v${RELEASE}" fi msg_info "Setting up Environment" diff --git a/install/npmplus-install.sh b/install/npmplus-install.sh index d8a4be573..9f3ed05e2 100644 --- a/install/npmplus-install.sh +++ b/install/npmplus-install.sh @@ -15,9 +15,9 @@ update_os msg_info "Installing Dependencies" $STD apk add \ - tzdata \ - gawk \ - yq + tzdata \ + gawk \ + yq msg_ok "Installed Dependencies" msg_info "Installing Docker & Compose" @@ -26,7 +26,7 @@ $STD rc-service docker start $STD rc-update add docker default get_latest_release() { - curl -fsSL https://api.github.com/repos/$1/releases/latest | grep '"tag_name":' | cut -d'"' -f4 + curl -fsSL https://api.github.com/repos/$1/releases/latest | grep '"tag_name":' | cut -d'"' -f4 } DOCKER_COMPOSE_LATEST_VERSION=$(get_latest_release "docker/compose") DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker} @@ -42,20 +42,20 @@ msg_ok "Fetched NPMplus" attempts=0 while true; do - read -r -p "Enter your TZ Identifier (e.g., Europe/Berlin): " TZ_INPUT - if validate_tz "$TZ_INPUT"; then - break - fi - msg_error "Invalid timezone! Please enter a valid TZ identifier." + read -r -p "${TAB3}Enter your TZ Identifier (e.g., Europe/Berlin): " TZ_INPUT + if validate_tz "$TZ_INPUT"; then + break + fi + msg_error "Invalid timezone! Please enter a valid TZ identifier." - attempts=$((attempts + 1)) - if [[ "$attempts" -ge 3 ]]; then - msg_error "Maximum attempts reached. Exiting." - exit 1 - fi + attempts=$((attempts + 1)) + if [[ "$attempts" -ge 3 ]]; then + msg_error "Maximum attempts reached. Exiting." + exit 1 + fi done -read -r -p "Enter your ACME Email: " ACME_EMAIL_INPUT +read -r -p "${TAB3}Enter your ACME Email: " ACME_EMAIL_INPUT yq -i " .services.npmplus.environment |= @@ -67,20 +67,20 @@ msg_info "Building and Starting NPMplus (Patience)" $STD docker compose up -d CONTAINER_ID="" for i in {1..60}; do - CONTAINER_ID=$(docker ps --filter "name=npmplus" --format "{{.ID}}") - if [[ -n "$CONTAINER_ID" ]]; then - STATUS=$(docker inspect --format '{{.State.Health.Status}}' "$CONTAINER_ID" 2>/dev/null || echo "starting") - if [[ "$STATUS" == "healthy" ]]; then - msg_ok "NPMplus is running and healthy" - break - elif [[ "$STATUS" == "unhealthy" ]]; then - msg_error "NPMplus container is unhealthy! Check logs." - docker logs "$CONTAINER_ID" - exit 1 - fi + CONTAINER_ID=$(docker ps --filter "name=npmplus" --format "{{.ID}}") + if [[ -n "$CONTAINER_ID" ]]; then + STATUS=$(docker inspect --format '{{.State.Health.Status}}' "$CONTAINER_ID" 2>/dev/null || echo "starting") + if [[ "$STATUS" == "healthy" ]]; then + msg_ok "NPMplus is running and healthy" + break + elif [[ "$STATUS" == "unhealthy" ]]; then + msg_error "NPMplus container is unhealthy! Check logs." + docker logs "$CONTAINER_ID" + exit 1 fi - sleep 2 - [[ $i -eq 60 ]] && msg_error "NPMplus container did not become healthy within 120s." && docker logs "$CONTAINER_ID" && exit 1 + fi + sleep 2 + [[ $i -eq 60 ]] && msg_error "NPMplus container did not become healthy within 120s." && docker logs "$CONTAINER_ID" && exit 1 done msg_ok "Builded and started NPMplus" @@ -90,18 +90,18 @@ customize msg_info "Retrieving Default Login (Patience)" PASSWORD_FOUND=0 for i in {1..60}; do - PASSWORD_LINE=$(docker logs npmplus 2>&1 | awk '/Creating a new user:/ { print; exit }') - if [[ -n "$PASSWORD_LINE" ]]; then - PASSWORD=$(echo "$PASSWORD_LINE" | awk -F 'password: ' '{print $2}') - echo -e "username: admin@example.org\npassword: $PASSWORD" >/opt/.npm_pwd - msg_ok "Saved default login to /opt/.npm_pwd" - PASSWORD_FOUND=1 - break - fi - sleep 2 + PASSWORD_LINE=$(docker logs "$CONTAINER_ID" 2>&1 | awk '/Creating a new user:/ { print; exit }') + if [[ -n "$PASSWORD_LINE" ]]; then + PASSWORD=$(echo "$PASSWORD_LINE" | awk -F 'password: ' '{print $2}') + echo -e "username: admin@example.org\npassword: $PASSWORD" >/opt/.npm_pwd + msg_ok "Saved default login to /opt/.npm_pwd" + PASSWORD_FOUND=1 + break + fi + sleep 2 done if [[ $PASSWORD_FOUND -eq 0 ]]; then - msg_error "Could not retrieve default login after 60 seconds." - echo -e "\nYou can manually check the container logs with:\n docker logs npmplus | grep 'Creating a new user:'\n" + msg_error "Could not retrieve default login after 60 seconds." + echo -e "\nYou can manually check the container logs with:\n docker logs $CONTAINER_ID | grep 'Creating a new user:'\n" fi diff --git a/install/openwebui-install.sh b/install/openwebui-install.sh index 9c64c1d65..090562ecd 100644 --- a/install/openwebui-install.sh +++ b/install/openwebui-install.sh @@ -56,7 +56,7 @@ export NODE_OPTIONS="--max-old-space-size=3584" $STD npm run build msg_ok "Installed Open WebUI" -read -r -p "Would you like to add Ollama? " prompt +read -r -p "${TAB3}Would you like to add Ollama? " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_info "Installing Ollama" curl -fsSLO https://ollama.com/download/ollama-linux-arm64.tgz diff --git a/install/openziti-controller-install.sh b/install/openziti-controller-install.sh index bbeddec7d..78a2c0ad5 100644 --- a/install/openziti-controller-install.sh +++ b/install/openziti-controller-install.sh @@ -5,7 +5,7 @@ # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://github.com/openziti/ziti -source /dev/stdin <<< "$FUNCTIONS_FILE_PATH" +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" color verb_ip6 catch_errors @@ -21,22 +21,22 @@ msg_info "Installing openziti" mkdir -p --mode=0755 /usr/share/keyrings curl -fsSL https://get.openziti.io/tun/package-repos.gpg | gpg --dearmor -o /usr/share/keyrings/openziti.gpg echo "deb [signed-by=/usr/share/keyrings/openziti.gpg] https://packages.openziti.org/zitipax-openziti-deb-stable debian main" >/etc/apt/sources.list.d/openziti.list -$STD apt-get update +$STD apt-get update $STD apt-get install -y openziti-controller openziti-console msg_ok "Installed openziti" -read -r -p "Would you like to go through the auto configuration now? " prompt +read -r -p "${TAB3}Would you like to go through the auto configuration now? " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then IPADDRESS=$(hostname -I | awk '{print $1}') GEN_FQDN="controller.${IPADDRESS}.sslip.io" - read -r -p "Please enter the controller FQDN [${GEN_FQDN}]: " ZITI_CTRL_ADVERTISED_ADDRESS + read -r -p "${TAB3}Please enter the controller FQDN [${GEN_FQDN}]: " ZITI_CTRL_ADVERTISED_ADDRESS ZITI_CTRL_ADVERTISED_ADDRESS=${ZITI_CTRL_ADVERTISED_ADDRESS:-$GEN_FQDN} - read -r -p "Please enter the controller port [1280]: " ZITI_CTRL_ADVERTISED_PORT + read -r -p "${TAB3}Please enter the controller port [1280]: " ZITI_CTRL_ADVERTISED_PORT ZITI_CTRL_ADVERTISED_PORT=${ZITI_CTRL_ADVERTISED_PORT:-1280} - read -r -p "Please enter the controller admin user [admin]: " ZITI_USER + read -r -p "${TAB3}Please enter the controller admin user [admin]: " ZITI_USER ZITI_USER=${ZITI_USER:-admin} GEN_PWD=$(head -c128 /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9!@#$%^*_+~' | cut -c 1-12) - read -r -p "Please enter the controller admin password [${GEN_PWD}]:" ZITI_PWD + read -r -p "${TAB3}Please enter the controller admin password [${GEN_PWD}]:" ZITI_PWD ZITI_PWD=${ZITI_PWD:-$GEN_PWD} CONFIG_FILE="/opt/openziti/etc/controller/bootstrap.env" sed -i "s|^ZITI_CTRL_ADVERTISED_ADDRESS=.*|ZITI_CTRL_ADVERTISED_ADDRESS='${ZITI_CTRL_ADVERTISED_ADDRESS}'|" "$CONFIG_FILE" diff --git a/install/openziti-tunnel-install.sh b/install/openziti-tunnel-install.sh index 97d85e924..e781fa51e 100644 --- a/install/openziti-tunnel-install.sh +++ b/install/openziti-tunnel-install.sh @@ -27,16 +27,16 @@ sed -i '0,/^ExecStart/ { /^ExecStart/ { n; s|^ExecStart.*|ExecStart=/opt/openzit systemctl daemon-reload msg_ok "Installed openziti" -read -r -p "Please paste an identity enrollment token(JTW)" prompt +read -r -p "${TAB3}Please paste an identity enrollment token(JTW)" prompt if [[ ${prompt} ]]; then - msg_info "Adding identity" - echo "${prompt}" >/opt/openziti/etc/identities/identity.jwt - chown ziti:ziti /opt/openziti/etc/identities/identity.jwt - systemctl enable -q --now ziti-edge-tunnel - msg_ok "Service Started" + msg_info "Adding identity" + echo "${prompt}" >/opt/openziti/etc/identities/identity.jwt + chown ziti:ziti /opt/openziti/etc/identities/identity.jwt + systemctl enable -q --now ziti-edge-tunnel + msg_ok "Service Started" else - systemctl enable -q ziti-edge-tunnel - msg_error "No identity provided; please place an identity file in /opt/openziti/etc/identities/ and restart the service" + systemctl enable -q ziti-edge-tunnel + msg_error "No identity provided; please place an identity file in /opt/openziti/etc/identities/ and restart the service" fi motd_ssh diff --git a/install/paperless-gpt-install.sh b/install/paperless-gpt-install.sh index f78a2da4e..7ccb1c456 100644 --- a/install/paperless-gpt-install.sh +++ b/install/paperless-gpt-install.sh @@ -50,8 +50,8 @@ msg_info "Setup Paperless-GPT" temp_file=$(mktemp) RELEASE=$(curl -fsSL https://api.github.com/repos/icereed/paperless-gpt/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }') curl -fsSL "https://github.com/icereed/paperless-gpt/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file" -tar zxf $temp_file -mv paperless-gpt-${RELEASE} /opt/paperless-gpt +tar zxf "$temp_file" +mv paperless-gpt-"${RELEASE}" /opt/paperless-gpt cd /opt/paperless-gpt/web-app $STD npm install $STD npm run build @@ -64,16 +64,16 @@ echo "${RELEASE}" >"/opt/${APPLICATION}_version.txt" msg_ok "Setup Paperless-GPT" mkdir -p /opt/paperless-gpt-data -read -p "Do you want to enter the Paperless local URL now? (y/n) " input_url +read -p "${TAB3}Do you want to enter the Paperless local URL now? (y/n) " input_url if [[ "$input_url" =~ ^[Yy]$ ]]; then - read -p "Enter your Paperless-NGX instance URL (e.g., http://192.168.1.100:8000): " PAPERLESS_BASE_URL + read -p "${TAB3}Enter your Paperless-NGX instance URL (e.g., http://192.168.1.100:8000): " PAPERLESS_BASE_URL else PAPERLESS_BASE_URL="http://your_paperless_ngx_url" fi -read -p "Do you want to enter the Paperless API token now? (y/n) " input_token +read -p "${TAB3}Do you want to enter the Paperless API token now? (y/n) " input_token if [[ "$input_token" =~ ^[Yy]$ ]]; then - read -p "Enter your Paperless API token: " PAPERLESS_API_TOKEN + read -p "${TAB3}Enter your Paperless API token: " PAPERLESS_API_TOKEN else PAPERLESS_API_TOKEN="your_paperless_api_token" fi @@ -129,7 +129,7 @@ motd_ssh customize msg_info "Cleaning up" -rm -f $temp_file +rm -f "$temp_file" $STD apt-get -y autoremove $STD apt-get -y autoclean msg_ok "Cleaned" diff --git a/install/paperless-ngx-install.sh b/install/paperless-ngx-install.sh index af0deaedd..a9c74ed4e 100644 --- a/install/paperless-ngx-install.sh +++ b/install/paperless-ngx-install.sh @@ -126,7 +126,7 @@ cd /opt/paperless/src $STD python3 manage.py migrate msg_ok "Set up PostgreSQL database" -read -r -p "Would you like to add Adminer? " prompt +read -r -p "${TAB3}Would you like to add Adminer? " prompt if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then msg_info "Installing Adminer" $STD apt install -y adminer diff --git a/install/pihole-install.sh b/install/pihole-install.sh index 3ea462d74..79c7cf262 100644 --- a/install/pihole-install.sh +++ b/install/pihole-install.sh @@ -54,9 +54,9 @@ $STD pihole-FTL --config ntp.sync.interval 0 systemctl restart pihole-FTL.service msg_ok "Installed Pi-hole" -read -r -p "Would you like to add Unbound? " prompt +read -r -p "${TAB3}Would you like to add Unbound? " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then - read -r -p "Unbound is configured as a recursive DNS server by default, would you like it to be configured as a forwarding DNS server (using DNS-over-TLS (DoT)) instead? " prompt + read -r -p "${TAB3}Unbound is configured as a recursive DNS server by default, would you like it to be configured as a forwarding DNS server (using DNS-over-TLS (DoT)) instead? " prompt msg_info "Installing Unbound" $STD apt-get install -y unbound cat </etc/unbound/unbound.conf.d/pi-hole.conf diff --git a/install/pocketid-install.sh b/install/pocketid-install.sh index 92a2f3ca4..b5d9e9216 100644 --- a/install/pocketid-install.sh +++ b/install/pocketid-install.sh @@ -42,7 +42,7 @@ rm -f "$temp_file" set -o pipefail msg_ok "Installed Golang" -read -r -p "What public URL do you want to use (e.g. pocketid.mydomain.com)? " public_url +read -r -p "${TAB3}What public URL do you want to use (e.g. pocketid.mydomain.com)? " public_url msg_info "Setup Pocket ID" cd /opt RELEASE=$(curl -fsSL https://api.github.com/repos/pocket-id/pocket-id/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }') diff --git a/install/podman-homeassistant-install.sh b/install/podman-homeassistant-install.sh index b3039e46a..c1e73b5c9 100644 --- a/install/podman-homeassistant-install.sh +++ b/install/podman-homeassistant-install.sh @@ -49,7 +49,7 @@ $STD systemctl enable --now podman.socket echo -e 'unqualified-search-registries=["docker.io"]' >>/etc/containers/registries.conf msg_ok "Installed Podman" -read -r -p "Would you like to add Portainer? " prompt +read -r -p "${TAB3}Would you like to add Portainer? " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_info "Installing Portainer $PORTAINER_LATEST_VERSION" podman volume create portainer_data >/dev/null @@ -63,7 +63,7 @@ if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then portainer/portainer-ce:latest msg_ok "Installed Portainer $PORTAINER_LATEST_VERSION" else - read -r -p "Would you like to add the Portainer Agent? " prompt + read -r -p "${TAB3}Would you like to add the Portainer Agent? " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_info "Installing Portainer agent $PORTAINER_AGENT_LATEST_VERSION" podman volume create temp >/dev/null diff --git a/install/podman-install.sh b/install/podman-install.sh index 915ef016a..532c326c3 100644 --- a/install/podman-install.sh +++ b/install/podman-install.sh @@ -49,7 +49,7 @@ $STD systemctl enable --now podman.socket echo -e 'unqualified-search-registries=["docker.io"]' >>/etc/containers/registries.conf msg_ok "Installed Podman" -read -r -p "Would you like to add Portainer? " prompt +read -r -p "${TAB3}Would you like to add Portainer? " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_info "Installing Portainer $PORTAINER_LATEST_VERSION" podman volume create portainer_data >/dev/null @@ -63,7 +63,7 @@ if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then portainer/portainer-ce:latest msg_ok "Installed Portainer $PORTAINER_LATEST_VERSION" else - read -r -p "Would you like to add the Portainer Agent? " prompt + read -r -p "${TAB3}Would you like to add the Portainer Agent? " prompt if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then msg_info "Installing Portainer agent $PORTAINER_AGENT_LATEST_VERSION" podman volume create temp >/dev/null diff --git a/install/postgresql-install.sh b/install/postgresql-install.sh index bfcabf5ec..ce4503bd6 100644 --- a/install/postgresql-install.sh +++ b/install/postgresql-install.sh @@ -130,7 +130,7 @@ EOF sudo systemctl restart postgresql msg_ok "Installed PostgreSQL" -read -r -p "Would you like to add Adminer? " prompt +read -r -p "${TAB3}Would you like to add Adminer? " prompt if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then msg_info "Installing Adminer" $STD apt install -y adminer diff --git a/install/pterodactyl-panel-install.sh b/install/pterodactyl-panel-install.sh index 30ae73078..4bab7899f 100644 --- a/install/pterodactyl-panel-install.sh +++ b/install/pterodactyl-panel-install.sh @@ -53,9 +53,9 @@ $STD mysql -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH } >>~/pterodactyl-panel.creds msg_ok "Set up MariaDB" -read -p "Provide an email address for admin login, this should be a valid email address: " ADMIN_EMAIL -read -p "Enter your First Name: " NAME_FIRST -read -p "Enter your Last Name: " NAME_LAST +read -p "${TAB3}Provide an email address for admin login, this should be a valid email address: " ADMIN_EMAIL +read -p "${TAB3}nter your First Name: " NAME_FIRST +read -p "${TAB3}Enter your Last Name: " NAME_LAST msg_info "Installing pterodactyl Panel" RELEASE=$(curl -fsSL https://api.github.com/repos/pterodactyl/panel/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }') diff --git a/install/sqlserver2022-install.sh b/install/sqlserver2022-install.sh index ef7b39582..8cb13a1fe 100644 --- a/install/sqlserver2022-install.sh +++ b/install/sqlserver2022-install.sh @@ -39,7 +39,7 @@ echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >>~/.bash_profile source ~/.bash_profile msg_ok "Installed SQL Server Tools" -read -r -p "Do you want to run the SQL server setup now? (Later is also possible) " prompt +read -r -p "${TAB3}Do you want to run the SQL server setup now? (Later is also possible) " prompt if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then /opt/mssql/bin/mssql-conf setup else diff --git a/misc/alpine-install.func b/misc/alpine-install.func index a6d649a44..29becc127 100644 --- a/misc/alpine-install.func +++ b/misc/alpine-install.func @@ -16,6 +16,7 @@ color() { BFR="\\r\\033[K" BOLD=$(echo "\033[1m") TAB=" " + TAB3=" " # System RETRY_NUM=10 diff --git a/misc/build.func b/misc/build.func index 55f539c7d..11a53d54a 100644 --- a/misc/build.func +++ b/misc/build.func @@ -31,6 +31,7 @@ color() { BOLD=$(echo "\033[1m") HOLD=" " TAB=" " + TAB3=" " # Icons CM="${TAB}✔️${TAB}" @@ -360,6 +361,76 @@ base_settings() { var_version="12" fi } +write_config() { + # This function writes the configuration to a file. + if whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "Write configfile" --yesno "Do you want to write the selections to a config file?" 10 60; then + FILEPATH="/opt/community-scripts/${NSAPP}.conf" + if [[ ! -f $FILEPATH ]]; then + cat <"$FILEPATH" +# ${NSAPP} Configuration File +# Generated on $(date) + +CT_TYPE="${CT_TYPE}" +DISK_SIZE="${DISK_SIZE}" +CORE_COUNT="${DISK_SIZE}" +RAM_SIZE="${RAM_SIZE}" +HN="${HN}" +BRG="${BRG}" +APT_CACHER_IP="${APT_CACHER_IP:-none}" +DISABLEIP6="${DISABLEIP6}" +PW="${PW:-none}" +SSH="${SSH}" +SSH_AUTHORIZED_KEY="${SSH_AUTHORIZED_KEY}" +VERBOSE="${VERBOSE}" +TAGS="${TAGS:-none}" +VLAN="${VLAN:-none}" +MTU="${MTU:-1500}" +GATE="${GATE:-none}" +SD="${SD:-none}" +MAC="${MAC:-none}" +NS="${NS:-none}" +NET="${NET}" + +EOF + echo -e "${INFO}${BOLD}${GN}Writing configuration to ${FILEPATH}${CL}" + else + echo -e "${INFO}${BOLD}${RD}Configuration file already exists at ${FILEPATH}${CL}" + if whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "Overwrite configfile" --yesno "Do you want to overwrite the existing config file?" 10 60; then + rm -f "$FILEPATH" + cat <"$FILEPATH" +# ${NSAPP} Configuration File +# Generated on $(date) + +CT_TYPE="${CT_TYPE}" +DISK_SIZE="${DISK_SIZE}" +CORE_COUNT="${DISK_SIZE}" +RAM_SIZE="${RAM_SIZE}" +HN="${HN}" +BRG="${BRG}" +APT_CACHER_IP="${APT_CACHER_IP:-none}" +DISABLEIP6="${DISABLEIP6}" +PW="${PW:-none}" +SSH="${SSH}" +SSH_AUTHORIZED_KEY="${SSH_AUTHORIZED_KEY}" +VERBOSE="${VERBOSE}" +TAGS="${TAGS:-none}" +VLAN="${VLAN:-none}" +MTU="${MTU:-1500}" +GATE="${GATE:-none}" +SD="${SD:-none}" +MAC="${MAC:-none}" +NS="${NS:-none}" +NET="${NET}" + +EOF + echo -e "${INFO}${BOLD}${GN}Writing configuration to ${FILEPATH}${CL}" + else + echo -e "${INFO}${BOLD}${RD}Configuration file not overwritten${CL}" + fi + fi + fi +} + # This function displays the default values for various settings. echo_default() { @@ -527,29 +598,29 @@ advanced_settings() { exit_script fi - BRIDGES="" IFACE_FILEPATH_LIST="/etc/network/interfaces"$'\n'$(find "/etc/network/interfaces.d/" -type f) - OLD_IFS=$IFS; IFS=$'\n' + OLD_IFS=$IFS + IFS=$'\n' for iface_filepath in ${IFACE_FILEPATH_LIST}; do iface_indexes_tmpfile=$(mktemp -q -u '.iface-XXXX') - ( grep -Pn '^\s*iface' "${iface_filepath}" | cut -d':' -f1 && wc -l "${iface_filepath}" | cut -d' ' -f1 ) | \ - awk 'FNR==1 {line=$0; next} {print line":"$0-1; line=$0}' > "${iface_indexes_tmpfile}" + (grep -Pn '^\s*iface' "${iface_filepath}" | cut -d':' -f1 && wc -l "${iface_filepath}" | cut -d' ' -f1) | + awk 'FNR==1 {line=$0; next} {print line":"$0-1; line=$0}' >"${iface_indexes_tmpfile}" || true if [ -f "${iface_indexes_tmpfile}" ]; then - while read -r pair; do - start=$(echo "${pair}" | cut -d':' -f1) - end=$(echo "${pair}" | cut -d':' -f2) + while read -r pair; do + start=$(echo "${pair}" | cut -d':' -f1) + end=$(echo "${pair}" | cut -d':' -f2) - if awk "NR >= ${start} && NR <= ${end}" "${iface_filepath}" | grep -qP '^\s*bridge[-_](ports|stp|fd|vlan-aware|vids)\s+'; then - iface_name=$(sed "${start}q;d" "${iface_filepath}" | awk '{print $2}') - BRIDGES="${iface_name}"$'\n'"${BRIDGES}" - fi + if awk "NR >= ${start} && NR <= ${end}" "${iface_filepath}" | grep -qP '^\s*(bridge[-_](ports|stp|fd|vlan-aware|vids)|ovs_type\s+OVSBridge)\b'; then + iface_name=$(sed "${start}q;d" "${iface_filepath}" | awk '{print $2}') + BRIDGES="${iface_name}"$'\n'"${BRIDGES}" + fi - done < "${iface_indexes_tmpfile}" - rm -f "${iface_indexes_tmpfile}" + done <"${iface_indexes_tmpfile}" + rm -f "${iface_indexes_tmpfile}" fi done @@ -563,11 +634,11 @@ advanced_settings() { echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}" else BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --menu "Select network bridge:" 15 40 6 $(echo "$BRIDGES" | awk '{print $0, "Bridge"}') 3>&1 1>&2 2>&3) - if [ -z "$BRG" ]; then - exit_script - else - echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}" - fi + if [ -z "$BRG" ]; then + exit_script + else + echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}" + fi fi while true; do @@ -700,8 +771,14 @@ advanced_settings() { exit_script fi - if [[ "$PW" == -password* ]]; then - if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH ACCESS" --yesno "Enable Root SSH Access?" 10 58); then + SSH_AUTHORIZED_KEY="$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --inputbox "SSH Authorized key for root (leave empty for none)" 8 58 --title "SSH Key" 3>&1 1>&2 2>&3)" + + if [[ -z "${SSH_AUTHORIZED_KEY}" ]]; then + SSH_AUTHORIZED_KEY="" + fi + + if [[ "$PW" == -password* || -n "$SSH_AUTHORIZED_KEY" ]]; then + if (whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "SSH ACCESS" --yesno "Enable Root SSH Access?" 10 58); then SSH="yes" else SSH="no" @@ -712,15 +789,7 @@ advanced_settings() { echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}" fi - if [[ "${SSH}" == "yes" ]]; then - SSH_AUTHORIZED_KEY="$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "SSH Authorized key for root (leave empty for none)" 8 58 --title "SSH Key" 3>&1 1>&2 2>&3)" - if [[ -z "${SSH_AUTHORIZED_KEY}" ]]; then - echo "Warning: No SSH key provided." - fi - else - SSH_AUTHORIZED_KEY="" - fi if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "VERBOSE MODE" --yesno "Enable Verbose Mode?" 10 58); then VERB="yes" else @@ -730,6 +799,7 @@ advanced_settings() { if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS COMPLETE" --yesno "Ready to create ${APP} LXC?" 10 58); then echo -e "${CREATING}${BOLD}${RD}Creating a ${APP} LXC using the above advanced settings${CL}" + else clear header_info @@ -806,285 +876,6 @@ EOF } -config_file() { - - CONFIG_FILE="/opt/community-scripts/.settings" - - if [[ -f "/opt/community-scripts/${NSAPP}.conf" ]]; then - CONFIG_FILE="/opt/community-scripts/${NSAPP}.conf" - fi - - if CONFIG_FILE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set absolute path to config file" 8 58 "$CONFIG_FILE" --title "CONFIG FILE" 3>&1 1>&2 2>&3); then - if [[ ! -f "$CONFIG_FILE" ]]; then - echo -e "${CROSS}${RD}Config file not found, exiting script!.${CL}" - exit - else - echo -e "${INFO}${BOLD}${DGN}Using config File: ${BGN}$CONFIG_FILE${CL}" - base_settings - source "$CONFIG_FILE" - fi - fi - if [[ -n "$CT_ID" ]]; then - if [[ "$CT_ID" =~ ^([0-9]{3,4})-([0-9]{3,4})$ ]]; then - MIN_ID=${BASH_REMATCH[1]} - MAX_ID=${BASH_REMATCH[2]} - if ((MIN_ID >= MAX_ID)); then - msg_error "Invalid Container ID range. The first number must be smaller than the second number, was ${CT_ID}" - exit - fi - - LIST_OF_IDS=$(pvesh get /cluster/resources --type vm --output-format json 2>/dev/null | grep -oP '"vmid":\s*\K\d+') || true - if [[ -n "$LIST_OF_IDS" ]]; then - for ((ID = MIN_ID; ID <= MAX_ID; ID++)); do - if ! grep -q "^$ID$" <<<"$LIST_OF_IDS"; then - CT_ID=$ID - break - fi - done - fi - echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}" - - elif [[ "$CT_ID" =~ ^[0-9]+$ ]]; then - LIST_OF_IDS=$(pvesh get /cluster/resources --type vm --output-format json 2>/dev/null | grep -oP '"vmid":\s*\K\d+') || true - if [[ -n "$LIST_OF_IDS" ]]; then - - if ! grep -q "^$CT_ID$" <<<"$LIST_OF_IDS"; then - echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}" - else - msg_error "Container ID $CT_ID already exists" - exit - fi - else - echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}" - fi - else - msg_error "Invalid Container ID format. Needs to be 0000-9999 or 0-9999, was ${CT_ID}" - exit - fi - fi - - if [[ "$CT_TYPE" -eq 0 ]]; then - CT_TYPE_DESC="Privileged" - elif [[ "$CT_TYPE" -eq 1 ]]; then - CT_TYPE_DESC="Unprivileged" - else - msg_error "Unknown setting for CT_TYPE, should be 1 or 0, was ${CT_TYPE}" - exit - fi - echo -e "${CONTAINERTYPE}${BOLD}${DGN}Container Type: ${BGN}$CT_TYPE_DESC${CL}" - - if [[ ! -z "$PW" ]]; then - - if [[ "$PW" == *" "* ]]; then - msg_error "Password cannot be empty" - exit - elif [[ ${#PW} -lt 5 ]]; then - msg_error "Password must be at least 5 characters long" - exit - else - echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}********${CL}" - fi - PW="-password $PW" - else - PW="" - echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}Automatic Login${CL}" - fi - echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}" - - if [[ ! -z "$HN" ]]; then - echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}" - else - msg_error "Hostname cannot be empty" - exit - fi - - if [[ ! -z "$DISK_SIZE" ]]; then - if [[ "$DISK_SIZE" =~ ^-?[0-9]+$ ]]; then - echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}" - else - msg_error "DISK_SIZE must be an integer, was ${DISK_SIZE}" - exit - fi - else - msg_error "DISK_SIZE cannot be empty" - exit - fi - - if [[ ! -z "$CORE_COUNT" ]]; then - if [[ "$CORE_COUNT" =~ ^-?[0-9]+$ ]]; then - echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT}${CL}" - else - msg_error "CORE_COUNT must be an integer, was ${CORE_COUNT}" - exit - fi - else - msg_error "CORE_COUNT cannot be empty" - exit - fi - - if [[ ! -z "$RAM_SIZE" ]]; then - if [[ "$RAM_SIZE" =~ ^-?[0-9]+$ ]]; then - echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}" - else - msg_error "RAM_SIZE must be an integer, was ${RAM_SIZE}" - exit - fi - else - msg_error "RAM_SIZE cannot be empty" - exit - fi - - if [[ ! -z "$BRG" ]]; then - if grep -q "^iface ${BRG}" /etc/network/interfaces; then - echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}" - else - msg_error "Bridge '${BRG}' does not exist in /etc/network/interfaces" - exit - fi - else - msg_error "Bridge cannot be empty" - exit - fi - - local ip_cidr_regex='^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/([0-9]{1,2})$' - local ip_regex='^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$' - - if [[ ! -z $NET ]]; then - if [ "$NET" == "dhcp" ]; then - echo -e "${NETWORK}${BOLD}${DGN}IP Address: ${BGN}DHCP${CL}" - echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}Default${CL}" - elif [[ "$NET" =~ $ip_cidr_regex ]]; then - echo -e "${NETWORK}${BOLD}${DGN}IP Address: ${BGN}$NET${CL}" - if [ ! -z "$GATE" ]; then - if [[ "$GATE" =~ $ip_regex ]]; then - echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}$GATE${CL}" - GATE=",gw=$GATE" - else - msg_error "Invalid IP Address format for Gateway. Needs to be 0.0.0.0, was ${GATE}" - exit - fi - else - msg_error "Gateway IP Address cannot be empty" - exit - fi - else - msg_error "Invalid IP Address format. Needs to be 0.0.0.0/0, was ${NET}" - exit - fi - fi - - - if [[ ! -z "$APT_CACHER_IP" ]]; then - if [[ "$APT_CACHER_IP" =~ $ip_regex ]]; then - APT_CACHER="yes" - echo -e "${NETWORK}${BOLD}${DGN}APT-CACHER IP Address: ${BGN}$APT_CACHER_IP${CL}" - else - msg_error "Invalid IP Address format for APT-Cacher. Needs to be 0.0.0.0, was ${APT_CACHER_IP}" - exit - fi - fi - - if [[ "$DISABLEIP6" == "yes" ]]; then - echo -e "${DISABLEIPV6}${BOLD}${DGN}Disable IPv6: ${BGN}Yes${CL}" - elif [[ "$DISABLEIP6" == "no" ]]; then - echo -e "${DISABLEIPV6}${BOLD}${DGN}Disable IPv6: ${BGN}No${CL}" - else - msg_error "Disable IPv6 needs to be 'yes' or 'no'" - exit - fi - - if [[ ! -z "$MTU" ]]; then - if [[ "$MTU" =~ ^-?[0-9]+$ ]]; then - echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$MTU${CL}" - MTU=",mtu=$MTU" - else - msg_error "MTU must be an integer, was ${MTU}" - exit - fi - else - MTU="" - echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}Default${CL}" - - fi - - if [[ ! -z "$SD" ]]; then - echo -e "${SEARCH}${BOLD}${DGN}DNS Search Domain: ${BGN}$SD${CL}" - SD="-searchdomain=$SD" - else - SD="" - echo -e "${SEARCH}${BOLD}${DGN}DNS Search Domain: ${BGN}HOST${CL}" - fi - - if [[ ! -z "$NS" ]]; then - if [[ "$NS" =~ $ip_regex ]]; then - echo -e "${NETWORK}${BOLD}${DGN}DNS Server IP Address: ${BGN}$NS${CL}" - NS="-nameserver=$NS" - else - msg_error "Invalid IP Address format for DNS Server. Needs to be 0.0.0.0, was ${NS}" - exit - fi - else - NS="" - echo -e "${NETWORK}${BOLD}${DGN}DNS Server IP Address: ${BGN}HOST${CL}" - fi - - if [[ ! -z "$MAC" ]]; then - if [[ "$MAC" =~ ^([A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}$ ]]; then - echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC${CL}" - MAC=",hwaddr=$MAC" - else - msg_error "MAC Address must be in the format xx:xx:xx:xx:xx:xx, was ${MAC}" - exit - fi - fi - - if [[ ! -z "$VLAN" ]]; then - if [[ "$VLAN" =~ ^-?[0-9]+$ ]]; then - echo -e "${VLANTAG}${BOLD}${DGN}Vlan: ${BGN}$VLAN${CL}" - VLAN=",tag=$VLAN" - else - msg_error "VLAN must be an integer, was ${VLAN}" - exit - fi - fi - - if [[ ! -z "$TAGS" ]]; then - echo -e "${NETWORK}${BOLD}${DGN}Tags: ${BGN}$TAGS${CL}" - fi - - if [[ "$SSH" == "yes" ]]; then - echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}" - if [[ ! -z "$SSH_AUTHORIZED_KEY" ]]; then - echo -e "${ROOTSSH}${BOLD}${DGN}SSH Authorized Key: ${BGN}********************${CL}" - else - echo -e "${ROOTSSH}${BOLD}${DGN}SSH Authorized Key: ${BGN}None${CL}" - fi - elif [[ "$SSH" == "no" ]]; then - echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}" - else - msg_error "SSH needs to be 'yes' or 'no', was ${SSH}" - exit - fi - - if [[ "$VERB" == "yes" ]]; then - echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}$VERB${CL}" - elif [[ "$VERB" == "no" ]]; then - echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}No${CL}" - else - msg_error "Verbose Mode needs to be 'yes' or 'no', was ${VERB}" - exit - fi - - if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS WITH CONFIG FILE COMPLETE" --yesno "Ready to create ${APP} LXC?" 10 58); then - echo -e "${CREATING}${BOLD}${RD}Creating a ${APP} LXC using the above settings${CL}" - else - clear - header_info - echo -e "${INFO}${HOLD} ${GN}Using Config File on node $PVEHOST_NAME${CL}" - config_file - fi - -} install_script() { pve_check @@ -1147,7 +938,7 @@ install_script() { header_info echo -e "${INFO}${HOLD} ${GN}Using Config File on node $PVEHOST_NAME${CL}" METHOD="advanced" - base_settings + source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/config-file.func) config_file break ;; diff --git a/misc/config-file.func b/misc/config-file.func new file mode 100644 index 000000000..2f4fe1637 --- /dev/null +++ b/misc/config-file.func @@ -0,0 +1,576 @@ +config_file() { + CONFIG_FILE="/opt/community-scripts/.settings" + + if [[ -f "/opt/community-scripts/${NSAPP}.conf" ]]; then + CONFIG_FILE="/opt/community-scripts/${NSAPP}.conf" + fi + + if CONFIG_FILE=$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --inputbox "Set absolute path to config file" 8 58 "$CONFIG_FILE" --title "CONFIG FILE" 3>&1 1>&2 2>&3); then + if [[ ! -f "$CONFIG_FILE" ]]; then + echo -e "${CROSS}${RD}Config file not found, exiting script!.${CL}" + exit + else + echo -e "${INFO}${BOLD}${DGN}Using config File: ${BGN}$CONFIG_FILE${CL}" + source "$CONFIG_FILE" + fi + fi + if [[ -n "${CT_ID-}" ]]; then + if [[ "$CT_ID" =~ ^([0-9]{3,4})-([0-9]{3,4})$ ]]; then + MIN_ID=${BASH_REMATCH[1]} + MAX_ID=${BASH_REMATCH[2]} + if ((MIN_ID >= MAX_ID)); then + msg_error "Invalid Container ID range. The first number must be smaller than the second number, was ${CT_ID}" + exit + fi + + LIST_OF_IDS=$(pvesh get /cluster/resources --type vm --output-format json 2>/dev/null | grep -oP '"vmid":\s*\K\d+') || true + if [[ -n "$LIST_OF_IDS" ]]; then + for ((ID = MIN_ID; ID <= MAX_ID; ID++)); do + if ! grep -q "^$ID$" <<<"$LIST_OF_IDS"; then + CT_ID=$ID + break + fi + done + fi + echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}" + + elif [[ "$CT_ID" =~ ^[0-9]+$ ]]; then + LIST_OF_IDS=$(pvesh get /cluster/resources --type vm --output-format json 2>/dev/null | grep -oP '"vmid":\s*\K\d+') || true + if [[ -n "$LIST_OF_IDS" ]]; then + + if ! grep -q "^$CT_ID$" <<<"$LIST_OF_IDS"; then + echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}" + else + msg_error "Container ID $CT_ID already exists" + exit + fi + else + echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}" + fi + else + msg_error "Invalid Container ID format. Needs to be 0000-9999 or 0-9999, was ${CT_ID}" + exit + fi + else + if CT_ID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Container ID" 8 58 "$NEXTID" --title "CONTAINER ID" 3>&1 1>&2 2>&3); then + if [ -z "$CT_ID" ]; then + CT_ID="$NEXTID" + echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}" + else + echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}" + fi + else + exit_script + fi + + fi + if [[ -n "${CT_TYPE-}" ]]; then + if [[ "$CT_TYPE" -eq 0 ]]; then + CT_TYPE_DESC="Privileged" + elif [[ "$CT_TYPE" -eq 1 ]]; then + CT_TYPE_DESC="Unprivileged" + else + msg_error "Unknown setting for CT_TYPE, should be 1 or 0, was ${CT_TYPE}" + exit + fi + echo -e "${CONTAINERTYPE}${BOLD}${DGN}Container Type: ${BGN}$CT_TYPE_DESC${CL}" + else + if CT_TYPE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CONTAINER TYPE" --radiolist "Choose Type" 10 58 2 \ + "1" "Unprivileged" ON \ + "0" "Privileged" OFF \ + 3>&1 1>&2 2>&3); then + if [ -n "$CT_TYPE" ]; then + CT_TYPE_DESC="Unprivileged" + if [ "$CT_TYPE" -eq 0 ]; then + CT_TYPE_DESC="Privileged" + fi + echo -e "${CONTAINERTYPE}${BOLD}${DGN}Container Type: ${BGN}$CT_TYPE_DESC${CL}" + fi + else + exit_script + fi + fi + + + if [[ -n "${PW-}" ]]; then + if [[ "$PW" == "none" ]]; then + PW="" + else + if [[ "$PW" == *" "* ]]; then + msg_error "Password cannot be empty" + exit + elif [[ ${#PW} -lt 5 ]]; then + msg_error "Password must be at least 5 characters long" + exit + else + echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}********${CL}" + fi + PW="-password $PW" + fi + else + while true; do + if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nSet Root Password (needed for root ssh access)" 9 58 --title "PASSWORD (leave blank for automatic login)" 3>&1 1>&2 2>&3); then + if [[ -n "$PW1" ]]; then + if [[ "$PW1" == *" "* ]]; then + whiptail --msgbox "Password cannot contain spaces. Please try again." 8 58 + elif [ ${#PW1} -lt 5 ]; then + whiptail --msgbox "Password must be at least 5 characters long. Please try again." 8 58 + else + if PW2=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nVerify Root Password" 9 58 --title "PASSWORD VERIFICATION" 3>&1 1>&2 2>&3); then + if [[ "$PW1" == "$PW2" ]]; then + PW="-password $PW1" + echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}********${CL}" + break + else + whiptail --msgbox "Passwords do not match. Please try again." 8 58 + fi + else + exit_script + fi + fi + else + PW1="Automatic Login" + PW="" + echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}$PW1${CL}" + break + fi + else + exit_script + fi + done + fi + + if [[ -n "${HN-}" ]]; then + echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}" + else + if CT_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 "$NSAPP" --title "HOSTNAME" 3>&1 1>&2 2>&3); then + if [ -z "$CT_NAME" ]; then + HN="$NSAPP" + else + HN=$(echo "${CT_NAME,,}" | tr -d ' ') + fi + echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}" + else + exit_script + fi + fi + + if [[ -n "${DISK_SIZE-}" ]]; then + if [[ "$DISK_SIZE" =~ ^-?[0-9]+$ ]]; then + echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}" + else + msg_error "DISK_SIZE must be an integer, was ${DISK_SIZE}" + exit + fi + else + if DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Disk Size in GB" 8 58 "$var_disk" --title "DISK SIZE" 3>&1 1>&2 2>&3); then + if [ -z "$DISK_SIZE" ]; then + DISK_SIZE="$var_disk" + echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}" + else + if ! [[ $DISK_SIZE =~ $INTEGER ]]; then + echo -e "{INFO}${HOLD}${RD} DISK SIZE MUST BE AN INTEGER NUMBER!${CL}" + advanced_settings + fi + echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}" + fi + else + exit_script + fi + fi + + if [[ -n "${CORE_COUNT-}" ]]; then + if [[ "$CORE_COUNT" =~ ^-?[0-9]+$ ]]; then + echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT}${CL}" + else + msg_error "CORE_COUNT must be an integer, was ${CORE_COUNT}" + exit + fi + else + if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 "$var_cpu" --title "CORE COUNT" 3>&1 1>&2 2>&3); then + if [ -z "$CORE_COUNT" ]; then + CORE_COUNT="$var_cpu" + echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}" + else + echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}" + fi + else + exit_script + fi + fi + + if [[ -n "${RAM_SIZE-}" ]]; then + if [[ "$RAM_SIZE" =~ ^-?[0-9]+$ ]]; then + echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}" + else + msg_error "RAM_SIZE must be an integer, was ${RAM_SIZE}" + exit + fi + else + if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 "$var_ram" --title "RAM" 3>&1 1>&2 2>&3); then + if [ -z "$RAM_SIZE" ]; then + RAM_SIZE="$var_ram" + echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}" + else + echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}" + fi + else + exit_script + fi + fi + + IFACE_FILEPATH_LIST="/etc/network/interfaces"$'\n'$(find "/etc/network/interfaces.d/" -type f) + BRIDGES="" + OLD_IFS=$IFS + IFS=$'\n' + + for iface_filepath in ${IFACE_FILEPATH_LIST}; do + + iface_indexes_tmpfile=$(mktemp -q -u '.iface-XXXX') + ( grep -Pn '^\s*iface' "${iface_filepath}" | cut -d':' -f1 && wc -l "${iface_filepath}" | cut -d' ' -f1 ) | awk 'FNR==1 {line=$0; next} {print line":"$0-1; line=$0}' > "${iface_indexes_tmpfile}" || true + + if [ -f "${iface_indexes_tmpfile}" ]; then + + while read -r pair; do + start=$(echo "${pair}" | cut -d':' -f1) + end=$(echo "${pair}" | cut -d':' -f2) + if awk "NR >= ${start} && NR <= ${end}" "${iface_filepath}" | grep -qP '^\s*(bridge[-_](ports|stp|fd|vlan-aware|vids)|ovs_type\s+OVSBridge)\b'; then + iface_name=$(sed "${start}q;d" "${iface_filepath}" | awk '{print $2}') + BRIDGES="${iface_name}"$'\n'"${BRIDGES}" + fi + + done < "${iface_indexes_tmpfile}" + rm -f "${iface_indexes_tmpfile}" + fi + + done + IFS=$OLD_IFS + BRIDGES=$(echo "$BRIDGES" | grep -v '^\s*$' | sort | uniq) + + if [[ -n "${BRG-}" ]]; then + if echo "$BRIDGES" | grep -q "${BRG}"; then + echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}" + else + msg_error "Bridge '${BRG}' does not exist in /etc/network/interfaces or /etc/network/interfaces.d/sdn" + exit + fi + else + BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --menu "Select network bridge:" 15 40 6 $(echo "$BRIDGES" | awk '{print $0, "Bridge"}') 3>&1 1>&2 2>&3) + if [ -z "$BRG" ]; then + exit_script + else + echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}" + fi + fi + + local ip_cidr_regex='^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/([0-9]{1,2})$' + local ip_regex='^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$' + + if [[ -n ${NET-} ]]; then + if [ "$NET" == "dhcp" ]; then + echo -e "${NETWORK}${BOLD}${DGN}IP Address: ${BGN}DHCP${CL}" + echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}Default${CL}" + elif [[ "$NET" =~ $ip_cidr_regex ]]; then + echo -e "${NETWORK}${BOLD}${DGN}IP Address: ${BGN}$NET${CL}" + if [ ! -z "$GATE" ]; then + if [[ "$GATE" =~ $ip_regex ]]; then + echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}$GATE${CL}" + GATE=",gw=$GATE" + else + msg_error "Invalid IP Address format for Gateway. Needs to be 0.0.0.0, was ${GATE}" + exit + fi + else + msg_error "Gateway IP Address cannot be empty" + exit + fi + else + msg_error "Invalid IP Address format. Needs to be 0.0.0.0/0, was ${NET}" + exit + fi + else + while true; do + NET=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Static IPv4 CIDR Address (/24)" 8 58 dhcp --title "IP ADDRESS" 3>&1 1>&2 2>&3) + exit_status=$? + if [ $exit_status -eq 0 ]; then + if [ "$NET" = "dhcp" ]; then + echo -e "${NETWORK}${BOLD}${DGN}IP Address: ${BGN}$NET${CL}" + break + else + if [[ "$NET" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}/([0-9]|[1-2][0-9]|3[0-2])$ ]]; then + echo -e "${NETWORK}${BOLD}${DGN}IP Address: ${BGN}$NET${CL}" + break + else + whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "$NET is an invalid IPv4 CIDR address. Please enter a valid IPv4 CIDR address or 'dhcp'" 8 58 + fi + fi + else + exit_script + fi + done + if [ "$NET" != "dhcp" ]; then + while true; do + GATE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Enter gateway IP address" 8 58 --title "Gateway IP" 3>&1 1>&2 2>&3) + if [ -z "$GATE1" ]; then + whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "Gateway IP address cannot be empty" 8 58 + elif [[ ! "$GATE1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then + whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "Invalid IP address format" 8 58 + else + GATE=",gw=$GATE1" + echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}$GATE1${CL}" + break + fi + done + else + GATE="" + echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}Default${CL}" + fi + fi + + if [ "$var_os" == "alpine" ]; then + APT_CACHER="" + APT_CACHER_IP="" + else + if [[ -n "${APT_CACHER_IP-}" ]]; then + if [[ ! $APT_CACHER_IP == "none" ]]; then + if [[ "$APT_CACHER_IP" =~ $ip_regex ]]; then + APT_CACHER="yes" + echo -e "${NETWORK}${BOLD}${DGN}APT-CACHER IP Address: ${BGN}$APT_CACHER_IP${CL}" + else + msg_error "Invalid IP Address format for APT-Cacher. Needs to be 0.0.0.0, was ${APT_CACHER_IP}" + exit + fi + else + APT_CACHER="" + echo -e "${NETWORK}${BOLD}${DGN}APT-Cacher IP Address: ${BGN}No${CL}" + fi + else + if APT_CACHER_IP=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set APT-Cacher IP (leave blank for none)" 8 58 --title "APT-Cacher IP" 3>&1 1>&2 2>&3); then + APT_CACHER="${APT_CACHER_IP:+yes}" + echo -e "${NETWORK}${BOLD}${DGN}APT-Cacher IP Address: ${BGN}${APT_CACHER_IP:-Default}${CL}" + if [[ -n $APT_CACHER_IP ]]; then + APT_CACHER_IP="none" + fi + else + exit_script + fi + fi + fi + + if [[ "${DISABLEIP6-}" == "yes" ]]; then + echo -e "${DISABLEIPV6}${BOLD}${DGN}Disable IPv6: ${BGN}Yes${CL}" + elif [[ "${DISABLEIP6-}" == "no" ]]; then + echo -e "${DISABLEIPV6}${BOLD}${DGN}Disable IPv6: ${BGN}No${CL}" + else + if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "IPv6" --yesno "Disable IPv6?" 10 58); then + DISABLEIP6="yes" + else + DISABLEIP6="no" + fi + echo -e "${DISABLEIPV6}${BOLD}${DGN}Disable IPv6: ${BGN}$DISABLEIP6${CL}" + fi + + if [[ -n "${MTU-}" ]]; then + if [[ "$MTU" =~ ^-?[0-9]+$ ]]; then + echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$MTU${CL}" + MTU=",mtu=$MTU" + else + msg_error "MTU must be an integer, was ${MTU}" + exit + fi + else + if MTU1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Interface MTU Size (leave blank for default [The MTU of your selected vmbr, default is 1500])" 8 58 --title "MTU SIZE" 3>&1 1>&2 2>&3); then + if [ -z "$MTU1" ]; then + MTU1="Default" + MTU="" + else + MTU=",mtu=$MTU1" + fi + echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$MTU1${CL}" + else + exit_script + fi + fi + + if [[ -n "${SD-}" ]]; then + if [[ "$SD" == "none" ]]; then + SD="" + echo -e "${SEARCH}${BOLD}${DGN}DNS Search Domain: ${BGN}Host${CL}" + else + echo -e "${SEARCH}${BOLD}${DGN}DNS Search Domain: ${BGN}$SD${CL}" + SD="-searchdomain=$SD" + fi + else + if SD=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a DNS Search Domain (leave blank for HOST)" 8 58 --title "DNS Search Domain" 3>&1 1>&2 2>&3); then + if [ -z "$SD" ]; then + SX=Host + SD="" + else + SX=$SD + SD="-searchdomain=$SD" + fi + echo -e "${SEARCH}${BOLD}${DGN}DNS Search Domain: ${BGN}$SX${CL}" + else + exit_script + fi + fi + + if [[ -n "${NS-}" ]]; then + if [[ $NS == "none" ]]; then + NS="" + echo -e "${NETWORK}${BOLD}${DGN}DNS Server IP Address: ${BGN}Host${CL}" + else + if [[ "$NS" =~ $ip_regex ]]; then + echo -e "${NETWORK}${BOLD}${DGN}DNS Server IP Address: ${BGN}$NS${CL}" + NS="-nameserver=$NS" + else + msg_error "Invalid IP Address format for DNS Server. Needs to be 0.0.0.0, was ${NS}" + exit + fi + fi + else + if NX=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a DNS Server IP (leave blank for HOST)" 8 58 --title "DNS SERVER IP" 3>&1 1>&2 2>&3); then + if [ -z "$NX" ]; then + NX=Host + NS="" + else + NS="-nameserver=$NX" + fi + echo -e "${NETWORK}${BOLD}${DGN}DNS Server IP Address: ${BGN}$NX${CL}" + else + exit_script + fi + fi + + if [[ -n "${MAC-}" ]]; then + if [[ "$MAC" == "none" ]]; then + MAC="" + echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}Host${CL}" + else + if [[ "$MAC" =~ ^([A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}$ ]]; then + echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC${CL}" + MAC=",hwaddr=$MAC" + else + msg_error "MAC Address must be in the format xx:xx:xx:xx:xx:xx, was ${MAC}" + exit + fi + fi + else + if MAC1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a MAC Address(leave blank for generated MAC)" 8 58 --title "MAC ADDRESS" 3>&1 1>&2 2>&3); then + if [ -z "$MAC1" ]; then + MAC1="Default" + MAC="" + else + MAC=",hwaddr=$MAC1" + echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC1${CL}" + fi + else + exit_script + fi + fi + + if [[ -n "${VLAN-}" ]]; then + if [[ "$VLAN" == "none" ]]; then + VLAN="" + echo -e "${VLANTAG}${BOLD}${DGN}Vlan: ${BGN}Host${CL}" + else + if [[ "$VLAN" =~ ^-?[0-9]+$ ]]; then + echo -e "${VLANTAG}${BOLD}${DGN}Vlan: ${BGN}$VLAN${CL}" + VLAN=",tag=$VLAN" + else + msg_error "VLAN must be an integer, was ${VLAN}" + exit + fi + fi + else + if VLAN1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Vlan(leave blank for no VLAN)" 8 58 --title "VLAN" 3>&1 1>&2 2>&3); then + if [ -z "$VLAN1" ]; then + VLAN1="Default" + VLAN="" + else + VLAN=",tag=$VLAN1" + fi + echo -e "${VLANTAG}${BOLD}${DGN}Vlan: ${BGN}$VLAN1${CL}" + else + exit_script + fi + fi + + if [[ -n "${TAGS-}" ]]; then + echo -e "${NETWORK}${BOLD}${DGN}Tags: ${BGN}$TAGS${CL}" + else + TAGS="community-scripts;" + if ADV_TAGS=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Custom Tags?[If you remove all, there will be no tags!]" 8 58 "${TAGS}" --title "Advanced Tags" 3>&1 1>&2 2>&3); then + if [ -n "${ADV_TAGS}" ]; then + ADV_TAGS=$(echo "$ADV_TAGS" | tr -d '[:space:]') + TAGS="${ADV_TAGS}" + else + TAGS=";" + fi + echo -e "${NETWORK}${BOLD}${DGN}Tags: ${BGN}$TAGS${CL}" + else + exit_script + fi + fi + + if [[ -n "${SSH-}" ]]; then + if [[ "$SSH" == "yes" ]]; then + echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}" + if [[ ! -z "$SSH_AUTHORIZED_KEY" ]]; then + echo -e "${ROOTSSH}${BOLD}${DGN}SSH Authorized Key: ${BGN}********************${CL}" + else + echo -e "${ROOTSSH}${BOLD}${DGN}SSH Authorized Key: ${BGN}None${CL}" + fi + elif [[ "$SSH" == "no" ]]; then + echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}" + else + msg_error "SSH needs to be 'yes' or 'no', was ${SSH}" + exit + fi + else + SSH_AUTHORIZED_KEY="$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --inputbox "SSH Authorized key for root (leave empty for none)" 8 58 --title "SSH Key" 3>&1 1>&2 2>&3)" + if [[ -z "${SSH_AUTHORIZED_KEY}" ]]; then + SSH_AUTHORIZED_KEY="" + fi + if [[ "$PW" == -password* || -n "$SSH_AUTHORIZED_KEY" ]]; then + if (whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "SSH ACCESS" --yesno "Enable Root SSH Access?" 10 58); then + SSH="yes" + else + SSH="no" + fi + echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}" + else + SSH="no" + echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}" + fi + fi + + if [[ -n "${VERBOSE-}" ]]; then + if [[ "$VERBOSE" == "yes" ]]; then + echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}$VERBOSE${CL}" + elif [[ "$VERBOSE" == "no" ]]; then + echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}No${CL}" + else + msg_error "Verbose Mode needs to be 'yes' or 'no', was ${VERBOSE}" + exit + fi + else + if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "VERBOSE MODE" --yesno "Enable Verbose Mode?" 10 58); then + VERBOSE="yes" + else + VERBOSE="no" + fi + echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}$VERBOSE${CL}" + fi + + if (whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS WITH CONFIG FILE COMPLETE" --yesno "Ready to create ${APP} LXC?" 10 58); then + echo -e "${CREATING}${BOLD}${RD}Creating a ${APP} LXC using the above settings${CL}" + write_config + else + clear + header_info + echo -e "${INFO}${HOLD} ${GN}Using Config File on node $PVEHOST_NAME${CL}" + config_file + fi + +} diff --git a/misc/install.func b/misc/install.func index b97416788..63967265c 100644 --- a/misc/install.func +++ b/misc/install.func @@ -18,6 +18,7 @@ color() { BOLD=$(echo "\033[1m") HOLD=" " TAB=" " + TAB3=" " # System RETRY_NUM=10 diff --git a/misc/tools.func b/misc/tools.func index 1aa597733..5a91033ce 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -1,4 +1,17 @@ #!/bin/bash + +# ------------------------------------------------------------------------------ +# Installs Node.js and optional global modules. +# +# Description: +# - Installs specified Node.js version using NodeSource APT repo +# - Optionally installs or updates global npm modules +# +# Variables: +# NODE_VERSION - Node.js version to install (default: 22) +# NODE_MODULE - Comma-separated list of global modules (e.g. "yarn,@vue/cli@5.0.0") +# ------------------------------------------------------------------------------ + install_node_and_modules() { local NODE_VERSION="${NODE_VERSION:-22}" local NODE_MODULE="${NODE_MODULE:-}" @@ -99,6 +112,19 @@ install_node_and_modules() { fi } +# ------------------------------------------------------------------------------ +# Installs or upgrades PostgreSQL and performs data migration. +# +# Description: +# - Detects existing PostgreSQL version +# - Dumps all databases before upgrade +# - Adds PGDG repo and installs specified version +# - Restores dumped data post-upgrade +# +# Variables: +# PG_VERSION - Major PostgreSQL version (e.g. 15, 16) (default: 16) +# ------------------------------------------------------------------------------ + install_postgresql() { local PG_VERSION="${PG_VERSION:-16}" local CURRENT_PG_VERSION="" @@ -115,7 +141,7 @@ install_postgresql() { msg_info "Detected PostgreSQL $CURRENT_PG_VERSION, preparing upgrade to $PG_VERSION" NEED_PG_INSTALL=true else - msg_info "PostgreSQL not installed, proceeding with fresh install of $PG_VERSION" + msg_info "Setup PostgreSQL $PG_VERSION" NEED_PG_INSTALL=true fi @@ -123,10 +149,10 @@ install_postgresql() { if [[ -n "$CURRENT_PG_VERSION" ]]; then msg_info "Dumping all PostgreSQL data from version $CURRENT_PG_VERSION" su - postgres -c "pg_dumpall > /var/lib/postgresql/backup_$(date +%F)_v${CURRENT_PG_VERSION}.sql" - fi - msg_info "Stopping PostgreSQL service" - systemctl stop postgresql || true + msg_info "Stopping PostgreSQL service" + systemctl stop postgresql + fi msg_info "Removing pgdg repo and old GPG key" rm -f /etc/apt/sources.list.d/pgdg.list /etc/apt/trusted.gpg.d/postgresql.gpg @@ -149,7 +175,7 @@ install_postgresql() { fi $STD msg_info "Starting PostgreSQL $PG_VERSION" - systemctl enable --now postgresql + systemctl enable -q --now postgresql if [[ -n "$CURRENT_PG_VERSION" ]]; then $STD msg_info "Restoring dumped data" @@ -160,6 +186,18 @@ install_postgresql() { fi } +# ------------------------------------------------------------------------------ +# Installs or updates MariaDB from official repo. +# +# Description: +# - Detects current MariaDB version and replaces it if necessary +# - Preserves existing database data +# - Dynamically determines latest GA version if "latest" is given +# +# Variables: +# MARIADB_VERSION - MariaDB version to install (e.g. 10.11, latest) (default: latest) +# ------------------------------------------------------------------------------ + install_mariadb() { local MARIADB_VERSION="${MARIADB_VERSION:-latest}" local DISTRO_CODENAME @@ -167,13 +205,18 @@ install_mariadb() { # grab dynamic latest LTS version if [[ "$MARIADB_VERSION" == "latest" ]]; then - msg_info "Resolving latest MariaDB version" - MARIADB_VERSION=$(curl -fsSL https://mariadb.org | grep -oP 'MariaDB \K10\.[0-9]+' | head -n1) + $STD msg_info "Resolving latest GA MariaDB version" + MARIADB_VERSION=$(curl -fsSL http://mirror.mariadb.org/repo/ | + grep -Eo '[0-9]+\.[0-9]+\.[0-9]+/' | + grep -vE 'rc/|rolling/' | + sed 's|/||' | + sort -Vr | + head -n1) if [[ -z "$MARIADB_VERSION" ]]; then - msg_error "Could not determine latest MariaDB version" + msg_error "Could not determine latest GA MariaDB version" return 1 fi - msg_ok "Latest MariaDB version is $MARIADB_VERSION" + $STD msg_ok "Latest GA MariaDB version is $MARIADB_VERSION" fi local CURRENT_VERSION="" @@ -182,23 +225,23 @@ install_mariadb() { fi if [[ "$CURRENT_VERSION" == "$MARIADB_VERSION" ]]; then - msg_info "MariaDB $MARIADB_VERSION already installed, checking for upgrade" + $STD msg_info "MariaDB $MARIADB_VERSION, upgrading" $STD apt-get update $STD apt-get install --only-upgrade -y mariadb-server mariadb-client - msg_ok "MariaDB $MARIADB_VERSION upgraded if applicable" + $STD msg_ok "MariaDB upgraded to $MARIADB_VERSION" return 0 fi if [[ -n "$CURRENT_VERSION" ]]; then - msg_info "Replacing MariaDB $CURRENT_VERSION with $MARIADB_VERSION (data will be preserved)" + $STD msg_info "Replacing MariaDB $CURRENT_VERSION with $MARIADB_VERSION (data will be preserved)" $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 - msg_info "Installing MariaDB $MARIADB_VERSION" + msg_info "Setup MariaDB $MARIADB_VERSION" fi - msg_info "Setting up MariaDB Repository" + $STD 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 @@ -208,9 +251,21 @@ install_mariadb() { $STD apt-get update $STD apt-get install -y mariadb-server mariadb-client - msg_ok "Installed MariaDB $MARIADB_VERSION" + msg_ok "Setup MariaDB $MARIADB_VERSION" } +# ------------------------------------------------------------------------------ +# Installs or upgrades MySQL and configures APT repo. +# +# Description: +# - Detects existing MySQL installation +# - Purges conflicting packages before installation +# - Supports clean upgrade +# +# Variables: +# MYSQL_VERSION - MySQL version to install (e.g. 5.7, 8.0) (default: 8.0) +# ------------------------------------------------------------------------------ + install_mysql() { local MYSQL_VERSION="${MYSQL_VERSION:-8.0}" local CURRENT_VERSION="" @@ -248,11 +303,33 @@ install_mysql() { fi } +# ------------------------------------------------------------------------------ +# Installs PHP with selected modules and configures Apache/FPM support. +# +# Description: +# - Adds Sury PHP repo if needed +# - Installs default and user-defined modules +# - Patches php.ini for CLI, Apache, and FPM as needed +# +# Variables: +# PHP_VERSION - PHP version to install (default: 8.4) +# PHP_MODULE - Additional comma-separated modules +# PHP_APACHE - Set YES to enable PHP with Apache +# PHP_FPM - Set YES to enable PHP-FPM +# PHP_MEMORY_LIMIT - (default: 512M) +# PHP_UPLOAD_MAX_FILESIZE - (default: 128M) +# PHP_POST_MAX_SIZE - (default: 128M) +# PHP_MAX_EXECUTION_TIME - (default: 300) +# ------------------------------------------------------------------------------ + install_php() { local PHP_VERSION="${PHP_VERSION:-8.4}" 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 DEFAULT_MODULES="bcmath,cli,curl,gd,intl,mbstring,opcache,readline,xml,zip" local COMBINED_MODULES @@ -279,11 +356,11 @@ install_php() { fi if [[ "$CURRENT_PHP" != "$PHP_VERSION" ]]; then - $STD echo "PHP $CURRENT_PHP detected, migrating to PHP $PHP_VERSION" + $STD msg_info "PHP $CURRENT_PHP detected, migrating to PHP $PHP_VERSION" if [[ ! -f /etc/apt/sources.list.d/php.list ]]; 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/ $(lsb_release -sc) main" \ + 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 fi @@ -329,16 +406,24 @@ install_php() { for ini in "${PHP_INI_PATHS[@]}"; do if [[ -f "$ini" ]]; then - msg_info "Patching $ini" + $STD 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" - msg_ok "Patched $ini" + $STD msg_ok "Patched $ini" fi done } +# ------------------------------------------------------------------------------ +# Installs or updates Composer globally. +# +# Description: +# - Downloads latest version from getcomposer.org +# - Installs to /usr/local/bin/composer +# ------------------------------------------------------------------------------ + install_composer() { local COMPOSER_BIN="/usr/local/bin/composer" export COMPOSER_ALLOW_SUPERUSER=1 @@ -347,14 +432,14 @@ install_composer() { if [[ -x "$COMPOSER_BIN" ]]; then local CURRENT_VERSION CURRENT_VERSION=$("$COMPOSER_BIN" --version | awk '{print $3}') - msg_info "Composer $CURRENT_VERSION found, updating to latest" + $STD msg_info "Composer $CURRENT_VERSION found, updating to latest" else - msg_info "Composer not found, installing latest version" + msg_info "Setup Composer" fi # Download and install latest composer curl -fsSL https://getcomposer.org/installer -o /tmp/composer-setup.php - php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer >/dev/null 2>&1 + php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer &>/dev/null if [[ $? -ne 0 ]]; then msg_error "Failed to install Composer" @@ -365,6 +450,17 @@ install_composer() { msg_ok "Installed Composer $($COMPOSER_BIN --version | awk '{print $3}')" } +# ------------------------------------------------------------------------------ +# Installs Go (Golang) from official tarball. +# +# Description: +# - Determines system architecture +# - Downloads latest version if GO_VERSION not set +# +# Variables: +# GO_VERSION - Version to install (e.g. 1.22.2 or latest) +# ------------------------------------------------------------------------------ + install_go() { local ARCH case "$(uname -m)" in @@ -420,6 +516,17 @@ install_go() { msg_ok "Installed Go $GO_VERSION" } +# ------------------------------------------------------------------------------ +# Installs Temurin JDK via Adoptium APT repository. +# +# Description: +# - Removes previous JDK if version mismatch +# - Installs or upgrades to specified JAVA_VERSION +# +# Variables: +# JAVA_VERSION - Temurin JDK version to install (e.g. 17, 21) +# ------------------------------------------------------------------------------ + install_java() { local JAVA_VERSION="${JAVA_VERSION:-21}" local DISTRO_CODENAME @@ -460,6 +567,17 @@ install_java() { fi } +# ------------------------------------------------------------------------------ +# Installs or updates MongoDB to specified major version. +# +# Description: +# - Preserves data across installations +# - Adds official MongoDB repo +# +# Variables: +# MONGO_VERSION - MongoDB major version to install (e.g. 7.0, 8.0) +# ------------------------------------------------------------------------------ + install_mongodb() { local MONGO_VERSION="${MONGO_VERSION:-8.0}" local DISTRO_CODENAME @@ -508,6 +626,19 @@ install_mongodb() { msg_ok "MongoDB $MONGO_VERSION installed and started" } +# ------------------------------------------------------------------------------ +# Downloads and deploys latest GitHub release tarball. +# +# Description: +# - Fetches latest release from GitHub API +# - Detects matching asset by architecture +# - Extracts to /opt/ and saves version +# +# Variables: +# APP - Override default application name (optional) +# GITHUB_TOKEN - (optional) GitHub token for private rate limits +# ------------------------------------------------------------------------------ + fetch_and_deploy_gh_release() { local repo="$1" local app=${APP:-$(echo "${APPLICATION,,}" | tr -d ' ')} @@ -518,13 +649,11 @@ fetch_and_deploy_gh_release() { local api_response tag http_code local current_version="" local curl_timeout="--connect-timeout 10 --max-time 30" - # Check if the app directory exists and if there's a version file if [[ -f "/opt/${app}_version.txt" ]]; then current_version=$(cat "/opt/${app}_version.txt") $STD msg_info "Current version: $current_version" fi - # ensure that jq is installed if ! command -v jq &>/dev/null; then $STD msg_info "Installing jq..." @@ -534,58 +663,45 @@ fetch_and_deploy_gh_release() { return 1 } fi - [[ -n "${GITHUB_TOKEN:-}" ]] && header=(-H "Authorization: token $GITHUB_TOKEN") - until [[ $attempt -ge $max_attempts ]]; do ((attempt++)) || true $STD msg_info "[$attempt/$max_attempts] Fetching GitHub release for $repo...\n" - api_response=$(curl $curl_timeout -fsSL -w "%{http_code}" -o /tmp/gh_resp.json "${header[@]}" "$api_url") http_code="${api_response:(-3)}" - if [[ "$http_code" == "404" ]]; then msg_error "Repository $repo has no Release candidate (404)" return 1 fi - if [[ "$http_code" != "200" ]]; then $STD msg_info "Request failed with HTTP $http_code, retrying...\n" sleep $((attempt * 2)) continue fi - api_response=$(/dev/null; then msg_error "Repository not found: $repo" return 1 fi - tag=$(echo "$api_response" | jq -r '.tag_name // .name // empty') [[ "$tag" =~ ^v[0-9] ]] && tag="${tag:1}" version="${tag#v}" - if [[ -z "$tag" ]]; then $STD msg_info "Empty tag received, retrying...\n" sleep $((attempt * 2)) continue fi - $STD msg_ok "Found release: $tag for $repo" break done - if [[ -z "$tag" ]]; then msg_error "Failed to fetch release for $repo after $max_attempts attempts." exit 1 fi - # Version comparison (if we already have this version, skip) if [[ "$current_version" == "$tag" ]]; then $STD msg_info "Already running the latest version ($tag). Skipping update." @@ -595,11 +711,9 @@ fetch_and_deploy_gh_release() { local base_url="https://github.com/$repo/releases/download/v$tag" local tmpdir tmpdir=$(mktemp -d) || return 1 - # Extract list of assets from the Release API local assets urls assets=$(echo "$api_response" | jq -r '.assets[].browser_download_url') || true - # Detect current architecture local arch if command -v dpkg &>/dev/null; then @@ -616,7 +730,6 @@ fetch_and_deploy_gh_release() { arch="unknown" fi $STD msg_info "Detected system architecture: $arch" - # Try to find a matching asset for our architecture local url="" for u in $assets; do @@ -626,7 +739,6 @@ fetch_and_deploy_gh_release() { break fi done - # Fallback to other architectures if our specific one isn't found if [[ -z "$url" ]]; then for u in $assets; do @@ -637,7 +749,6 @@ fetch_and_deploy_gh_release() { fi done fi - # Fallback to any tar.gz if [[ -z "$url" ]]; then for u in $assets; do @@ -648,7 +759,6 @@ fetch_and_deploy_gh_release() { fi done fi - # Final fallback to GitHub source tarball if [[ -z "$url" ]]; then # Use tarball_url directly from API response instead of constructing our own URL @@ -661,18 +771,14 @@ fetch_and_deploy_gh_release() { $STD msg_info "Using GitHub source tarball: $url" fi - local filename="${url##*/}" $STD msg_info "Downloading $url" - if ! curl $curl_timeout -fsSL -o "$tmpdir/$filename" "$url"; then msg_error "Failed to download release asset from $url" rm -rf "$tmpdir" return 1 fi - mkdir -p "/opt/$app" - tar -xzf "$tmpdir/$filename" -C "$tmpdir" local content_root content_root=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d) @@ -681,12 +787,19 @@ fetch_and_deploy_gh_release() { else cp -r "$tmpdir"/* "/opt/$app/" fi - echo "$version" >"/opt/${app}_version.txt" $STD msg_ok "Deployed $app v$version to /opt/$app" rm -rf "$tmpdir" } +# ------------------------------------------------------------------------------ +# Installs a local IP updater script using networkd-dispatcher. +# +# Description: +# - Stores current IP in /run/local-ip.env +# - Automatically runs on network changes +# ------------------------------------------------------------------------------ + setup_local_ip_helper() { local BASE_DIR="/usr/local/community-scripts/ip-management" local SCRIPT_PATH="$BASE_DIR/update_local_ip.sh" @@ -759,6 +872,13 @@ EOF $STD msg_ok "LOCAL_IP helper installed using networkd-dispatcher" } +# ------------------------------------------------------------------------------ +# Loads LOCAL_IP from persistent store or detects if missing. +# +# Description: +# - Loads from /run/local-ip.env or performs runtime lookup +# ------------------------------------------------------------------------------ + import_local_ip() { local IP_FILE="/run/local-ip.env" if [[ -f "$IP_FILE" ]]; then @@ -796,6 +916,14 @@ import_local_ip() { export LOCAL_IP } +# ------------------------------------------------------------------------------ +# Downloads file with optional progress indicator using pv. +# +# Arguments: +# $1 - URL +# $2 - Destination path +# ------------------------------------------------------------------------------ + function download_with_progress() { local url="$1" local output="$2" @@ -824,6 +952,14 @@ function download_with_progress() { fi } +# ------------------------------------------------------------------------------ +# Installs or upgrades uv (Python package manager) from GitHub releases. +# +# Description: +# - Downloads architecture-specific tarball +# - Places binary in /usr/local/bin +# ------------------------------------------------------------------------------ + function setup_uv() { $STD msg_info "Checking uv installation..." UV_BIN="/usr/local/bin/uv" @@ -877,6 +1013,13 @@ function setup_uv() { msg_ok "uv installed/updated to $LATEST_VERSION" } +# ------------------------------------------------------------------------------ +# Ensures /usr/local/bin is permanently in system PATH. +# +# Description: +# - Adds to /etc/profile.d if not present +# ------------------------------------------------------------------------------ + function ensure_usr_local_bin_persist() { local PROFILE_FILE="/etc/profile.d/custom_path.sh" @@ -886,6 +1029,14 @@ function ensure_usr_local_bin_persist() { fi } +# ------------------------------------------------------------------------------ +# Installs or updates Ghostscript (gs) from source. +# +# Description: +# - Fetches latest release +# - Builds and installs system-wide +# ------------------------------------------------------------------------------ + function setup_gs() { msg_info "Setup Ghostscript" mkdir -p /tmp @@ -939,3 +1090,112 @@ function setup_gs() { msg_error "Ghostscript installation failed" fi } + +# ------------------------------------------------------------------------------ +# Installs rbenv and ruby-build, installs Ruby and optionally Rails. +# +# Description: +# - Downloads rbenv and ruby-build from GitHub +# - Compiles and installs target Ruby version +# - Optionally installs Rails via gem +# +# Variables: +# RUBY_VERSION - Ruby version to install (default: 3.4.4) +# RUBY_INSTALL_RAILS - true/false to install Rails (default: true) +# ------------------------------------------------------------------------------ + +setup_rbenv_stack() { + local RUBY_VERSION="${RUBY_VERSION:-3.4.4}" + local RUBY_INSTALL_RAILS="${RUBY_INSTALL_RAILS:-true}" + + local RBENV_DIR="$HOME/.rbenv" + local RBENV_BIN="$RBENV_DIR/bin/rbenv" + local PROFILE_FILE="$HOME/.profile" + local TMP_DIR + TMP_DIR=$(mktemp -d) + + $STD msg_info "Installing rbenv + ruby-build + Ruby $RUBY_VERSION" + + # Fetch latest rbenv release tag from GitHub (e.g. v1.3.2 → 1.3.2) + local RBENV_RELEASE + RBENV_RELEASE=$(curl -fsSL https://api.github.com/repos/rbenv/rbenv/releases/latest | grep '"tag_name":' | cut -d '"' -f4 | sed 's/^v//') + if [[ -z "$RBENV_RELEASE" ]]; then + msg_error "Failed to fetch latest rbenv version" + rm -rf "$TMP_DIR" + return 1 + fi + + # Download and extract rbenv release + curl -fsSL "https://github.com/rbenv/rbenv/archive/refs/tags/v${RBENV_RELEASE}.tar.gz" -o "$TMP_DIR/rbenv.tar.gz" + tar -xzf "$TMP_DIR/rbenv.tar.gz" -C "$TMP_DIR" + mkdir -p "$RBENV_DIR" + cp -r "$TMP_DIR/rbenv-${RBENV_RELEASE}/." "$RBENV_DIR/" + cd "$RBENV_DIR" && src/configure && make -C src + + # Fetch latest ruby-build plugin release tag (e.g. v20250507 → 20250507) + local RUBY_BUILD_RELEASE + RUBY_BUILD_RELEASE=$(curl -fsSL https://api.github.com/repos/rbenv/ruby-build/releases/latest | grep '"tag_name":' | cut -d '"' -f4 | sed 's/^v//') + if [[ -z "$RUBY_BUILD_RELEASE" ]]; then + msg_error "Failed to fetch latest ruby-build version" + rm -rf "$TMP_DIR" + return 1 + fi + + # Download and install ruby-build plugin + curl -fsSL "https://github.com/rbenv/ruby-build/archive/refs/tags/v${RUBY_BUILD_RELEASE}.tar.gz" -o "$TMP_DIR/ruby-build.tar.gz" + tar -xzf "$TMP_DIR/ruby-build.tar.gz" -C "$TMP_DIR" + mkdir -p "$RBENV_DIR/plugins/ruby-build" + cp -r "$TMP_DIR/ruby-build-${RUBY_BUILD_RELEASE}/." "$RBENV_DIR/plugins/ruby-build/" + echo "$RUBY_BUILD_RELEASE" >"$RBENV_DIR/plugins/ruby-build/RUBY_BUILD_version.txt" + + # Persist rbenv init to user's profile + if ! grep -q 'rbenv init' "$PROFILE_FILE"; then + echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >>"$PROFILE_FILE" + echo 'eval "$(rbenv init -)"' >>"$PROFILE_FILE" + fi + + # Activate rbenv in current shell + export PATH="$RBENV_DIR/bin:$PATH" + eval "$("$RBENV_BIN" init - bash)" + + # Install Ruby version if not already present + if "$RBENV_BIN" versions --bare | grep -qx "$RUBY_VERSION"; then + msg_ok "Ruby $RUBY_VERSION already installed" + else + $STD msg_info "Installing Ruby $RUBY_VERSION" + $STD "$RBENV_BIN" install "$RUBY_VERSION" + fi + + # Set Ruby version globally + "$RBENV_BIN" global "$RUBY_VERSION" + hash -r + + # Optionally install Rails via gem + if [[ "$RUBY_INSTALL_RAILS" == "true" ]]; then + $STD msg_info "Installing latest Rails via gem" + gem install rails + msg_ok "Rails $(rails -v) installed" + fi + + rm -rf "$TMP_DIR" + msg_ok "rbenv stack ready (Ruby $RUBY_VERSION)" +} + +# ------------------------------------------------------------------------------ +# Creates and installs self-signed certificates. +# +# Description: +# - Create a self-signed certificate with option to override application name +# +# Variables: +# APP - Application name (default: $APPLICATION variable) +# ------------------------------------------------------------------------------ +create_selfsigned_certs() { + local app=${APP:-$(echo "${APPLICATION,,}" | tr -d ' ')} + $STD msg_info "Creating Self-Signed Certificate" + $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" + $STD msg_ok "Created Self-Signed Certificate" +}