#!/usr/bin/env bash # Universal Proxmox Subscription Nag Remover - Improved Version # Works with PVE (Proxmox VE), PBS (Proxmox Backup Server), and PMG (Proxmox Mail Gateway) # # Based on community-scripts by tteck and contributors # Original scripts: https://community-scripts.github.io/ProxmoxVE/ # License: MIT # Copyright (c) 2021-2025 community-scripts contributors set -euo pipefail # Colors for output RD=$(echo "\033[01;31m") YW=$(echo "\033[33m") GN=$(echo "\033[1;92m") BL=$(echo "\033[94m") CL=$(echo "\033[m") BFR="\\r\\033[K" HOLD="-" CM="${GN}✓${CL}" CROSS="${RD}✗${CL}" INFO="${BL}ℹ${CL}" # Output functions msg_info() { local msg="$1" echo -ne " ${HOLD} ${YW}${msg}..." } msg_ok() { local msg="$1" echo -e "${BFR} ${CM} ${GN}${msg}${CL}" } msg_error() { local msg="$1" echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}" } msg_note() { local msg="$1" echo -e " ${INFO} ${BL}${msg}${CL}" } # Header header_info() { clear cat <<"EOF" ╔═════════════════════════════════════════════════════════════════════════════╗ ║ Universal Proxmox Nag Remover - Improved ║ ║ PVE • PBS • PMG Support ║ ╚═════════════════════════════════════════════════════════════════════════════╝ EOF echo -e "${BL}Universal Subscription Nag Remover for All Proxmox Products${CL}" echo -e "${YW}Based on community-scripts: https://community-scripts.github.io/ProxmoxVE/${CL}" echo "" } # Detect Proxmox product detect_proxmox() { local product="" local version="" if command -v pveversion >/dev/null 2>&1; then product="PVE" version=$(pveversion | head -1) elif command -v proxmox-backup-manager >/dev/null 2>&1; then product="PBS" version=$(proxmox-backup-manager version 2>/dev/null | head -1 || echo "PBS detected") elif command -v pmgversion >/dev/null 2>&1; then product="PMG" version=$(pmgversion | head -1) elif [ -f /usr/bin/pmg-admin ]; then product="PMG" version="PMG detected" else msg_error "No supported Proxmox product detected" echo "" echo "This script supports:" echo " • Proxmox VE (PVE)" echo " • Proxmox Backup Server (PBS)" echo " • Proxmox Mail Gateway (PMG)" exit 1 fi echo "$product|$version" } # Function to apply nag removal to files apply_nag_patch() { local file="$1" local backup_file="${file}.backup-$(date +%s)" if [ -f "$file" ]; then # Create backup cp "$file" "$backup_file" # Apply multiple patterns to catch different variations sed -i.tmp \ -e "s/data\.status !== 'active'/false/g" \ -e "s/data\.status!=='active'/false/g" \ -e "s/data\.status != 'active'/false/g" \ -e "s/data\.status!='active'/false/g" \ -e "s/checked_command: 'subscription'/checked_command: 'no-subscription'/g" \ -e "/getNoSubKeyHtml.*{/,/},/{s/text: gettext('No valid subscription')/text: ''/g}" \ -e "s/'No valid subscription'/''/g" \ -e "/.*data\.status.*{/{s/\!//g; s/active/NoMoreNagging/g}" \ "$file" # Clean up tmp file rm -f "${file}.tmp" echo "Patched: $file" return 0 else echo "File not found: $file" return 1 fi } # Check if nag is present in file check_nag_present() { local file="$1" if [ -f "$file" ]; then grep -q "No valid subscription\|data\.status.*active" "$file" 2>/dev/null else return 1 fi } # Apply nag removal based on product apply_nag_removal() { local product="$1" case $product in PVE) msg_info "Applying PVE subscription nag removal" # More robust apt hook for PVE cat > /etc/apt/apt.conf.d/no-nag-script << 'EOF' DPkg::Post-Invoke { "if [ -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js ]; then if grep -q 'No valid subscription\\|data\\.status.*active' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js 2>/dev/null; then echo 'Reapplying PVE subscription nag removal...'; sed -i \ -e 's/data\\.status !== '\"'\"'active'\"'\"'/false/g' \ -e 's/data\\.status!==='\"'\"'active'\"'\"'/false/g' \ -e 's/data\\.status != '\"'\"'active'\"'\"'/false/g' \ -e 's/data\\.status!='\"'\"'active'\"'\"'/false/g' \ -e 's/checked_command: '\"'\"'subscription'\"'\"'/checked_command: '\"'\"'no-subscription'\"'\"'/g' \ -e '/getNoSubKeyHtml.*{/,/},/{s/text: gettext('\"'\"'No valid subscription'\"'\"')/text: '\"'\"''\"'\"'/g}' \ -e 's/'\"'\"'No valid subscription'\"'\"'/'\"'\"''\"'\"'/g' \ -e '/.*data\\.status.*{/{s/\\!//g; s/active/NoMoreNagging/g}' \ /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; echo 'PVE nag removal reapplied successfully.'; fi; fi"; }; EOF # Apply initial patch apply_nag_patch "/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js" msg_ok "PVE subscription nag removal applied" ;; PBS) msg_info "Applying PBS subscription nag removal" # More robust apt hook for PBS cat > /etc/apt/apt.conf.d/no-nag-script << 'EOF' DPkg::Post-Invoke { "if [ -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js ]; then if grep -q 'No valid subscription\\|data\\.status.*active' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js 2>/dev/null; then echo 'Reapplying PBS subscription nag removal...'; sed -i \ -e 's/data\\.status !== '\"'\"'active'\"'\"'/false/g' \ -e 's/data\\.status!==='\"'\"'active'\"'\"'/false/g' \ -e 's/data\\.status != '\"'\"'active'\"'\"'/false/g' \ -e 's/data\\.status!='\"'\"'active'\"'\"'/false/g' \ -e '/data\\.status.*{/{s/\\!//g; s/active/NoMoreNagging/g}' \ /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; echo 'PBS nag removal reapplied successfully.'; fi; fi"; }; EOF # Apply initial patch apply_nag_patch "/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js" msg_ok "PBS subscription nag removal applied" ;; PMG) msg_info "Applying PMG subscription nag removal" # More robust apt hook for PMG (both desktop and mobile) cat > /etc/apt/apt.conf.d/no-nag-script << 'EOF' DPkg::Post-Invoke { "if [ -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js ]; then if grep -q 'No valid subscription\\|data\\.status.*active' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js 2>/dev/null; then echo 'Reapplying PMG subscription nag removal (desktop)...'; sed -i \ -e 's/data\\.status !== '\"'\"'active'\"'\"'/false/g' \ -e 's/data\\.status!==='\"'\"'active'\"'\"'/false/g' \ -e 's/data\\.status != '\"'\"'active'\"'\"'/false/g' \ -e 's/data\\.status!='\"'\"'active'\"'\"'/false/g' \ -e '/.*data\\.status.*{/{s/\\!//g; s/active/NoMoreNagging/g}' \ /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; echo 'PMG desktop nag removal reapplied successfully.'; fi; fi; if [ -f /usr/share/javascript/pmg-gui/js/pmgmanagerlib-mobile.js ]; then if grep -q 'No valid subscription\\|data\\.status.*active' /usr/share/javascript/pmg-gui/js/pmgmanagerlib-mobile.js 2>/dev/null; then echo 'Reapplying PMG subscription nag removal (mobile)...'; sed -i \ -e 's/data\\.status !== '\"'\"'active'\"'\"'/false/g' \ -e 's/data\\.status!==='\"'\"'active'\"'\"'/false/g' \ -e 's/data\\.status != '\"'\"'active'\"'\"'/false/g' \ -e 's/data\\.status!='\"'\"'active'\"'\"'/false/g' \ -e '/data\\.status.*{/{s/\\!//g; s/active/NoMoreNagging/g}' \ /usr/share/javascript/pmg-gui/js/pmgmanagerlib-mobile.js; echo 'PMG mobile nag removal reapplied successfully.'; fi; fi"; }; EOF # Apply initial patches apply_nag_patch "/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js" apply_nag_patch "/usr/share/javascript/pmg-gui/js/pmgmanagerlib-mobile.js" msg_ok "PMG subscription nag removal applied (desktop & mobile)" ;; esac } # Test if the current fix is working test_current_fix() { local product="$1" local files_to_check=() case $product in PVE|PBS) files_to_check=("/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js") ;; PMG) files_to_check=( "/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js" "/usr/share/javascript/pmg-gui/js/pmgmanagerlib-mobile.js" ) ;; esac local nag_found=false for file in "${files_to_check[@]}"; do if check_nag_present "$file"; then nag_found=true echo "⚠ Nag still present in: $file" fi done if [ "$nag_found" = false ]; then echo "✓ No subscription nags detected in relevant files" return 0 else return 1 fi } # Main execution main() { # Check if running as root if [[ $EUID -ne 0 ]]; then echo "This script must be run as root (use sudo)" exit 1 fi header_info # Detect Proxmox product msg_info "Detecting Proxmox product" detection_result=$(detect_proxmox) IFS='|' read -r PRODUCT VERSION <<< "$detection_result" msg_ok "Detected $PRODUCT" msg_note "$VERSION" echo "" # Check current status msg_info "Checking current nag status" if test_current_fix "$PRODUCT"; then msg_ok "No subscription nags currently present" if [[ -f /etc/apt/apt.conf.d/no-nag-script ]]; then echo "" echo "✓ Apt hook is installed and nags are already removed" echo "✓ The fix should persist through updates" echo "" echo "If nags return after updates, there may be a new pattern to patch." echo "Run this script again to update the fix." exit 0 fi else msg_ok "Subscription nags detected - fix needed" fi # Check if hook exists but isn't working if [[ -f /etc/apt/apt.conf.d/no-nag-script ]]; then msg_info "Updating existing apt hook" rm -f /etc/apt/apt.conf.d/no-nag-script msg_ok "Old hook removed" fi echo "" # Show subscription support message echo -e "${YW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CL}" echo -e "${BL} Support Subscriptions${CL}" echo -e "${YW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CL}" echo "" echo "Supporting the software's development team is essential. Check their official" echo "website's Support Subscriptions for pricing. Without their dedicated work," echo "we wouldn't have this exceptional software." echo "" echo -e "${YW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CL}" echo "" # Confirm installation echo "This will disable the subscription nag message that appears when logging" echo "into the web interface. The fix will automatically reapply after updates." echo "" while true; do read -p "Continue with subscription nag removal? (y/n): " yn case $yn in [Yy]*) break ;; [Nn]*) echo "Aborted." exit 0 ;; *) echo "Please answer yes or no." ;; esac done echo "" # Apply the fix apply_nag_removal "$PRODUCT" echo "" # Test the fix msg_info "Testing nag removal" if test_current_fix "$PRODUCT"; then msg_ok "Nag removal test passed" else msg_error "Nag removal test failed - manual intervention may be needed" fi echo "" echo -e "${GN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CL}" echo -e "${GN} Installation Complete${CL}" echo -e "${GN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CL}" echo "" echo "✓ The subscription nag has been disabled for $PRODUCT" echo "✓ The fix will automatically reapply after Proxmox updates" echo "✓ Clear your browser cache and refresh the web interface" echo "" if [[ "$PRODUCT" == "PMG" ]]; then echo "✓ Both desktop and mobile interfaces have been patched" echo "" fi echo "To test the apt hook manually, run:" echo " apt --reinstall install proxmox-widget-toolkit" echo "" echo -e "${YW}Original community-scripts: https://community-scripts.github.io/ProxmoxVE/${CL}" echo "" } # Run main function main "$@"