Compare commits

...

15 Commits

Author SHA1 Message Date
CanbiZ (MickLesk) 482e1356c0 VM-Core: Update some Functions
fbd
2026-06-15 11:08:36 +02:00
community-scripts-pr-app[bot] 3c42589ff0 Update CHANGELOG.md (#15112)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-15 08:10:04 +00:00
community-scripts-pr-app[bot] 0d271f55a6 Update CHANGELOG.md (#15111)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-15 08:09:42 +00:00
CanbiZ (MickLesk) 6762208d66 core: improve mirror selection and error handling (#15108) 2026-06-15 10:09:38 +02:00
community-scripts-pr-app[bot] dee66b996e Update CHANGELOG.md (#15110)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-15 08:09:30 +00:00
CanbiZ (MickLesk) 4b20b8dab5 tools.func: extend mesa-vulkan-drivers and vulkan-tools to installation for ARC GPU's (#15106) 2026-06-15 10:09:14 +02:00
community-scripts-pr-app[bot] a2f987f07b Update CHANGELOG.md (#15109)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-15 08:08:57 +00:00
CanbiZ (MickLesk) 96d828f379 Vaultwarden: extend version check for VaultWarden update (#15105) 2026-06-15 10:08:49 +02:00
CanbiZ (MickLesk) 293d4b73a1 core: implement gateway validation for DHCP and static networks (#15107) 2026-06-15 10:08:24 +02:00
community-scripts-pr-app[bot] cfb84ae12d Update CHANGELOG.md (#15101)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-14 12:32:32 +00:00
Slaviša Arežina f37bf50a47 Refactor (#15096) 2026-06-14 14:32:06 +02:00
community-scripts-pr-app[bot] 4a09cac506 Update CHANGELOG.md (#15100)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-14 12:00:59 +00:00
community-scripts-pr-app[bot] 5831cc246a Update CHANGELOG.md (#15099)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-14 12:00:36 +00:00
CanbiZ (MickLesk) bcea631c30 Iinvoiceninja: fix nginx setup assets port (#15090) 2026-06-14 14:00:32 +02:00
CanbiZ (MickLesk) d9e6e6ea3d fix(checkmk): remove stale backup site before creating new backup during update (#15088) 2026-06-14 14:00:10 +02:00
28 changed files with 701 additions and 233 deletions
+30
View File
@@ -483,8 +483,38 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details>
## 2026-06-15
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Vaultwarden: extend version check for VaultWarden update [@MickLesk](https://github.com/MickLesk) ([#15105](https://github.com/community-scripts/ProxmoxVE/pull/15105))
### 💾 Core
- #### ✨ New Features
- tools.func: extend mesa-vulkan-drivers and vulkan-tools to installation for ARC GPU's [@MickLesk](https://github.com/MickLesk) ([#15106](https://github.com/community-scripts/ProxmoxVE/pull/15106))
- #### 🔧 Refactor
- core: improve mirror selection and error handling [@MickLesk](https://github.com/MickLesk) ([#15108](https://github.com/community-scripts/ProxmoxVE/pull/15108))
- core: implement gateway validation for DHCP and static networks [@MickLesk](https://github.com/MickLesk) ([#15107](https://github.com/community-scripts/ProxmoxVE/pull/15107))
## 2026-06-14
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Iinvoiceninja: fix nginx setup assets port [@MickLesk](https://github.com/MickLesk) ([#15090](https://github.com/community-scripts/ProxmoxVE/pull/15090))
- CheckMK: remove stale backup site before creating new backup during update [@MickLesk](https://github.com/MickLesk) ([#15088](https://github.com/community-scripts/ProxmoxVE/pull/15088))
- #### 🔧 Refactor
- Refactor: Implement backup functions for scripts C-D [@tremor021](https://github.com/tremor021) ([#15096](https://github.com/community-scripts/ProxmoxVE/pull/15096))
## 2026-06-13
### 🆕 New Scripts
+3 -9
View File
@@ -35,10 +35,8 @@ function update_script() {
systemctl stop calibre-web
msg_ok "Stopped Service"
msg_info "Backing up Data"
cp -r /opt/calibre-web/app.db /opt/app.db_backup
cp -r /opt/calibre-web/data /opt/data_backup
msg_ok "Backed up Data"
create_backup /opt/calibre-web/app.db \
/opt/calibre-web/data
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Calibre-Web" "janeczku/calibre-web" "prebuild" "latest" "/opt/calibre-web" "calibre-web*.tar.gz"
setup_uv
@@ -50,11 +48,7 @@ function update_script() {
$STD uv pip install --python /opt/calibre-web/.venv/bin/python --no-cache-dir -r requirements.txt
msg_ok "Installed Dependencies"
msg_info "Restoring Data"
cp /opt/app.db_backup /opt/calibre-web/app.db 2>/dev/null
cp -r /opt/data_backup /opt/calibre-web/data 2>/dev/null
rm -rf /opt/app.db_backup /opt/data_backup
msg_ok "Restored Data"
restore_backup
msg_info "Starting Service"
systemctl start calibre-web
+2 -7
View File
@@ -35,16 +35,11 @@ function update_script() {
systemctl stop certimate
msg_ok "Stopped Service"
msg_info "Backing up Data"
cp -r /opt/certimate/pb_data /opt/certimate_pb_data_backup
msg_ok "Backed up Data"
create_backup /opt/certimate/pb_data
fetch_and_deploy_gh_release "certimate" "certimate-go/certimate" "prebuild" "latest" "/opt/certimate" "certimate_*_linux_amd64.zip"
msg_info "Restoring Data"
cp -r /opt/certimate_pb_data_backup/. /opt/certimate/pb_data
rm -rf /opt/certimate_pb_data_backup
msg_ok "Restored Data"
restore_backup
msg_info "Starting Service"
systemctl start certimate
+3 -8
View File
@@ -35,10 +35,8 @@ function update_script() {
systemctl stop checkmate-server checkmate-client nginx
msg_ok "Stopped Services"
msg_info "Backing up Data"
cp /opt/checkmate/server/.env /opt/checkmate_server.env.bak
[ -f /opt/checkmate/client/.env.local ] && cp /opt/checkmate/client/.env.local /opt/checkmate_client.env.local.bak
msg_ok "Backed up Data"
create_backup /opt/checkmate/server/.env \
/opt/checkmate/client/.env.local
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "checkmate" "bluewave-labs/Checkmate" "tarball"
@@ -56,10 +54,7 @@ function update_script() {
VITE_APP_API_BASE_URL="/api/v1" UPTIME_APP_API_BASE_URL="/api/v1" VITE_APP_LOG_LEVEL="warn" $STD npm run build
msg_ok "Updated Checkmate Client"
msg_info "Restoring Data"
mv /opt/checkmate_server.env.bak /opt/checkmate/server/.env
[ -f /opt/checkmate_client.env.local.bak ] && mv /opt/checkmate_client.env.local.bak /opt/checkmate/client/.env.local
msg_ok "Restored Data"
restore_backup
msg_info "Starting Services"
systemctl start checkmate-server checkmate-client nginx
+1
View File
@@ -33,6 +33,7 @@ function update_script() {
RELEASE="${RELEASE%%+*}"
msg_info "Updating checkmk"
$STD omd stop monitoring
$STD omd -f rm monitoringbackup 2>/dev/null || true
$STD omd cp monitoring monitoringbackup
curl_download "/opt/checkmk.deb" "https://download.checkmk.com/checkmk/${RELEASE}/check-mk-community-${RELEASE}_0.$(get_os_info codename)_amd64.deb"
$STD apt install -y /opt/checkmk.deb
+2 -7
View File
@@ -33,16 +33,11 @@ function update_script() {
systemctl stop cleanuparr
msg_ok "Stopped Service"
msg_info "Backing up config"
cp -r /opt/cleanuparr/config /opt/cleanuparr_config_backup
msg_ok "Backed up config"
create_backup /opt/cleanuparr/config
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Cleanuparr" "Cleanuparr/Cleanuparr" "prebuild" "latest" "/opt/cleanuparr" "*linux-amd64.zip"
msg_info "Restoring config"
[[ -d /opt/cleanuparr/config ]] && rm -rf /opt/cleanuparr/config
mv /opt/cleanuparr_config_backup /opt/cleanuparr/config
msg_ok "Restored config"
restore_backup
msg_info "Starting Service"
systemctl start cleanuparr
+2 -11
View File
@@ -36,20 +36,11 @@ function update_script() {
msg_ok "Stopped Service"
ensure_dependencies rsync
if [ -d /opt/commafeed/data ] && [ "$(ls -A /opt/commafeed/data)" ]; then
msg_info "Backing up existing data"
mv /opt/commafeed/data /opt/data.bak
msg_ok "Backed up existing data"
fi
create_backup /opt/commafeed/data
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "commafeed" "Athou/commafeed" "prebuild" "latest" "/opt/commafeed" "commafeed-*-h2-jvm.zip"
if [ -d /opt/data.bak ] && [ "$(ls -A /opt/data.bak)" ]; then
msg_info "Restoring data"
mv /opt/data.bak /opt/commafeed/data
msg_ok "Restored data"
fi
restore_backup
msg_info "Starting Service"
systemctl start commafeed
+6 -4
View File
@@ -33,11 +33,13 @@ function update_script() {
systemctl stop configarr-task.timer
msg_ok "Stopped Service"
mkdir -p /opt/backup/
mv /opt/configarr/{config.yml,secrets.yml,.env} /opt/backup/
create_backup /opt/configarr/config.yml \
/opt/configarr/secrets.yml \
/opt/configarr/.env
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "configarr" "raydak-labs/configarr" "prebuild" "latest" "/opt/configarr" "configarr-linux-x64.tar.xz"
mv /opt/backup/{config.yml,secrets.yml,.env} /opt/configarr/
rm -rf /opt/backup
restore_backup
msg_info "Starting Service"
systemctl start configarr-task.timer
+4 -9
View File
@@ -36,19 +36,14 @@ function update_script() {
ensure_dependencies libreoffice-writer
msg_info "Move data-Folder"
if [[ -d /opt/convertx/data ]]; then
mv /opt/convertx/data /opt/data
fi
msg_ok "Moved data-Folder"
create_backup /opt/convertx/data
fetch_and_deploy_gh_release "ConvertX" "C4illin/ConvertX" "tarball" "latest" "/opt/convertx"
restore_backup
msg_info "Updating ConvertX"
if [[ -d /opt/data ]]; then
mv /opt/data /opt/convertx/data
fi
cd /opt/convertx
cd /opt/convertx
$STD bun install
msg_ok "Updated ConvertX"
+7 -13
View File
@@ -30,20 +30,17 @@ function update_script() {
fi
RELEASE=$(curl -fsSL "https://gitlab.com/api/v4/projects/20430749/releases" | grep -o '"tag_name":"v[^"]*"' | head -n 1 | sed 's/"tag_name":"v//;s/"//')
if [[ ! -f /opt/crafty-controller_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/crafty-controller_version.txt)" ]]; then
if [[ ! -f /opt/crafty-controller_version.txt ]] || [[ ${RELEASE} != "$(cat /opt/crafty-controller_version.txt)" ]]; then
msg_info "Stopping Crafty-Controller"
systemctl stop crafty-controller
msg_ok "Stopped Crafty-Controller"
msg_info "Creating Backup of config"
cp -a /opt/crafty-controller/crafty/crafty-4/app/config/. /opt/crafty-controller/backup
rm /opt/crafty-controller/backup/version.json
rm /opt/crafty-controller/backup/credits.json
rm /opt/crafty-controller/backup/logging.json
rm /opt/crafty-controller/backup/default.json.example
rm /opt/crafty-controller/backup/motd_format.json
msg_ok "Backup Created"
create_backup /opt/crafty-controller/crafty/crafty-4/app/config/version.json \
/opt/crafty-controller/crafty/crafty-4/app/config/credits.json \
/opt/crafty-controller/crafty/crafty-4/app/config/logging.json \
/opt/crafty-controller/crafty/crafty-4/app/config/default.json.example \
/opt/crafty-controller/crafty/crafty-4/app/config/motd_format.json
msg_info "Updating Crafty-Controller to v${RELEASE}"
curl -fsSL "https://gitlab.com/crafty-controller/crafty-4/-/archive/v${RELEASE}/crafty-4-v${RELEASE}.zip" -o $(basename "https://gitlab.com/crafty-controller/crafty-4/-/archive/v${RELEASE}/crafty-4-v${RELEASE}.zip")
@@ -58,11 +55,8 @@ function update_script() {
echo "${RELEASE}" >"/opt/crafty-controller_version.txt"
msg_ok "Updated Crafty-Controller to v${RELEASE}"
msg_info "Restoring Backup of config"
cp -a /opt/crafty-controller/backup/. /opt/crafty-controller/crafty/crafty-4/app/config
rm -rf /opt/crafty-controller/backup
restore_backup
chown -R crafty:crafty /opt/crafty-controller/
msg_ok "Backup Restored"
msg_info "Starting Crafty-Controller"
systemctl start crafty-controller
+9 -12
View File
@@ -34,21 +34,18 @@ function update_script() {
systemctl stop cryptpad
msg_info "Stopped Service"
msg_info "Creating backup"
[ -f /opt/cryptpad/config/config.js ] && mv /opt/cryptpad/config/config.js /opt/
for dir in blob block customize data datastore www/common/onlyoffice/dist onlyoffice-conf; do
[ -d "/opt/cryptpad/${dir}" ] && mv "/opt/cryptpad/${dir}" "/tmp/cryptpad_${dir//\//_}"
done
msg_ok "Created backup"
create_backup /opt/cryptpad/config/config.js \
/opt/cryptpad/blob \
/opt/cryptpad/block \
/opt/cryptpad/customize \
/opt/cryptpad/data \
/opt/cryptpad/datastore \
/opt/cryptpad/www/common/onlyoffice/dist \
/opt/cryptpad/onlyoffice-conf
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "cryptpad" "cryptpad/cryptpad" "tarball"
msg_info "Restoring backup"
mv /opt/config.js /opt/cryptpad/config/
for dir in blob block customize data datastore www/common/onlyoffice/dist onlyoffice-conf; do
[ -d "/tmp/cryptpad_${dir//\//_}" ] && mv "/tmp/cryptpad_${dir//\//_}" "/opt/cryptpad/${dir}"
done
msg_ok "Restored backup"
restore_backup
msg_info "Updating CryptPad"
cd /opt/cryptpad
+2 -8
View File
@@ -35,17 +35,11 @@ function update_script() {
systemctl stop dagu
msg_ok "Stopped Service"
msg_info "Backing up Data"
cp -r /opt/dagu/data /opt/dagu_data_backup
msg_ok "Backed up Data"
create_backup /opt/dagu/data
fetch_and_deploy_gh_release "dagu" "dagucloud/dagu" "prebuild" "latest" "/opt/dagu" "dagu_*_linux_amd64.tar.gz"
msg_info "Restoring Data"
mkdir -p /opt/dagu/data
cp -r /opt/dagu_data_backup/. /opt/dagu/data
rm -rf /opt/dagu_data_backup
msg_ok "Restored Data"
restore_backup
msg_info "Starting Service"
systemctl start dagu
+2 -8
View File
@@ -36,10 +36,7 @@ function update_script() {
systemctl stop dashy
msg_ok "Stopped Service"
msg_info "Backing up user-data"
rm -rf /opt/dashy_user_data_backup
cp -r /opt/dashy/user-data /opt/dashy_user_data_backup
msg_ok "Backed up user-data"
create_backup /opt/dashy/user-data
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "dashy" "lissy93/dashy" "prebuild" "latest" "/opt/dashy" "dashy-*.tar.gz"
@@ -48,10 +45,7 @@ function update_script() {
$STD yarn install --ignore-engines --network-timeout 300000
msg_ok "Updated Dashy"
msg_info "Restoring user-data"
cp -r /opt/dashy_user_data_backup/. /opt/dashy/user-data/
rm -rf /opt/dashy_user_data_backup
msg_ok "Restored user-data"
restore_backup
msg_info "Starting Dashy"
systemctl start dashy
+2 -11
View File
@@ -35,12 +35,7 @@ function update_script() {
$STD systemctl stop databasus
msg_ok "Stopped Databasus"
msg_info "Backing up Configuration"
[[ ! -f /.env && -f /opt/databasus/.env ]] && cp /opt/databasus/.env /.env
chmod 600 /.env
cp /.env /opt/databasus.env.bak
chmod 600 /opt/databasus.env.bak
msg_ok "Backed up Configuration"
create_backup /opt/databasus/.env
msg_info "Ensuring Database Clients"
# Create PostgreSQL version symlinks for compatibility
@@ -87,11 +82,7 @@ function update_script() {
chown -R postgres:postgres /opt/databasus
msg_ok "Updated Databasus"
msg_info "Restoring Configuration"
cp /opt/databasus.env.bak /.env
rm -f /opt/databasus.env.bak
chmod 600 /.env
msg_ok "Restored Configuration"
restore_backup
if ! grep -q "EnvironmentFile=/.env" /etc/systemd/system/databasus.service; then
msg_info "Updating Service"
+4 -11
View File
@@ -37,11 +37,9 @@ function update_script() {
systemctl stop dawarich-web dawarich-worker
msg_ok "Stopped Services"
msg_info "Backing up Data"
cp -r /opt/dawarich/app/storage /opt/dawarich_storage_backup 2>/dev/null || true
cp /opt/dawarich/app/config/master.key /opt/dawarich_master.key 2>/dev/null || true
cp /opt/dawarich/app/config/credentials.yml.enc /opt/dawarich_credentials.yml.enc 2>/dev/null || true
msg_ok "Backed up Data"
create_backup /opt/dawarich/app/storage \
/opt/dawarich/app/config/master.key \
/opt/dawarich/app/config/credentials.yml.enc
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "dawarich" "Freika/dawarich" "tarball" "latest" "/opt/dawarich/app"
@@ -85,12 +83,7 @@ function update_script() {
$STD bundle exec rake data:migrate
msg_ok "Ran Migrations"
msg_info "Restoring Data"
cp -r /opt/dawarich_storage_backup/. /opt/dawarich/app/storage/ 2>/dev/null || true
cp /opt/dawarich_master.key /opt/dawarich/app/config/master.key 2>/dev/null || true
cp /opt/dawarich_credentials.yml.enc /opt/dawarich/app/config/credentials.yml.enc 2>/dev/null || true
rm -rf /opt/dawarich_storage_backup /opt/dawarich_master.key /opt/dawarich_credentials.yml.enc
msg_ok "Restored Data"
restore_backup
msg_info "Starting Services"
systemctl start dawarich-web dawarich-worker
+2 -7
View File
@@ -33,16 +33,11 @@ function update_script() {
systemctl stop ddns-updater
msg_ok "Stopped Service"
msg_info "Backing up Data"
cp -r /opt/ddns-updater/data /opt/ddns-updater_data_backup
msg_ok "Backed up Data"
create_backup /opt/ddns-updater/data
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "ddns-updater" "qdm12/ddns-updater" "singlefile" "latest" "/opt/ddns-updater" "ddns-updater_*_linux_amd64"
msg_info "Restoring Data"
cp -r /opt/ddns-updater_data_backup/. /opt/ddns-updater/data/
rm -rf /opt/ddns-updater_data_backup
msg_ok "Restored Data"
restore_backup
msg_info "Starting Service"
systemctl start ddns-updater
+3 -7
View File
@@ -35,10 +35,8 @@ function update_script() {
systemctl stop degoog
msg_ok "Stopped Service"
msg_info "Backing up Configuration & Data"
[[ -f /opt/degoog/.env ]] && cp /opt/degoog/.env /opt/degoog.env.bak
[[ -d /opt/degoog/data ]] && mv /opt/degoog/data /opt/degoog_data_backup
msg_ok "Backed up Configuration & Data"
create_backup /opt/degoog/.env \
/opt/degoog/data
if ! command -v bun >/dev/null 2>&1; then
msg_info "Installing Bun"
@@ -55,9 +53,7 @@ function update_script() {
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "degoog" "fccview/degoog" "prebuild" "latest" "/opt/degoog" "degoog_*_prebuild.tar.gz"
msg_info "Restoring Configuration & Data"
[[ -f /opt/degoog.env.bak ]] && mv /opt/degoog.env.bak /opt/degoog/.env
[[ -d /opt/degoog_data_backup ]] && mv /opt/degoog_data_backup /opt/degoog/data
restore_backup
if [[ -f /opt/degoog/.env ]]; then
grep -q "^DEGOOG_VALKEY_URL=" /opt/degoog/.env && sed -i "s|^DEGOOG_VALKEY_URL=.*|DEGOOG_VALKEY_URL=redis://valkey:6379|" /opt/degoog/.env || echo "DEGOOG_VALKEY_URL=redis://valkey:6379" >>/opt/degoog/.env
+2 -9
View File
@@ -37,19 +37,12 @@ function update_script() {
systemctl stop discopanel
msg_ok "Stopped Service"
msg_info "Creating Backup"
mkdir -p /opt/discopanel_backup_temp
cp /opt/discopanel/data/discopanel.db /opt/discopanel_backup_temp/discopanel.db
msg_ok "Created Backup"
create_backup /opt/discopanel/data/discopanel.db
fetch_and_deploy_gh_release "discopanel" "nickheyer/discopanel" "prebuild" "latest" "/opt/discopanel" "discopanel-linux-amd64.tar.gz"
ln -sf /opt/discopanel/discopanel-linux-amd64 /opt/discopanel/discopanel
msg_info "Restoring Data"
mkdir -p /opt/discopanel/data
mv /opt/discopanel_backup_temp/discopanel.db /opt/discopanel/data/discopanel.db
rm -rf /opt/discopanel_backup_temp
msg_ok "Restored Data"
restore_backup
msg_info "Starting Service"
systemctl start discopanel
+5 -11
View File
@@ -37,25 +37,19 @@ function update_script() {
systemctl stop docmost
msg_ok "Stopped Service"
msg_info "Backing up data"
cp /opt/docmost/.env /opt/
cp -r /opt/docmost/data /opt/
rm -rf /opt/docmost
msg_ok "Data backed up"
create_backup /opt/docmost/.env \
/opt/docmost/data
fetch_and_deploy_gh_release "docmost" "docmost/docmost" "tarball"
msg_info "Updating ${APP}"
cd /opt/docmost
mv /opt/.env /opt/docmost/.env
mv /opt/data /opt/docmost/data
restore_backup
# Fix: Docmost EE (audit logs etc.) lives in a git submodule that is NOT
# included in GitHub tarballs. The community NoopAuditService exists but
# is only exported by CoreModule child modules such as UserModule cannot
# resolve it. Making CoreModule @Global() exposes the token app-wide.
if [[ ! -f /opt/docmost/apps/server/src/ee/ee.module.ts ]] \
&& ! grep -q '@Global()' /opt/docmost/apps/server/src/core/core.module.ts 2>/dev/null; then
if [[ ! -f /opt/docmost/apps/server/src/ee/ee.module.ts ]] &&
! grep -q '@Global()' /opt/docmost/apps/server/src/core/core.module.ts 2>/dev/null; then
sed -i '/^ Module,$/a\ Global,' /opt/docmost/apps/server/src/core/core.module.ts
sed -i '/^@Module({$/i @Global()' /opt/docmost/apps/server/src/core/core.module.ts
fi
+4 -9
View File
@@ -35,24 +35,19 @@ function update_script() {
systemctl stop docuseal docuseal-sidekiq
msg_ok "Stopped Services"
msg_info "Backing up Data"
cp /opt/docuseal/.env /opt/docuseal.env.bak
[[ -d /opt/docuseal/data ]] && mv /opt/docuseal/data /opt/docuseal_data.bak
msg_ok "Backed up Data"
create_backup /opt/docuseal/.env \
/opt/docuseal/data
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "docuseal" "docusealco/docuseal" "tarball"
local required_ruby current_ruby
required_ruby=$(grep -m1 '^ruby ' /opt/docuseal/Gemfile | grep -oP '[0-9]+\.[0-9]+\.[0-9]+')
current_ruby=$(PATH="/root/.rbenv/bin:/root/.rbenv/shims:${PATH}" rbenv global 2>/dev/null || true)
if [[ -n "$required_ruby" && "$required_ruby" != "$current_ruby" ]]; then
if [[ -n $required_ruby && $required_ruby != "$current_ruby" ]]; then
RUBY_VERSION="${required_ruby}" RUBY_INSTALL_RAILS="false" HOME=/root setup_ruby
fi
msg_info "Restoring Data"
mv /opt/docuseal.env.bak /opt/docuseal/.env
[[ -d /opt/docuseal_data.bak ]] && mv /opt/docuseal_data.bak /opt/docuseal/data
msg_ok "Restored Data"
restore_backup
msg_info "Building Application"
cd /opt/docuseal
+2 -6
View File
@@ -43,9 +43,7 @@ function update_script() {
systemctl stop apache2
msg_info "Service stopped"
msg_info "Creating backup"
mv /opt/domain-monitor/.env /opt
msg_ok "Created backup"
create_backup /opt/domain-monitor/.env
setup_composer
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "domain-monitor" "Hosteroid/domain-monitor" "prebuild" "latest" "/opt/domain-monitor" "domain-monitor-v*.zip"
@@ -56,9 +54,7 @@ function update_script() {
chown -R www-data:www-data /opt/domain-monitor
msg_ok "Updated Domain Monitor"
msg_info "Restoring backup"
mv /opt/.env /opt/domain-monitor
msg_ok "Restored backup"
restore_backup
msg_info "Restarting Services"
systemctl start apache2
+3 -7
View File
@@ -35,18 +35,14 @@ function update_script() {
systemctl stop donetick
msg_ok "Stopped Service"
msg_info "Backing Up Configurations"
mv /opt/donetick/config/selfhosted.yaml /opt/donetick/donetick.db /opt
msg_ok "Backed Up Configurations"
create_backup /opt/donetick/config/selfhosted.yaml \
/opt/donetick/donetick.db
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "donetick" "donetick/donetick" "prebuild" "latest" "/opt/donetick" "donetick_Linux_x86_64.tar.gz"
msg_info "Restoring Configurations"
mv /opt/selfhosted.yaml /opt/donetick/config
restore_backup
grep -q 'http://localhost"$' /opt/donetick/config/selfhosted.yaml || sed -i '/https:\/\/localhost"$/a\ - "http://localhost"' /opt/donetick/config/selfhosted.yaml
grep -q 'capacitor://localhost' /opt/donetick/config/selfhosted.yaml || sed -i '/http:\/\/localhost"$/a\ - "capacitor://localhost"' /opt/donetick/config/selfhosted.yaml
mv /opt/donetick.db /opt/donetick
msg_ok "Restored Configurations"
msg_info "Starting Service"
systemctl start donetick
+4 -10
View File
@@ -35,19 +35,13 @@ function update_script() {
systemctl stop dynacat
msg_ok "Stopped Service"
msg_info "Backing up Data"
cp -r /opt/dynacat/config /opt/dynacat_config_backup
cp -r /opt/dynacat/assets /opt/dynacat_assets_backup
cp -r /opt/dynacat/data /opt/dynacat_data_backup
msg_ok "Backed up Data"
create_backup /opt/dynacat/config \
/opt/dynacat/assets \
/opt/dynacat/data
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "dynacat" "Panonim/dynacat" "prebuild" "latest" "/opt/dynacat" "dynacat-linux-amd64.tar.gz"
msg_info "Restoring Data"
cp -r /opt/dynacat_config_backup/. /opt/dynacat/config
cp -r /opt/dynacat_assets_backup/. /opt/dynacat/assets
cp -r /opt/dynacat_data_backup/. /opt/dynacat/data
rm -rf /opt/dynacat_config_backup /opt/dynacat_assets_backup /opt/dynacat_data_backup
restore_backup
chmod +x /opt/dynacat/dynacat
msg_ok "Restored Data"
+5
View File
@@ -37,6 +37,11 @@ function update_script() {
"2" "Set Admin Token")
if [ "$UPD" == "1" ]; then
INSTALLED_VERSION="$(/opt/vaultwarden/bin/vaultwarden --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)"
if [[ -n "$INSTALLED_VERSION" ]] &&
! grep -qxF "$INSTALLED_VERSION" "$HOME/.vaultwarden" 2>/dev/null; then
printf '%s\n' "$INSTALLED_VERSION" >"$HOME/.vaultwarden"
fi
if check_for_gh_release "vaultwarden" "dani-garcia/vaultwarden"; then
msg_info "Stopping Service"
systemctl stop vaultwarden
+2
View File
@@ -133,6 +133,8 @@ server {
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_param HTTP_X_FORWARDED_HOST $http_host;
fastcgi_param HTTP_X_FORWARDED_PROTO $scheme;
fastcgi_read_timeout 300;
}
+33 -4
View File
@@ -979,6 +979,20 @@ base_settings() {
IPV6_METHOD=${var_ipv6_method:-"none"}
GATE=${var_gateway:-""}
# Guard against invalid gateway combinations from defaults/app vars:
# - DHCP must not force a static gateway
# - Static IPv4 must use a gateway in the same subnet
if [[ "$NET" == "dhcp" && -n "$GATE" ]]; then
msg_warn "Ignoring var_gateway '$GATE' because var_net is 'dhcp'"
GATE=""
elif [[ "$NET" != "dhcp" && -n "$GATE" ]]; then
if ! validate_gateway_in_subnet "$NET" "$GATE"; then
msg_warn "Ignoring var_gateway '$GATE' because it is not in subnet of var_net '$NET'"
GATE=""
fi
fi
APT_CACHER=${var_apt_cacher:-""}
APT_CACHER_IP=${var_apt_cacher_ip:-""}
@@ -4379,10 +4393,12 @@ EOF
pct exec "$CTID" -- bash -c "apt-get update 2>&1 && apt-get install -y ${_base_pkgs} 2>&1" >>"$BUILD_LOG" 2>&1 || {
local failed_mirror
failed_mirror=$(pct exec "$CTID" -- bash -c "grep -m1 -oP '(?<=URIs: https?://)[^/]+' /etc/apt/sources.list.d/debian.sources 2>/dev/null || grep -m1 -oP '(?<=deb https?://)[^/]+' /etc/apt/sources.list 2>/dev/null" 2>/dev/null || echo "unknown")
msg_warn "apt-get update failed (${failed_mirror}), trying alternate mirrors..."
msg_warn "apt-get update failed (${failed_mirror})."
msg_custom "️" "${YW}" "Probing alternate mirrors (this can take 1-2 minutes on network issues)"
local mirror_exit=0
pct exec "$CTID" -- env APT_BASE="$_base_pkgs" bash -c '
DISTRO=$(. /etc/os-release 2>/dev/null && echo "$ID" || echo "debian")
echo " Mirror fallback for distro: $DISTRO"
if [ "$DISTRO" = "ubuntu" ]; then
EU_MIRRORS="de.archive.ubuntu.com fr.archive.ubuntu.com se.archive.ubuntu.com nl.archive.ubuntu.com it.archive.ubuntu.com ch.archive.ubuntu.com mirrors.xtom.de"
@@ -4440,15 +4456,21 @@ EOF
}
# Phase 1: Scan global mirrors first (independent of local CDN issues)
echo " Phase 1/3: Scanning global mirrors for reachability..."
OTHERS_OK=$(scan_reachable "$OTHERS")
OTHERS_PICK=$(printf "%s\n" $OTHERS_OK | shuf | head -3 | xargs)
if [ -z "$OTHERS_PICK" ]; then
echo " No reachable global mirrors found"
fi
for mirror in $OTHERS_PICK; do
echo " Attempting mirror: $mirror"
try_mirrors "$mirror" && exit 0
done
# Phase 2: Try primary mirror
echo " Phase 2/3: Trying primary mirror..."
if [ "$DISTRO" = "ubuntu" ]; then
PRIMARY="archive.ubuntu.com"
else
@@ -4460,9 +4482,14 @@ EOF
fi
# Phase 3: Fall back to regional mirrors
echo " Phase 3/3: Scanning regional mirrors..."
REGIONAL_OK=$(scan_reachable "$REGIONAL")
REGIONAL_PICK=$(printf "%s\n" $REGIONAL_OK | shuf | head -3 | xargs)
if [ -z "$REGIONAL_PICK" ]; then
echo " No reachable regional mirrors found"
fi
for mirror in $REGIONAL_PICK; do
echo " Attempting mirror: $mirror"
try_mirrors "$mirror" && exit 0
@@ -4496,12 +4523,14 @@ EOF
msg_warn "Mirror '${custom_mirror}' also failed. Try another or type 'skip'."
done
if [[ "$custom_mirror" == "skip" ]]; then
msg_error "apt-get base packages installation failed"
install_exit_code=1
msg_warn "Mirror selection aborted by user ('skip')"
msg_warn "Aborting installation before base package bootstrap"
post_update_to_api "aborted" "130" "force"
install_exit_code=130
fi
elif [[ $mirror_exit -ne 0 ]]; then
msg_error "apt-get base packages installation failed"
install_exit_code=1
install_exit_code=100
fi
}
fi
+8
View File
@@ -5267,6 +5267,8 @@ _setup_intel_arc() {
intel-media-va-driver-non-free \
intel-opencl-icd \
libmfx-gen1.2 \
mesa-vulkan-drivers \
vulkan-tools \
vainfo \
intel-gpu-tools 2>/dev/null || msg_warn "Some Intel Arc packages failed"
@@ -5301,6 +5303,8 @@ _setup_intel_arc() {
ocl-icd-libopencl1 \
libvpl2 \
libmfx-gen1.2 \
mesa-vulkan-drivers \
vulkan-tools \
vainfo \
intel-gpu-tools 2>/dev/null || msg_warn "Some Intel Arc packages failed"
@@ -5324,6 +5328,8 @@ _setup_intel_modern() {
va-driver-all \
intel-media-va-driver \
ocl-icd-libopencl1 \
mesa-vulkan-drivers \
vulkan-tools \
vainfo \
intel-gpu-tools 2>/dev/null || msg_warn "Some Intel packages failed"
@@ -5358,6 +5364,8 @@ _setup_intel_modern() {
$STD apt -y install \
intel-media-va-driver-non-free \
ocl-icd-libopencl1 \
mesa-vulkan-drivers \
vulkan-tools \
vainfo \
libmfx-gen1.2 \
intel-gpu-tools 2>/dev/null || msg_warn "Some Intel packages failed"
+549 -45
View File
@@ -1,5 +1,5 @@
# Copyright (c) 2021-2026 community-scripts ORG
# License: MIT | https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/LICENSE
# License: MIT | https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/LICENSE
set -euo pipefail
SPINNER_PID=""
@@ -14,9 +14,18 @@ declare -A MSG_INFO_SHOWN
[[ -n "${_CORE_FUNC_LOADED:-}" ]] && return
_CORE_FUNC_LOADED=1
COMMUNITY_SCRIPTS_URL="${COMMUNITY_SCRIPTS_URL:-https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main}"
load_api_functions() {
if ! declare -f post_to_api_vm >/dev/null 2>&1; then
source /dev/stdin <<<$(curl -fsSL "$COMMUNITY_SCRIPTS_URL/misc/api.func")
fi
}
load_functions() {
[[ -n "${__FUNCTIONS_LOADED:-}" ]] && return
__FUNCTIONS_LOADED=1
load_api_functions
color
formatting
icons
@@ -31,18 +40,24 @@ load_functions() {
arch_check
}
load_cloud_init_functions() {
if ! declare -f setup_cloud_init >/dev/null 2>&1; then
source <(curl -fsSL "$COMMUNITY_SCRIPTS_URL/misc/cloud-init.func") 2>/dev/null || true
fi
}
# Function to download & save header files
get_header() {
local app_name=$(echo "${APP,,}" | tr ' ' '-')
local app_type=${APP_TYPE:-vm}
local header_url="https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/${app_type}/headers/${app_name}"
local header_url="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/${app_type}/headers/${app_name}"
local local_header_path="/usr/local/community-scripts/headers/${app_type}/${app_name}"
mkdir -p "$(dirname "$local_header_path")"
if [ ! -s "$local_header_path" ]; then
if ! curl -fsSL "$header_url" -o "$local_header_path"; then
return 250
return 1
fi
fi
@@ -98,6 +113,7 @@ icons() {
DNSOK="✔️ "
DNSFAIL="${TAB}✖️${TAB}"
INFO="${TAB}💡${TAB}${CL}"
CLOUD="${TAB}☁️${TAB}${CL}"
OS="${TAB}🖥️${TAB}${CL}"
OSVERSION="${TAB}🌟${TAB}${CL}"
CONTAINERTYPE="${TAB}📦${TAB}${CL}"
@@ -188,18 +204,32 @@ silent() {
trap 'error_handler' ERR
if [[ $rc -ne 0 ]]; then
# Return instead of exit so that callers can use `$STD cmd || true`
# When no || is used, set -e + ERR trap catches it via error_handler()
export _SILENT_FAILED_RC="$rc"
export _SILENT_FAILED_CMD="$cmd"
export _SILENT_FAILED_LINE="$caller_line"
export _SILENT_FAILED_LOG="$logfile"
# Source explain_exit_code if needed
if ! declare -f explain_exit_code >/dev/null 2>&1; then
source <(curl -fsSL "$COMMUNITY_SCRIPTS_URL/misc/error_handler.func") 2>/dev/null || true
fi
return "$rc"
local explanation=""
if declare -f explain_exit_code >/dev/null 2>&1; then
explanation="$(explain_exit_code "$rc")"
fi
printf "\e[?25h"
if [[ -n "$explanation" ]]; then
msg_error "in line ${caller_line}: exit code ${rc} (${explanation})"
else
msg_error "in line ${caller_line}: exit code ${rc}"
fi
msg_custom "→" "${YWB}" "${cmd}"
if [[ -s "$logfile" ]]; then
echo -e "\n${TAB}--- Last 20 lines of log ---"
tail -n 20 "$logfile"
echo -e "${TAB}----------------------------\n"
fi
exit "$rc"
fi
# Clear stale flags on success
unset _SILENT_FAILED_RC _SILENT_FAILED_CMD _SILENT_FAILED_LINE _SILENT_FAILED_LOG 2>/dev/null || true
}
# ------------------------------------------------------------------------------
@@ -230,7 +260,7 @@ curl_handler() {
if [[ -z "$url" ]]; then
msg_error "no valid url or option entered for curl_handler"
exit 64
exit 1
fi
$STD msg_info "Fetching: $url"
@@ -259,7 +289,7 @@ curl_handler() {
rm -f /tmp/curl_error.log
fi
__curl_err_handler "$exit_code" "$url" "$curl_stderr"
exit "$exit_code"
exit 1 # hard exit if exit_code is not 0
fi
$STD printf "\r\033[K${INFO}${YW}Retry $attempt/$max_retries in ${delay}s...${CL}" >&2
@@ -302,7 +332,7 @@ __curl_err_handler() {
esac
[[ -n "$curl_msg" ]] && printf "%s\n" "$curl_msg" >&2
exit "$exit_code"
exit 1
}
# ------------------------------------------------------------------------------
@@ -317,7 +347,7 @@ shell_check() {
msg_error "Your default shell is currently not set to Bash. To use these scripts, please switch to the Bash shell."
echo -e "\nExiting..."
sleep 2
exit 103
exit
fi
}
@@ -338,11 +368,11 @@ clear_line() {
#
# - Determines if script should run in verbose mode
# - Checks VERBOSE and var_verbose variables
# - Note: Non-TTY (pipe) scenarios are handled separately in msg_info()
# - Also returns true if not running in TTY (pipe/redirect scenario)
# ------------------------------------------------------------------------------
is_verbose_mode() {
local verbose="${VERBOSE:-${var_verbose:-no}}"
[[ "$verbose" != "no" ]]
[[ "$verbose" != "no" || ! -t 2 ]]
}
### dev spinner ###
@@ -481,6 +511,20 @@ msg_debug() {
fi
}
error_handler() {
local exit_code="$?"
local line_number="${1:-unknown}"
local command="${2:-unknown}"
if declare -f post_update_to_api >/dev/null 2>&1; then
post_update_to_api "failed" "$exit_code"
fi
local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}"
echo -e "\n$error_message\n"
cleanup_vmid
}
# Displays error message and immediately terminates script
fatal() {
msg_error "$1"
@@ -516,9 +560,13 @@ cleanup_vmid() {
cleanup() {
local exit_code=$?
stop_spinner
if [[ "$(dirs -p | wc -l)" -gt 1 ]]; then
popd >/dev/null || true
fi
if [[ -n "${TEMP_DIR:-}" && -d "$TEMP_DIR" ]]; then
rm -rf "$TEMP_DIR"
fi
# Report final telemetry status if post_to_api_vm was called but no update was sent
if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then
if declare -f post_update_to_api >/dev/null 2>&1; then
@@ -538,18 +586,37 @@ check_root() {
msg_error "Please run this script as root."
echo -e "\nExiting..."
sleep 2
exit 104
exit
fi
}
pve_check() {
if ! pveversion | grep -Eq "pve-manager/(8\.[1-4]|9\.[0-2])(\.[0-9]+)*"; then
msg_error "This version of Proxmox Virtual Environment is not supported"
echo -e "Requires Proxmox Virtual Environment Version 8.1 - 8.4 or 9.0 - 9.2."
echo -e "Exiting..."
sleep 2
exit 105
local pve_ver
pve_ver="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')"
if [[ "$pve_ver" =~ ^8\.([0-9]+) ]]; then
local minor="${BASH_REMATCH[1]}"
if ((minor < 0 || minor > 9)); then
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported: Proxmox VE version 8.0 8.9"
exit 105
fi
return 0
fi
if [[ "$pve_ver" =~ ^9\.([0-9]+) ]]; then
local minor="${BASH_REMATCH[1]}"
if ((minor < 0 || minor > 2)); then
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported: Proxmox VE version 9.0 9.2"
exit 105
fi
return 0
fi
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported versions: Proxmox VE 8.0 8.9 or 9.0 9.2"
exit 105
}
arch_check() {
@@ -558,50 +625,487 @@ arch_check() {
echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n"
echo -e "Exiting..."
sleep 2
exit 106
exit
fi
}
ssh_check() {
if command -v pveversion >/dev/null 2>&1 && [ -n "${SSH_CLIENT:-}" ]; then
if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH DETECTED" --yesno "It's suggested to use the Proxmox shell instead of SSH, since SSH can create issues while gathering variables. Would you like to proceed with using SSH?" 10 62; then
:
else
clear
exit
fi
fi
}
exit_script() {
clear
echo -e "\n${CROSS}${RD}User exited script${CL}\n"
exit 0
exit
}
sanitize_vm_hostname() {
local hostname="${1,,}"
hostname=$(echo "$hostname" | tr -cs 'a-z0-9-' '-' | sed 's/^-//;s/-$//')
echo "${hostname:0:63}"
}
vm_confirm_new_vm() {
local title="$1"
local message="$2"
local height="${3:-10}"
local width="${4:-58}"
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" --yesno "$message" "$height" "$width"
}
vm_choose_settings_mode() {
local message="${1:-Use Default Settings?}"
local height="${2:-10}"
local width="${3:-58}"
whiptail --backtitle "Proxmox VE Helper Scripts" --title "SETTINGS" --yesno "$message" --no-button Advanced "$height" "$width"
}
vm_confirm_advanced_settings() {
local message="$1"
local height="${2:-10}"
local width="${3:-58}"
whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS COMPLETE" --yesno "$message" --no-button Do-Over "$height" "$width"
}
vm_prompt_vmid() {
local default_vmid="${1:-$(get_valid_nextid)}"
while true; do
if VMID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Virtual Machine ID" 8 58 "$default_vmid" --title "VIRTUAL MACHINE ID" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$VMID" ]; then
VMID=$(get_valid_nextid)
fi
if pct status "$VMID" &>/dev/null || qm status "$VMID" &>/dev/null; then
echo -e "${CROSS}${RD} ID $VMID is already in use${CL}"
sleep 2
continue
fi
echo -e "${CONTAINERID}${BOLD}${DGN}Virtual Machine ID: ${BGN}$VMID${CL}"
break
else
exit_script
fi
done
}
vm_apply_machine_type() {
local machine_type="${1:-i440fx}"
if [ "$machine_type" = "q35" ]; then
MACHINE_TYPE="q35"
FORMAT=""
MACHINE=" -machine q35"
else
MACHINE_TYPE="i440fx"
FORMAT=",efitype=4m"
MACHINE=""
fi
}
vm_machine_type_label() {
case "${1:-i440fx}" in
q35)
echo "Q35 (Modern)"
;;
*)
echo "i440fx"
;;
esac
}
vm_prompt_machine_type() {
local default_machine="${1:-i440fx}"
local i440fx_default="ON"
local q35_default="OFF"
local machine_choice
if [ "$default_machine" = "q35" ]; then
i440fx_default="OFF"
q35_default="ON"
fi
if machine_choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "MACHINE TYPE" --radiolist --cancel-button Exit-Script "Choose Type" 10 58 2 \
"i440fx" "Machine i440fx" "$i440fx_default" \
"q35" "Machine q35" "$q35_default" \
3>&1 1>&2 2>&3); then
vm_apply_machine_type "$machine_choice"
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}$(vm_machine_type_label "$MACHINE_TYPE")${CL}"
else
exit_script
fi
}
vm_prompt_cloud_init() {
local default_user="${1:-root}"
USE_CLOUD_INIT="no"
load_cloud_init_functions
if ! declare -f configure_cloud_init_interactive >/dev/null 2>&1; then
echo -e "${CLOUD}${BOLD}${DGN}Cloud-Init: ${BGN}unavailable${CL}"
return 1
fi
configure_cloud_init_interactive "$default_user" || true
USE_CLOUD_INIT="${CLOUDINIT_ENABLE:-no}"
echo -e "${CLOUD}${BOLD}${DGN}Cloud-Init: ${BGN}${USE_CLOUD_INIT}${CL}"
if [ "$USE_CLOUD_INIT" = "yes" ] && declare -f configure_cloudinit_ssh_keys >/dev/null 2>&1; then
configure_cloudinit_ssh_keys || true
fi
return 0
}
vm_prompt_disk_size() {
local default_size="${1:-8G}"
local prompt_message="${2:-Set Disk Size in GiB (e.g., 10, 20)}"
if DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "$prompt_message" 8 58 "$default_size" --title "DISK SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
DISK_SIZE=$(echo "$DISK_SIZE" | tr -d ' ')
if [[ "$DISK_SIZE" =~ ^[0-9]+$ ]]; then
DISK_SIZE="${DISK_SIZE}G"
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}$DISK_SIZE${CL}"
elif [[ "$DISK_SIZE" =~ ^[0-9]+G$ ]]; then
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}$DISK_SIZE${CL}"
else
echo -e "${DISKSIZE}${BOLD}${RD}Invalid Disk Size. Please use a number (e.g., 10 or 10G).${CL}"
exit_script
fi
else
exit_script
fi
}
vm_prompt_disk_cache() {
local default_cache="${1:-none}"
local none_default="ON"
local write_default="OFF"
local cache_choice
if [ "$default_cache" = "writethrough" ]; then
none_default="OFF"
write_default="ON"
fi
if cache_choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "DISK CACHE" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
"0" "None (Default)" "$none_default" \
"1" "Write Through" "$write_default" \
3>&1 1>&2 2>&3); then
if [ "$cache_choice" = "1" ]; then
DISK_CACHE="cache=writethrough,"
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}Write Through${CL}"
else
DISK_CACHE=""
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}None${CL}"
fi
else
exit_script
fi
}
vm_prompt_hostname() {
local default_hostname="${1:-vm}"
local adjusted_hostname
local input_hostname
if input_hostname=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 "$default_hostname" --title "HOSTNAME" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$input_hostname" ]; then
HN="$default_hostname"
else
adjusted_hostname=$(sanitize_vm_hostname "$input_hostname")
HN="${adjusted_hostname:-$default_hostname}"
if [ "$HN" != "${input_hostname,,}" ]; then
whiptail --backtitle "Proxmox VE Helper Scripts" --title "HOSTNAME ADJUSTED" --msgbox "Invalid characters detected. Hostname has been adjusted to:\n\n $HN" 10 58
fi
fi
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
else
exit_script
fi
}
vm_prompt_cpu_model() {
local default_model="${1:-kvm64}"
local kvm_default="ON"
local host_default="OFF"
local cpu_choice
if [ "$default_model" = "host" ]; then
kvm_default="OFF"
host_default="ON"
fi
if cpu_choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU MODEL" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
"0" "KVM64 (Default)" "$kvm_default" \
"1" "Host" "$host_default" \
3>&1 1>&2 2>&3); then
if [ "$cpu_choice" = "1" ]; then
CPU_TYPE=" -cpu host"
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}Host${CL}"
else
CPU_TYPE=""
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}KVM64${CL}"
fi
else
exit_script
fi
}
vm_prompt_cpu_cores() {
local default_cores="${1:-2}"
while true; do
if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 "$default_cores" --title "CORE COUNT" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$CORE_COUNT" ]; then
CORE_COUNT="$default_cores"
fi
if [[ "$CORE_COUNT" =~ ^[1-9][0-9]*$ ]]; then
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "CPU Cores must be a positive integer (e.g., 2)." 8 58
else
exit_script
fi
done
}
vm_prompt_ram() {
local default_ram="${1:-2048}"
while true; do
if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 "$default_ram" --title "RAM" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$RAM_SIZE" ]; then
RAM_SIZE="$default_ram"
fi
if [[ "$RAM_SIZE" =~ ^[1-9][0-9]*$ ]]; then
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}$RAM_SIZE${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "RAM Size must be a positive integer in MiB (e.g., 2048)." 8 58
else
exit_script
fi
done
}
vm_prompt_bridge() {
local default_bridge="${1:-vmbr0}"
if BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Bridge" 8 58 "$default_bridge" --title "BRIDGE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$BRG" ]; then
BRG="$default_bridge"
fi
echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}"
else
exit_script
fi
}
vm_prompt_mac() {
local default_mac="${1:-$GEN_MAC}"
local input_mac
while true; do
if input_mac=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a MAC Address" 8 58 "$default_mac" --title "MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$input_mac" ]; then
MAC="$default_mac"
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC${CL}"
break
fi
if [[ "$input_mac" =~ ^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$ ]]; then
MAC="$input_mac"
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "Invalid MAC address format. Use XX:XX:XX:XX:XX:XX (e.g., AA:BB:CC:DD:EE:FF)." 8 58
else
exit_script
fi
done
}
vm_prompt_vlan() {
local default_vlan="${1:-}"
local input_vlan
while true; do
if input_vlan=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Vlan (leave blank for default)" 8 58 "$default_vlan" --title "VLAN" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$input_vlan" ]; then
VLAN=""
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}Default${CL}"
break
fi
if [[ "$input_vlan" =~ ^[0-9]+$ ]] && [ "$input_vlan" -ge 1 ] && [ "$input_vlan" -le 4094 ]; then
VLAN=",tag=$input_vlan"
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}$input_vlan${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "VLAN must be a number between 1 and 4094, or leave blank for default." 8 58
else
exit_script
fi
done
}
vm_prompt_mtu() {
local default_mtu="${1:-}"
local input_mtu
while true; do
if input_mtu=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Interface MTU Size (leave blank for default)" 8 58 "$default_mtu" --title "MTU SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
if [ -z "$input_mtu" ]; then
MTU=""
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}Default${CL}"
break
fi
if [[ "$input_mtu" =~ ^[0-9]+$ ]] && [ "$input_mtu" -ge 576 ] && [ "$input_mtu" -le 65520 ]; then
MTU=",mtu=$input_mtu"
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$input_mtu${CL}"
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "MTU Size must be a number between 576 and 65520, or leave blank for default." 8 58
else
exit_script
fi
done
}
vm_prompt_start_vm() {
local default_start="${1:-yes}"
local default_flag=()
if [ "$default_start" = "no" ]; then
default_flag=(--defaultno)
fi
if whiptail --backtitle "Proxmox VE Helper Scripts" "${default_flag[@]}" --title "START VIRTUAL MACHINE" --yesno "Start VM when completed?" 10 58; then
START_VM="yes"
else
START_VM="no"
fi
echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}${START_VM}${CL}"
}
vm_apply_storage_layout() {
local storage_type="$1"
case $storage_type in
nfs | dir | cifs)
DISK_EXT=".qcow2"
DISK_REF="$VMID/"
DISK_IMPORT_FORMAT="qcow2"
THIN=""
;;
btrfs)
DISK_EXT=".raw"
DISK_REF="$VMID/"
DISK_IMPORT_FORMAT="raw"
FORMAT=",efitype=4m"
THIN=""
;;
*)
DISK_EXT=""
DISK_REF=""
DISK_IMPORT_FORMAT="raw"
;;
esac
}
vm_select_storage() {
local hostname="${1:-${HN:-vm}}"
local storage_menu=()
local msg_max_length=0
local line tag type free item
local offset=2
local valid_storage
msg_info "Validating Storage"
while read -r line; do
tag=$(echo "$line" | awk '{print $1}')
type=$(echo "$line" | awk '{printf "%-10s", $2}')
free=$(echo "$line" | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}')
item=" Type: $type Free: $free "
if [[ $((${#item} + offset)) -gt $msg_max_length ]]; then
msg_max_length=$((${#item} + offset))
fi
storage_menu+=("$tag" "$item" "OFF")
done < <(pvesm status -content images | awk 'NR>1')
valid_storage=$(pvesm status -content images | awk 'NR>1')
if [ -z "$valid_storage" ]; then
msg_error "Unable to detect a valid storage location."
exit
elif [ $((${#storage_menu[@]} / 3)) -eq 1 ]; then
STORAGE=${storage_menu[0]}
else
if [ -n "${SPINNER_PID:-}" ] && ps -p "$SPINNER_PID" >/dev/null 2>&1; then
kill "$SPINNER_PID" >/dev/null 2>&1 || true
SPINNER_ACTIVE=0
printf "\r\e[2K" >&2
fi
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool would you like to use for ${hostname}?\nTo make a selection, use the Spacebar.\n" \
16 $(($msg_max_length + 23)) 6 \
"${storage_menu[@]}" 3>&1 1>&2 2>&3)
done
fi
msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location."
msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}."
STORAGE_TYPE=$(pvesm status -storage "$STORAGE" | awk 'NR>1 {print $2}')
vm_apply_storage_layout "$STORAGE_TYPE"
}
vm_define_disk_references() {
local disk_count="${1:-2}"
local i disk_name
for ((i = 0; i < disk_count; i++)); do
disk_name="vm-${VMID}-disk-${i}${DISK_EXT:-}"
printf -v "DISK${i}" '%s' "$disk_name"
printf -v "DISK${i}_REF" '%s' "${STORAGE}:${DISK_REF:-}${disk_name}"
done
}
check_hostname_conflict() {
local hostname="$1"
if qm list | awk '{print $2}' | grep -qx "$hostname"; then
msg_error "Hostname $hostname already in use by another VM."
exit 206
exit 1
fi
}
set_description() {
local app_name script_slug script_url donate_url
app_name=$(echo "${APP,,}" | tr ' ' '-')
script_slug="${SCRIPT_SLUG:-${app_name}}"
script_slug="$(echo "$script_slug" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')"
script_url="https://community-scripts.org/scripts/${script_slug}"
donate_url="https://community-scripts.org/donate"
local description_title="${APP:-${NSAPP} VM}"
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>
<h2 style='font-size: 24px; margin: 20px 0;'>${NSAPP} VM</h2>
<h2 style='font-size: 24px; margin: 20px 0;'>${description_title}</h2>
<p style='margin: 16px 0;'>
<a href='${donate_url}' target='_blank' rel='noopener noreferrer'>
<img src='https://img.shields.io/badge/❤️-Sponsoring%20%26%20Donations-FF5E5B' alt='Sponsoring and donations' />
</a>
</p>
<p style='margin: 12px 0;'>
<a href='${script_url}' target='_blank' rel='noopener noreferrer'>
<img src='https://img.shields.io/badge/📦-Open%20Script%20Page-00617f' alt='Open script page' />
<a href='https://ko-fi.com/community_scripts' target='_blank' rel='noopener noreferrer'>
<img src='https://img.shields.io/badge/&#x2615;-Buy us a coffee-blue' alt='spend Coffee' />
</a>
</p>