Compare commits

..

4 Commits

Author SHA1 Message Date
community-scripts-pr-app[bot]
5d2fea107d Update CHANGELOG.md (#13250)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-24 08:58:07 +00:00
CanbiZ (MickLesk)
86c658909a Classify exit-1 errors & guard telemetry
Analyze logs for generic exit code 1 and export an ERROR_CATEGORY_OVERRIDE so telemetry receives a more accurate error category (apt, oom, network, storage, dependency). Preserve any existing TELEMETRY_TYPE when posting updates. Add defense-in-depth by disabling strict error traps before running grep/sed log analysis to avoid spurious error_handler invocations. Mark successful installs with INSTALL_COMPLETE and update the error handler to only report a successful "done" telemetry state when INSTALL_COMPLETE is explicitly set, preventing false-positive success reports from early zero-exit exits.
2026-03-24 09:57:43 +01:00
community-scripts-pr-app[bot]
9aa0390553 Update CHANGELOG.md (#13245)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-23 21:22:47 +00:00
CanbiZ (MickLesk)
c8606e9fcc core: harden shell scripts against injection and insecure permissions (#13239) 2026-03-23 22:22:23 +01:00
41 changed files with 174 additions and 104 deletions

View File

@@ -21,7 +21,7 @@ jobs:
const message = `Hello, it looks like you are referencing the **old tteck repo**. const message = `Hello, it looks like you are referencing the **old tteck repo**.
This repository is no longer used for active scripts. This repository is no longer used for active scripts.
**Please update your bookmarks** and use: [https://community-scripts.com](https://community-scripts.com) **Please update your bookmarks** and use: [https://helper-scripts.com](https://helper-scripts.com)
Also make sure your Bash command starts with: Also make sure your Bash command starts with:
\`\`\`bash \`\`\`bash

View File

@@ -426,8 +426,16 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details> </details>
## 2026-03-24
## 2026-03-23 ## 2026-03-23
### 🚀 Updated Scripts
- #### 🔧 Refactor
- core: harden shell scripts against injection and insecure permissions [@MickLesk](https://github.com/MickLesk) ([#13239](https://github.com/community-scripts/ProxmoxVE/pull/13239))
## 2026-03-22 ## 2026-03-22
### 🆕 New Scripts ### 🆕 New Scripts

View File

@@ -5,7 +5,7 @@
<p><em>A Community Legacy in Memory of @tteck</em></p> <p><em>A Community Legacy in Memory of @tteck</em></p>
<p> <p>
<a href="https://community-scripts.com"> <a href="https://helper-scripts.com">
<img src="https://img.shields.io/badge/🌐_Website-Visit-4c9b3f?style=for-the-badge&labelColor=2d3748" alt="Website" /> <img src="https://img.shields.io/badge/🌐_Website-Visit-4c9b3f?style=for-the-badge&labelColor=2d3748" alt="Website" />
</a> </a>
<a href="https://discord.gg/3AnUqsXnmK"> <a href="https://discord.gg/3AnUqsXnmK">

View File

@@ -73,7 +73,7 @@ function update_script() {
$STD curl -fsSL https://github.com/filebrowser/filebrowser/releases/download/v2.23.0/linux-amd64-filebrowser.tar.gz | tar -xzv -C /usr/local/bin $STD curl -fsSL https://github.com/filebrowser/filebrowser/releases/download/v2.23.0/linux-amd64-filebrowser.tar.gz | tar -xzv -C /usr/local/bin
$STD filebrowser config init -a '0.0.0.0' $STD filebrowser config init -a '0.0.0.0'
$STD filebrowser config set -a '0.0.0.0' $STD filebrowser config set -a '0.0.0.0'
$STD filebrowser users add admin community-scripts.com --perm.admin $STD filebrowser users add admin helper-scripts.com --perm.admin
msg_ok "Installed FileBrowser" msg_ok "Installed FileBrowser"
msg_info "Creating Service" msg_info "Creating Service"
@@ -93,7 +93,7 @@ WantedBy=default.target" >$service_path
msg_ok "Completed successfully!\n" msg_ok "Completed successfully!\n"
echo -e "FileBrowser should be reachable by going to the following URL. echo -e "FileBrowser should be reachable by going to the following URL.
${BL}http://$LOCAL_IP:8080${CL} admin|community-scripts.com\n" ${BL}http://$LOCAL_IP:8080${CL} admin|helper-scripts.com\n"
exit exit
fi fi
} }

View File

@@ -68,7 +68,7 @@ function update_script() {
$STD curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | bash $STD curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | bash
$STD filebrowser config init -a '0.0.0.0' $STD filebrowser config init -a '0.0.0.0'
$STD filebrowser config set -a '0.0.0.0' $STD filebrowser config set -a '0.0.0.0'
$STD filebrowser users add admin community-scripts.com --perm.admin $STD filebrowser users add admin helper-scripts.com --perm.admin
msg_ok "Installed FileBrowser" msg_ok "Installed FileBrowser"
msg_info "Creating Service" msg_info "Creating Service"
@@ -90,7 +90,7 @@ EOF
msg_ok "Completed successfully!\n" msg_ok "Completed successfully!\n"
echo -e "FileBrowser should be reachable by going to the following URL. echo -e "FileBrowser should be reachable by going to the following URL.
${BL}http://$LOCAL_IP:8080${CL} admin|community-scripts.com\n" ${BL}http://$LOCAL_IP:8080${CL} admin|helper-scripts.com\n"
exit exit
fi fi
if [ "$UPD" == "4" ]; then if [ "$UPD" == "4" ]; then

View File

@@ -50,7 +50,7 @@ function update_script() {
/opt/semaphore/config.json /opt/semaphore/config.json
SEM_PW=$(cat ~/semaphore.creds) SEM_PW=$(cat ~/semaphore.creds)
systemctl start semaphore systemctl start semaphore
$STD semaphore user add --admin --login admin --email admin@community-scripts.com --name Administrator --password "${SEM_PW}" --config /opt/semaphore/config.json $STD semaphore user add --admin --login admin --email admin@helper-scripts.com --name Administrator --password "${SEM_PW}" --config /opt/semaphore/config.json
msg_ok "Moved from BoltDB to SQLite" msg_ok "Moved from BoltDB to SQLite"
fi fi

View File

@@ -62,10 +62,10 @@ expect "Email address"
send "\r" send "\r"
expect "Password" expect "Password"
send "community-scripts.com\r" send "helper-scripts.com\r"
expect "Password (again)" expect "Password (again)"
send "community-scripts.com\r" send "helper-scripts.com\r"
expect eof expect eof
EOF EOF

View File

@@ -58,7 +58,7 @@ service:
use_prerelease: false use_prerelease: false
dashboard: dashboard:
icon: https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/images/logo.png icon: https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/images/logo.png
icon_link_to: https://community-scripts.com/ icon_link_to: https://helper-scripts.com/
web_url: https://github.com/community-scripts/ProxmoxVE/releases web_url: https://github.com/community-scripts/ProxmoxVE/releases
EOF EOF
msg_ok "Setup Config" msg_ok "Setup Config"

View File

@@ -17,7 +17,7 @@ fetch_and_deploy_gh_release "inspircd" "inspircd/inspircd" "binary" "latest" "/o
msg_info "Configuring InspIRCd" msg_info "Configuring InspIRCd"
cat <<EOF >/etc/inspircd/inspircd.conf cat <<EOF >/etc/inspircd/inspircd.conf
<define name="networkDomain" value="community-scripts.com"> <define name="networkDomain" value="helper-scripts.com">
<define name="networkName" value="Proxmox VE Helper-Scripts"> <define name="networkName" value="Proxmox VE Helper-Scripts">
<server <server

View File

@@ -55,10 +55,10 @@ $STD expect <<EOF
set timeout -1 set timeout -1
log_user 0 log_user 0
spawn bin/console kimai:user:create admin admin@community-scripts.com ROLE_SUPER_ADMIN spawn bin/console kimai:user:create admin admin@helper-scripts.com ROLE_SUPER_ADMIN
expect "Please enter the password:" expect "Please enter the password:"
send "community-scripts.com\r" send "helper-scripts.com\r"
expect eof expect eof
EOF EOF

View File

@@ -33,7 +33,7 @@ $STD yarn config set ignore-engines true
$STD yarn install $STD yarn install
$STD yarn run production $STD yarn run production
$STD php artisan key:generate $STD php artisan key:generate
$STD php artisan setup:production --email=admin@community-scripts.com --password=community-scripts.com --force $STD php artisan setup:production --email=admin@helper-scripts.com --password=helper-scripts.com --force
chown -R www-data:www-data /opt/monica chown -R www-data:www-data /opt/monica
chmod -R 775 /opt/monica/storage chmod -R 775 /opt/monica/storage
echo "* * * * * root php /opt/monica/artisan schedule:run >> /dev/null 2>&1" >>/etc/crontab echo "* * * * * root php /opt/monica/artisan schedule:run >> /dev/null 2>&1" >>/etc/crontab

View File

@@ -60,7 +60,7 @@ read -r -p "${TAB3}Enter your ACME Email: " ACME_EMAIL_INPUT
yq -i " yq -i "
.services.npmplus.environment |= .services.npmplus.environment |=
(map(select(. != \"TZ=*\" and . != \"ACME_EMAIL=*\" and . != \"INITIAL_ADMIN_EMAIL=*\" and . != \"INITIAL_ADMIN_PASSWORD=*\")) + (map(select(. != \"TZ=*\" and . != \"ACME_EMAIL=*\" and . != \"INITIAL_ADMIN_EMAIL=*\" and . != \"INITIAL_ADMIN_PASSWORD=*\")) +
[\"TZ=$TZ_INPUT\", \"ACME_EMAIL=$ACME_EMAIL_INPUT\", \"INITIAL_ADMIN_EMAIL=admin@local.com\", \"INITIAL_ADMIN_PASSWORD=community-scripts.com\"]) [\"TZ=$TZ_INPUT\", \"ACME_EMAIL=$ACME_EMAIL_INPUT\", \"INITIAL_ADMIN_EMAIL=admin@local.com\", \"INITIAL_ADMIN_PASSWORD=helper-scripts.com\"])
" /opt/compose.yaml " /opt/compose.yaml
msg_info "Building and Starting NPMplus (Patience)" msg_info "Building and Starting NPMplus (Patience)"

View File

@@ -99,7 +99,7 @@ PHOTOPRISM_DEBUG='false'
PHOTOPRISM_LOG_LEVEL='info' PHOTOPRISM_LOG_LEVEL='info'
# Site Info # Site Info
PHOTOPRISM_SITE_CAPTION='https://community-scripts.com' PHOTOPRISM_SITE_CAPTION='https://Helper-Scripts.com'
PHOTOPRISM_SITE_DESCRIPTION='' PHOTOPRISM_SITE_DESCRIPTION=''
PHOTOPRISM_SITE_AUTHOR='' PHOTOPRISM_SITE_AUTHOR=''
EOF EOF

View File

@@ -40,7 +40,7 @@ cat <<EOF >/opt/semaphore/config.json
"access_key_encryption": "${SEM_KEY}" "access_key_encryption": "${SEM_KEY}"
} }
EOF EOF
$STD semaphore user add --admin --login admin --email admin@community-scripts.com --name Administrator --password "${SEM_PW}" --config /opt/semaphore/config.json $STD semaphore user add --admin --login admin --email admin@helper-scripts.com --name Administrator --password "${SEM_PW}" --config /opt/semaphore/config.json
echo "${SEM_PW}" >~/semaphore.creds echo "${SEM_PW}" >~/semaphore.creds
msg_ok "Setup Semaphore" msg_ok "Setup Semaphore"

View File

@@ -35,7 +35,7 @@ cd Shinobi
gitVersionNumber=$(git rev-parse HEAD) gitVersionNumber=$(git rev-parse HEAD)
theDateRightNow=$(date) theDateRightNow=$(date)
touch version.json touch version.json
chmod 777 version.json chmod 644 version.json
echo '{"Product" : "'"Shinobi"'" , "Branch" : "'"master"'" , "Version" : "'"$gitVersionNumber"'" , "Date" : "'"$theDateRightNow"'" , "Repository" : "'"https://gitlab.com/Shinobi-Systems/Shinobi.git"'"}' >version.json echo '{"Product" : "'"Shinobi"'" , "Branch" : "'"master"'" , "Version" : "'"$gitVersionNumber"'" , "Date" : "'"$theDateRightNow"'" , "Repository" : "'"https://gitlab.com/Shinobi-Systems/Shinobi.git"'"}' >version.json
msg_ok "Cloned Shinobi" msg_ok "Cloned Shinobi"

View File

@@ -23,7 +23,7 @@ fetch_and_deploy_gh_release "tasmoadmin" "TasmoAdmin/TasmoAdmin" "prebuild" "lat
msg_info "Configuring TasmoAdmin" msg_info "Configuring TasmoAdmin"
rm -rf /etc/php/8.4/apache2/conf.d/10-opcache.ini rm -rf /etc/php/8.4/apache2/conf.d/10-opcache.ini
chown -R www-data:www-data /var/www/tasmoadmin chown -R www-data:www-data /var/www/tasmoadmin
chmod 777 /var/www/tasmoadmin/tmp /var/www/tasmoadmin/data chmod 775 /var/www/tasmoadmin/tmp /var/www/tasmoadmin/data
cat <<EOF >/etc/apache2/sites-available/tasmoadmin.conf cat <<EOF >/etc/apache2/sites-available/tasmoadmin.conf
<VirtualHost *:9999> <VirtualHost *:9999>
ServerName tasmoadmin ServerName tasmoadmin

View File

@@ -348,10 +348,10 @@ explain_exit_code() {
json_escape() { json_escape() {
# Escape a string for safe JSON embedding using awk (handles any input size). # Escape a string for safe JSON embedding using awk (handles any input size).
# Pipeline: strip ANSI → remove control chars → escape \ " TAB → join lines with \n # Pipeline: strip ANSI → remove control chars → escape \ " TAB → join lines with \n
printf '%s' "$1" \ printf '%s' "$1" |
| sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' \ sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' |
| tr -d '\000-\010\013\014\016-\037\177\r' \ tr -d '\000-\010\013\014\016-\037\177\r' |
| awk ' awk '
BEGIN { ORS = "" } BEGIN { ORS = "" }
{ {
gsub(/\\/, "\\\\") # backslash → \\ gsub(/\\/, "\\\\") # backslash → \\
@@ -627,8 +627,8 @@ post_to_api() {
[[ "${DEV_MODE:-}" == "true" ]] && echo "[DEBUG] post_to_api() DIAGNOSTICS=$DIAGNOSTICS RANDOM_UUID=$RANDOM_UUID NSAPP=$NSAPP" >&2 [[ "${DEV_MODE:-}" == "true" ]] && echo "[DEBUG] post_to_api() DIAGNOSTICS=$DIAGNOSTICS RANDOM_UUID=$RANDOM_UUID NSAPP=$NSAPP" >&2
# Set type for later status updates # Set type for later status updates (preserve if already set, e.g. turnkey)
TELEMETRY_TYPE="lxc" TELEMETRY_TYPE="${TELEMETRY_TYPE:-lxc}"
local pve_version="" local pve_version=""
if command -v pveversion &>/dev/null; then if command -v pveversion &>/dev/null; then
@@ -692,6 +692,7 @@ EOF
# Send initial "installing" record with retry. # Send initial "installing" record with retry.
# This record MUST exist for all subsequent updates to succeed. # This record MUST exist for all subsequent updates to succeed.
local http_code="" attempt local http_code="" attempt
local _post_success=false
for attempt in 1 2 3; do for attempt in 1 2 3; do
if [[ "${DEV_MODE:-}" == "true" ]]; then if [[ "${DEV_MODE:-}" == "true" ]]; then
http_code=$(curl -sS -w "%{http_code}" -m "${TELEMETRY_TIMEOUT}" -X POST "${TELEMETRY_URL}" \ http_code=$(curl -sS -w "%{http_code}" -m "${TELEMETRY_TIMEOUT}" -X POST "${TELEMETRY_URL}" \
@@ -703,11 +704,19 @@ EOF
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d "$JSON_PAYLOAD" -o /dev/null 2>/dev/null) || http_code="000" -d "$JSON_PAYLOAD" -o /dev/null 2>/dev/null) || http_code="000"
fi fi
[[ "$http_code" =~ ^2[0-9]{2}$ ]] && break if [[ "$http_code" =~ ^2[0-9]{2}$ ]]; then
_post_success=true
break
fi
[[ "$attempt" -lt 3 ]] && sleep 1 [[ "$attempt" -lt 3 ]] && sleep 1
done done
POST_TO_API_DONE=true # Only mark done if at least one attempt succeeded.
# If all 3 failed, POST_TO_API_DONE stays false so post_update_to_api
# and on_exit() know the initial record was never created.
# The server has fallback logic to create a new record on status updates,
# so subsequent calls can still succeed even without the initial record.
POST_TO_API_DONE=${_post_success}
} }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@@ -798,15 +807,19 @@ EOF
# Send initial "installing" record with retry (must succeed for updates to work) # Send initial "installing" record with retry (must succeed for updates to work)
local http_code="" attempt local http_code="" attempt
local _post_success=false
for attempt in 1 2 3; do for attempt in 1 2 3; do
http_code=$(curl -sS -w "%{http_code}" -m "${TELEMETRY_TIMEOUT}" -X POST "${TELEMETRY_URL}" \ http_code=$(curl -sS -w "%{http_code}" -m "${TELEMETRY_TIMEOUT}" -X POST "${TELEMETRY_URL}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d "$JSON_PAYLOAD" -o /dev/null 2>/dev/null) || http_code="000" -d "$JSON_PAYLOAD" -o /dev/null 2>/dev/null) || http_code="000"
[[ "$http_code" =~ ^2[0-9]{2}$ ]] && break if [[ "$http_code" =~ ^2[0-9]{2}$ ]]; then
_post_success=true
break
fi
[[ "$attempt" -lt 3 ]] && sleep 1 [[ "$attempt" -lt 3 ]] && sleep 1
done done
POST_TO_API_DONE=true POST_TO_API_DONE=${_post_success}
} }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@@ -1083,6 +1096,12 @@ EOF
# - Used to group errors in dashboard # - Used to group errors in dashboard
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
categorize_error() { categorize_error() {
# Allow build.func to override category based on log analysis (exit code 1 subclassification)
if [[ -n "${ERROR_CATEGORY_OVERRIDE:-}" ]]; then
echo "$ERROR_CATEGORY_OVERRIDE"
return
fi
local code="$1" local code="$1"
case "$code" in case "$code" in
# Network errors (curl/wget) # Network errors (curl/wget)

View File

@@ -221,6 +221,14 @@ update_motd_ip() {
local current_hostname="$(hostname)" local current_hostname="$(hostname)"
local current_ip="$(hostname -I | awk '{print $1}')" local current_ip="$(hostname -I | awk '{print $1}')"
# Escape sed special chars in replacement strings (& \ |)
current_os="${current_os//\\/\\\\}"
current_os="${current_os//&/\\&}"
current_hostname="${current_hostname//\\/\\\\}"
current_hostname="${current_hostname//&/\\&}"
current_ip="${current_ip//\\/\\\\}"
current_ip="${current_ip//&/\\&}"
# Update only if values actually changed # Update only if values actually changed
if ! grep -q "OS:.*$current_os" "$PROFILE_FILE" 2>/dev/null; then if ! grep -q "OS:.*$current_os" "$PROFILE_FILE" 2>/dev/null; then
sed -i "s|OS:.*|OS: \${GN}$current_os\${CL}\\\"|" "$PROFILE_FILE" sed -i "s|OS:.*|OS: \${GN}$current_os\${CL}\\\"|" "$PROFILE_FILE"
@@ -4076,8 +4084,8 @@ EOF
if [ "$var_os" == "alpine" ]; then if [ "$var_os" == "alpine" ]; then
sleep 3 sleep 3
pct exec "$CTID" -- /bin/sh -c 'cat <<EOF >/etc/apk/repositories pct exec "$CTID" -- /bin/sh -c 'cat <<EOF >/etc/apk/repositories
http://dl-cdn.alpinelinux.org/alpine/latest-stable/main https://dl-cdn.alpinelinux.org/alpine/latest-stable/main
http://dl-cdn.alpinelinux.org/alpine/latest-stable/community https://dl-cdn.alpinelinux.org/alpine/latest-stable/community
EOF' EOF'
pct exec "$CTID" -- ash -c "apk add bash newt curl openssh nano mc ncurses jq" >>"$BUILD_LOG" 2>&1 || { pct exec "$CTID" -- ash -c "apk add bash newt curl openssh nano mc ncurses jq" >>"$BUILD_LOG" 2>&1 || {
msg_error "Failed to install base packages in Alpine container" msg_error "Failed to install base packages in Alpine container"
@@ -4086,7 +4094,9 @@ EOF'
else else
sleep 3 sleep 3
LANG=${LANG:-en_US.UTF-8} LANG=${LANG:-en_US.UTF-8}
pct exec "$CTID" -- bash -c "sed -i \"/$LANG/ s/^# //\" /etc/locale.gen" local LANG_ESC="${LANG//./\\.}"
LANG_ESC="${LANG_ESC//|/\\|}"
pct exec "$CTID" -- bash -c "sed -i \"/$LANG_ESC/ s/^# //\" /etc/locale.gen"
pct exec "$CTID" -- bash -c "locale_line=\$(grep -v '^#' /etc/locale.gen | grep -E '^[a-zA-Z]' | awk '{print \$1}' | head -n 1) && \ pct exec "$CTID" -- bash -c "locale_line=\$(grep -v '^#' /etc/locale.gen | grep -E '^[a-zA-Z]' | awk '{print \$1}' | head -n 1) && \
echo LANG=\$locale_line >/etc/default/locale && \ echo LANG=\$locale_line >/etc/default/locale && \
locale-gen >/dev/null && \ locale-gen >/dev/null && \
@@ -4216,6 +4226,53 @@ EOF'
fi fi
fi fi
# Defense-in-depth: Ensure error handling stays disabled during recovery.
# Some functions (e.g. silent/$STD) unconditionally re-enable set -Eeuo pipefail
# and trap 'error_handler' ERR. If any code path above called such a function,
# the grep/sed pipelines below would trigger error_handler on non-match (exit 1).
set +Eeuo pipefail
trap - ERR
# --- Exit code 1 subclassification: analyze logs BEFORE telemetry call ---
# Exit code 1 is generic ("General error"). Analyze logs to determine the
# real error category so telemetry gets a useful classification instead of "shell".
local is_oom=false
local is_network_issue=false
local is_apt_issue=false
local is_cmd_not_found=false
local is_disk_full=false
if [[ $install_exit_code -eq 1 && -f "$combined_log" ]]; then
if grep -qiE 'E: Unable to|E: Package|E: Failed to fetch|dpkg.*error|broken packages|unmet dependencies|dpkg --configure -a' "$combined_log"; then
is_apt_issue=true
fi
if grep -qiE 'Cannot allocate memory|Out of memory|oom-killer|Killed process|JavaScript heap' "$combined_log"; then
is_oom=true
fi
if grep -qiE 'Could not resolve|DNS|Connection refused|Network is unreachable|No route to host|Temporary failure resolving|Failed to fetch' "$combined_log"; then
is_network_issue=true
fi
if grep -qiE ': command not found|No such file or directory.*/s?bin/' "$combined_log"; then
is_cmd_not_found=true
fi
if grep -qiE 'ENOSPC|no space left on device|Disk quota exceeded|errno -28' "$combined_log"; then
is_disk_full=true
fi
fi
# Set override for categorize_error() so telemetry gets the real category
if [[ "$is_apt_issue" == true ]]; then
export ERROR_CATEGORY_OVERRIDE="dependency"
elif [[ "$is_oom" == true ]]; then
export ERROR_CATEGORY_OVERRIDE="resource"
elif [[ "$is_network_issue" == true ]]; then
export ERROR_CATEGORY_OVERRIDE="network"
elif [[ "$is_disk_full" == true ]]; then
export ERROR_CATEGORY_OVERRIDE="storage"
elif [[ "$is_cmd_not_found" == true ]]; then
export ERROR_CATEGORY_OVERRIDE="dependency"
fi
# Report failure to telemetry API (now with log available on host) # Report failure to telemetry API (now with log available on host)
# NOTE: Do NOT use msg_info/spinner here — the background spinner process # NOTE: Do NOT use msg_info/spinner here — the background spinner process
# causes SIGTSTP in non-interactive shells (bash -c "$(curl ...)"), which # causes SIGTSTP in non-interactive shells (bash -c "$(curl ...)"), which
@@ -4224,13 +4281,6 @@ EOF'
post_update_to_api "failed" "$install_exit_code" post_update_to_api "failed" "$install_exit_code"
$STD echo -e "${TAB}${CM:-} Failure reported" $STD echo -e "${TAB}${CM:-} Failure reported"
# Defense-in-depth: Ensure error handling stays disabled during recovery.
# Some functions (e.g. silent/$STD) unconditionally re-enable set -Eeuo pipefail
# and trap 'error_handler' ERR. If any code path above called such a function,
# the grep/sed pipelines below would trigger error_handler on non-match (exit 1).
set +Eeuo pipefail
trap - ERR
# Show combined log location # Show combined log location
if [[ -n "$CTID" && -n "${SESSION_ID:-}" ]]; then if [[ -n "$CTID" && -n "${SESSION_ID:-}" ]]; then
msg_custom "📋" "${YW}" "Installation log: ${combined_log}" msg_custom "📋" "${YW}" "Installation log: ${combined_log}"
@@ -4259,12 +4309,9 @@ EOF'
# Prompt user for cleanup with 60s timeout # Prompt user for cleanup with 60s timeout
echo "" echo ""
# Detect error type for smart recovery options # Extend error detection for non-exit-1 codes (exit 1 was already analyzed above)
local is_oom=false # The is_* flags were set above for exit code 1 log analysis; here we add
local is_network_issue=false # exit-code-specific detections for other codes.
local is_apt_issue=false
local is_cmd_not_found=false
local is_disk_full=false
local error_explanation="" local error_explanation=""
if declare -f explain_exit_code >/dev/null 2>&1; then if declare -f explain_exit_code >/dev/null 2>&1; then
error_explanation="$(explain_exit_code "$install_exit_code")" error_explanation="$(explain_exit_code "$install_exit_code")"
@@ -4314,26 +4361,6 @@ EOF'
;; ;;
esac esac
# Exit 1 subclassification: analyze logs to identify actual root cause
# Many exit 1 errors are actually APT, OOM, network, or command-not-found issues
if [[ $install_exit_code -eq 1 && -f "$combined_log" ]]; then
if grep -qiE 'E: Unable to|E: Package|E: Failed to fetch|dpkg.*error|broken packages|unmet dependencies|dpkg --configure -a' "$combined_log"; then
is_apt_issue=true
fi
if grep -qiE 'Cannot allocate memory|Out of memory|oom-killer|Killed process|JavaScript heap' "$combined_log"; then
is_oom=true
fi
if grep -qiE 'Could not resolve|DNS|Connection refused|Network is unreachable|No route to host|Temporary failure resolving|Failed to fetch' "$combined_log"; then
is_network_issue=true
fi
if grep -qiE ': command not found|No such file or directory.*/s?bin/' "$combined_log"; then
is_cmd_not_found=true
fi
if grep -qiE 'ENOSPC|no space left on device|Disk quota exceeded|errno -28' "$combined_log"; then
is_disk_full=true
fi
fi
# Show error explanation if available # Show error explanation if available
if [[ -n "$error_explanation" ]]; then if [[ -n "$error_explanation" ]]; then
echo -e "${TAB}${RD}Error: ${error_explanation}${CL}" echo -e "${TAB}${RD}Error: ${error_explanation}${CL}"
@@ -4535,6 +4562,7 @@ EOF'
if [[ $apt_retry_code -eq 0 ]]; then if [[ $apt_retry_code -eq 0 ]]; then
msg_ok "Installation completed successfully after APT repair!" msg_ok "Installation completed successfully after APT repair!"
INSTALL_COMPLETE=true
post_update_to_api "done" "0" "force" post_update_to_api "done" "0" "force"
return 0 return 0
else else
@@ -4759,6 +4787,10 @@ fix_gpu_gids() {
pct stop "$CTID" >/dev/null 2>&1 pct stop "$CTID" >/dev/null 2>&1
sleep 1 sleep 1
# Validate GIDs are numeric before sed
[[ "$render_gid" =~ ^[0-9]+$ ]] || render_gid="104"
[[ "$video_gid" =~ ^[0-9]+$ ]] || video_gid="44"
# Update dev entries with correct GIDs # Update dev entries with correct GIDs
sed -i.bak -E "s|(dev[0-9]+: /dev/dri/renderD[0-9]+),gid=[0-9]+|\1,gid=${render_gid}|g" "$LXC_CONFIG" sed -i.bak -E "s|(dev[0-9]+: /dev/dri/renderD[0-9]+),gid=[0-9]+|\1,gid=${render_gid}|g" "$LXC_CONFIG"
sed -i -E "s|(dev[0-9]+: /dev/dri/card[0-9]+),gid=[0-9]+|\1,gid=${video_gid}|g" "$LXC_CONFIG" sed -i -E "s|(dev[0-9]+: /dev/dri/card[0-9]+),gid=[0-9]+|\1,gid=${video_gid}|g" "$LXC_CONFIG"
@@ -5672,7 +5704,7 @@ description() {
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' 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;'/> <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>
@@ -5705,6 +5737,7 @@ EOF
systemctl start ping-instances.service systemctl start ping-instances.service
fi fi
INSTALL_COMPLETE=true
post_update_to_api "done" "none" post_update_to_api "done" "none"
} }

View File

@@ -507,14 +507,23 @@ _stop_container_if_installing() {
on_exit() { on_exit() {
local exit_code=$? local exit_code=$?
# Report orphaned "installing" records to telemetry API # Report orphaned telemetry records
# Catches ALL exit paths: errors, signals, AND clean exits where # Two scenarios handled:
# post_to_api was called but post_update_to_api was never called # 1. POST_TO_API_DONE=true but POST_UPDATE_DONE=false: Record was created but
if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then # never got a final status update → send abort/done now.
if [[ $exit_code -ne 0 ]]; then # 2. POST_TO_API_DONE=false but DIAGNOSTICS=yes: Initial post failed (server
_send_abort_telemetry "$exit_code" # unreachable/timeout), but the server has fallback create-on-update logic,
elif declare -f post_update_to_api >/dev/null 2>&1; then # so a status update can still create the record. Worth one last try.
post_update_to_api "done" "0" 2>/dev/null || true if [[ "${POST_UPDATE_DONE:-}" != "true" ]]; then
if [[ "${POST_TO_API_DONE:-}" == "true" || "${DIAGNOSTICS:-no}" == "yes" ]]; then
if [[ $exit_code -ne 0 ]]; then
_send_abort_telemetry "$exit_code"
elif [[ "${INSTALL_COMPLETE:-}" == "true" ]] && declare -f post_update_to_api >/dev/null 2>&1; then
# Only report success if the install was explicitly marked complete.
# Without this guard, early bailouts (e.g. user cancelled) with exit 0
# would be falsely reported as successful installations.
post_update_to_api "done" "0" 2>/dev/null || true
fi
fi fi
fi fi

View File

@@ -309,14 +309,14 @@ customize() {
if [[ "$PASSWORD" == "" ]]; then if [[ "$PASSWORD" == "" ]]; then
msg_info "Customizing Container" msg_info "Customizing Container"
GETTY_OVERRIDE="/etc/systemd/system/container-getty@1.service.d/override.conf" GETTY_OVERRIDE="/etc/systemd/system/container-getty@1.service.d/override.conf"
mkdir -p $(dirname $GETTY_OVERRIDE) mkdir -p "$(dirname "$GETTY_OVERRIDE")"
cat <<EOF >$GETTY_OVERRIDE cat <<EOF >"$GETTY_OVERRIDE"
[Service] [Service]
ExecStart= ExecStart=
ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud tty%I 115200,38400,9600 \$TERM ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud tty%I 115200,38400,9600 \$TERM
EOF EOF
systemctl daemon-reload systemctl daemon-reload
systemctl restart $(basename $(dirname $GETTY_OVERRIDE) | sed 's/\.d//') systemctl restart "$(basename "$(dirname "$GETTY_OVERRIDE")" | sed 's/\.d//')"
msg_ok "Customized Container" msg_ok "Customized Container"
fi fi
echo "bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${app}.sh)\"" >/usr/bin/update echo "bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${app}.sh)\"" >/usr/bin/update

View File

@@ -242,7 +242,7 @@ download_gpg_key() {
# Process based on mode # Process based on mode
if [[ "$mode" == "dearmor" ]]; then if [[ "$mode" == "dearmor" ]]; then
if gpg --dearmor --yes -o "$output" <"$temp_key" 2>/dev/null; then if gpg --dearmor --yes -o "$output" <"$temp_key" 2>/dev/null && [[ -s "$output" ]]; then
rm -f "$temp_key" rm -f "$temp_key"
debug_log "GPG key installed (dearmored): $output" debug_log "GPG key installed (dearmored): $output"
return 0 return 0
@@ -5192,7 +5192,7 @@ _setup_gpu_permissions() {
for nvidia_dev in /dev/nvidia*; do for nvidia_dev in /dev/nvidia*; do
[[ -e "$nvidia_dev" ]] && { [[ -e "$nvidia_dev" ]] && {
chgrp video "$nvidia_dev" 2>/dev/null || true chgrp video "$nvidia_dev" 2>/dev/null || true
chmod 666 "$nvidia_dev" 2>/dev/null || true chmod 660 "$nvidia_dev" 2>/dev/null || true
} }
done done
if [[ -d /dev/nvidia-caps ]]; then if [[ -d /dev/nvidia-caps ]]; then
@@ -5200,7 +5200,7 @@ _setup_gpu_permissions() {
for caps_dev in /dev/nvidia-caps/*; do for caps_dev in /dev/nvidia-caps/*; do
[[ -e "$caps_dev" ]] && { [[ -e "$caps_dev" ]] && {
chgrp video "$caps_dev" 2>/dev/null || true chgrp video "$caps_dev" 2>/dev/null || true
chmod 666 "$caps_dev" 2>/dev/null || true chmod 660 "$caps_dev" 2>/dev/null || true
} }
done done
fi fi
@@ -5217,7 +5217,8 @@ _setup_gpu_permissions() {
# /dev/kfd permissions (AMD ROCm) # /dev/kfd permissions (AMD ROCm)
if [[ -e /dev/kfd ]]; then if [[ -e /dev/kfd ]]; then
chmod 666 /dev/kfd 2>/dev/null || true chgrp render /dev/kfd 2>/dev/null || true
chmod 660 /dev/kfd 2>/dev/null || true
msg_info "AMD ROCm compute device configured" msg_info "AMD ROCm compute device configured"
fi fi

View File

@@ -594,7 +594,7 @@ set_description() {
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' 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;'/> <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>

View File

@@ -165,9 +165,9 @@ function install() {
else else
read -rp "${TAB}Set admin username [admin]: " admin_user read -rp "${TAB}Set admin username [admin]: " admin_user
admin_user=${admin_user:-admin} admin_user=${admin_user:-admin}
read -rsp "${TAB}Set admin password [community-scripts.com]: " admin_pass read -rsp "${TAB}Set admin password [helper-scripts.com]: " admin_pass
echo "" echo ""
admin_pass=${admin_pass:-community-scripts.com} admin_pass=${admin_pass:-helper-scripts.com}
msg_ok "Configured with admin user: ${admin_user}" msg_ok "Configured with admin user: ${admin_user}"
fi fi

View File

@@ -201,9 +201,9 @@ server:
- neverWatchPath: "/lost+found" - neverWatchPath: "/lost+found"
auth: auth:
adminUsername: admin adminUsername: admin
adminPassword: community-scripts.com adminPassword: helper-scripts.com
EOF EOF
msg_ok "Configured with default admin (admin / community-scripts.com)" msg_ok "Configured with default admin (admin / helper-scripts.com)"
fi fi
msg_info "Creating service" msg_info "Creating service"

View File

@@ -140,8 +140,8 @@ if [[ "${install_prompt,,}" =~ ^(y|yes)$ ]]; then
cd /usr/local/community-scripts cd /usr/local/community-scripts
filebrowser config init -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" &>/dev/null filebrowser config init -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" &>/dev/null
filebrowser config set -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" &>/dev/null filebrowser config set -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" &>/dev/null
filebrowser users add admin community-scripts.com --perm.admin --database "$DB_PATH" &>/dev/null filebrowser users add admin helper-scripts.com --perm.admin --database "$DB_PATH" &>/dev/null
msg_ok "Default authentication configured (admin:community-scripts.com)" msg_ok "Default authentication configured (admin:helper-scripts.com)"
fi fi
msg_info "Creating service" msg_info "Creating service"

View File

@@ -150,7 +150,7 @@ function install() {
curl -fsSL "https://raw.githubusercontent.com/runtipi/runtipi/master/scripts/install.sh" -o "install.sh" curl -fsSL "https://raw.githubusercontent.com/runtipi/runtipi/master/scripts/install.sh" -o "install.sh"
chmod +x install.sh chmod +x install.sh
$STD ./install.sh $STD ./install.sh
chmod 666 /opt/runtipi/state/settings.json 2>/dev/null || true chmod 660 /opt/runtipi/state/settings.json 2>/dev/null || true
rm -f /opt/install.sh rm -f /opt/install.sh
msg_ok "Installed ${APP}" msg_ok "Installed ${APP}"

View File

@@ -551,7 +551,7 @@ qm set $VMID \
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' 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;'/> <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>

View File

@@ -631,7 +631,7 @@ rm -f "$WORK_FILE"
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' 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;'/> <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>

View File

@@ -568,7 +568,7 @@ fi
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' 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;'/> <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>

View File

@@ -639,7 +639,7 @@ msg_ok "Resized disk"
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' 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;'/> <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>

View File

@@ -622,7 +622,7 @@ qm set $VMID \
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' 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;'/> <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>

View File

@@ -546,7 +546,7 @@ qm set $VMID \
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' 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;'/> <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>

View File

@@ -605,7 +605,7 @@ msg_ok "Resized disk to ${DISK_SIZE}"
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' 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;'/> <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>

View File

@@ -750,7 +750,7 @@ qm resize $VMID scsi0 20G >/dev/null
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'> <a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/michelroegl-brunner/ProxmoxVE/refs/heads/develop/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/> <img src='https://raw.githubusercontent.com/michelroegl-brunner/ProxmoxVE/refs/heads/develop/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>

View File

@@ -560,7 +560,7 @@ qm set $VMID \
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' 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;'/> <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>

View File

@@ -462,7 +462,7 @@ qm set $VMID \
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' 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;'/> <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>

View File

@@ -610,7 +610,7 @@ fi
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' 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;'/> <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>

View File

@@ -542,7 +542,7 @@ qm set $VMID \
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' 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;'/> <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>

View File

@@ -544,7 +544,7 @@ qm set $VMID \
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' 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;'/> <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>

View File

@@ -543,7 +543,7 @@ qm set $VMID \
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' 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;'/> <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>

View File

@@ -590,7 +590,7 @@ qm resize $VMID scsi0 ${DISK_SIZE} >/dev/null
DESCRIPTION=$( DESCRIPTION=$(
cat <<EOF cat <<EOF
<div align='center'> <div align='center'>
<a href='https://community-scripts.com' 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;'/> <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a> </a>