mirror of
https://github.com/myronblair/novacpx
synced 2026-06-30 09:40:38 -05:00
3a1746b0c0
1. admin.js: dashboard setTimeout was after return (dead code) — restructured to assign template to const html, run setTimeout, then return html 2. DockerManager.php createStack: replaced SELECT LAST_INSERT_ID() with db->insert() which already returns lastInsertId correctly for SQLite 3. DockerManager.php setQuota: replaced ON DUPLICATE KEY UPDATE / VALUES() MySQL syntax with SQLite-compatible ON CONFLICT(user_id) DO UPDATE SET excluded.col syntax 4. post-restore.sh: PHP helper file now written ONCE at start of step 4 before any call to it (was written AFTER first call, causing silent failure) 5. post-restore.sh: git pull exit code now captured before pipeline (the while-read loop always exited 0, masking pull failures) 6. uninstall.sh: tar backup now aborts on failure (previously 2>/dev/null swallowed errors and rm -rf destroyed source unconditionally); also rm -f → rm -rf for .service.d drop-in directory
226 lines
10 KiB
Bash
Executable File
226 lines
10 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# NovaCPX Uninstaller
|
|
# Backs up everything, then cleanly removes all NovaCPX components.
|
|
# Usage: bash uninstall.sh [--yes]
|
|
|
|
set -euo pipefail
|
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BOLD='\033[1m'; NC='\033[0m'
|
|
log() { echo -e "${GREEN}[✓]${NC} $*"; }
|
|
warn() { echo -e "${YELLOW}[!]${NC} $*"; }
|
|
fail() { echo -e "${RED}[✗]${NC} $*"; exit 1; }
|
|
step() { echo -e "\n${BOLD}━━━ $* ━━━${NC}"; }
|
|
|
|
[[ $EUID -ne 0 ]] && fail "Run as root"
|
|
|
|
SKIP_CONFIRM="${1:-}"
|
|
DB_PATH=$(python3 -c "import configparser; c=configparser.ConfigParser(); c.read('/etc/novacpx/config.ini'); print(c.get('database','path',fallback='/var/lib/novacpx/panel.db'))" 2>/dev/null || echo "/var/lib/novacpx/panel.db")
|
|
BACKUP_DIR="/tmp/novacpx-uninstall-backup-$(date +%Y%m%d-%H%M%S)"
|
|
BACKUP_ARCHIVE="${BACKUP_DIR}.tar.gz"
|
|
|
|
echo ""
|
|
echo -e "${BOLD}NovaCPX Uninstaller${NC}"
|
|
echo "This will completely remove NovaCPX and all hosted accounts."
|
|
echo ""
|
|
|
|
# ── STEP 1: Create full backup ─────────────────────────────────────────────
|
|
step "Creating full backup before removal"
|
|
|
|
mkdir -p "$BACKUP_DIR"/{db,configs,accounts,logs,certs,nginx,systemd,cron}
|
|
|
|
# Database
|
|
[[ -f "$DB_PATH" ]] && {
|
|
cp "$DB_PATH" "$BACKUP_DIR/db/panel.db"
|
|
log "Database backed up"
|
|
}
|
|
|
|
# All account home directories
|
|
if [[ -f "$DB_PATH" ]]; then
|
|
while IFS='|' read -r user home; do
|
|
[[ -d "$home" ]] && cp -a "$home" "$BACKUP_DIR/accounts/" 2>/dev/null && log "Account: $user ($home)"
|
|
done < <(sqlite3 "$DB_PATH" "SELECT username, home_dir FROM accounts;" 2>/dev/null)
|
|
fi
|
|
|
|
# Config files
|
|
[[ -d /etc/novacpx ]] && cp -a /etc/novacpx "$BACKUP_DIR/configs/" && log "NovaCPX configs"
|
|
[[ -d /var/lib/novacpx ]] && cp -a /var/lib/novacpx "$BACKUP_DIR/db/var-lib-novacpx" 2>/dev/null
|
|
|
|
# Nginx vhosts
|
|
cp /etc/nginx/sites-available/novacpx-*.conf "$BACKUP_DIR/nginx/" 2>/dev/null || true
|
|
log "Nginx vhosts"
|
|
|
|
# SSL certs per account
|
|
[[ -d /etc/novacpx/ssl/accounts ]] && cp -a /etc/novacpx/ssl/accounts "$BACKUP_DIR/certs/" && log "SSL certs"
|
|
|
|
# Systemd units
|
|
cp /etc/systemd/system/novacpx*.service "$BACKUP_DIR/systemd/" 2>/dev/null || true
|
|
log "Systemd units"
|
|
|
|
# Cron
|
|
cp /etc/cron.d/novacpx "$BACKUP_DIR/cron/" 2>/dev/null || true
|
|
log "Cron jobs"
|
|
|
|
# Logs
|
|
[[ -d /var/log/novacpx ]] && cp -a /var/log/novacpx "$BACKUP_DIR/logs/" && log "Logs"
|
|
|
|
# DNS zones
|
|
[[ -d /var/cache/bind ]] && cp -a /var/cache/bind "$BACKUP_DIR/configs/bind-cache" 2>/dev/null || true
|
|
[[ -f /etc/bind/named.conf.local ]] && cp /etc/bind/named.conf.local "$BACKUP_DIR/configs/" 2>/dev/null || true
|
|
|
|
# Mail config
|
|
[[ -d /etc/postfix ]] && cp -a /etc/postfix "$BACKUP_DIR/configs/postfix" 2>/dev/null || true
|
|
[[ -d /etc/dovecot ]] && cp -a /etc/dovecot "$BACKUP_DIR/configs/dovecot" 2>/dev/null || true
|
|
|
|
# Compress backup — abort if tar fails rather than silently delete unbackedup files
|
|
tar -czf "$BACKUP_ARCHIVE" -C "$(dirname $BACKUP_DIR)" "$(basename $BACKUP_DIR)" || {
|
|
echo -e "${RED}[✗]${NC} Backup archive creation FAILED. Uninstall aborted to protect your data."
|
|
echo " Staging dir preserved at: $BACKUP_DIR"
|
|
exit 1
|
|
}
|
|
rm -rf "$BACKUP_DIR"
|
|
BACKUP_SIZE=$(du -sh "$BACKUP_ARCHIVE" | cut -f1)
|
|
log "Backup archive: $BACKUP_ARCHIVE ($BACKUP_SIZE)"
|
|
|
|
echo ""
|
|
echo -e "${BOLD}Backup complete.${NC}"
|
|
echo ""
|
|
echo "To download the backup before continuing:"
|
|
echo " scp root@$(hostname -I | awk '{print $1}'):${BACKUP_ARCHIVE} ./"
|
|
echo ""
|
|
echo "Or serve temporarily:"
|
|
echo " cd $(dirname $BACKUP_ARCHIVE) && python3 -m http.server 9999 &"
|
|
echo " # Download: http://$(hostname -I | awk '{print $1}'):9999/$(basename $BACKUP_ARCHIVE)"
|
|
echo ""
|
|
|
|
if [[ "$SKIP_CONFIRM" != "--yes" ]]; then
|
|
read -r -p "Continue with uninstall? This CANNOT be undone. [yes/no]: " CONFIRM
|
|
[[ "$CONFIRM" != "yes" ]] && { warn "Aborted."; exit 0; }
|
|
fi
|
|
|
|
# ── STEP 2: Stop all NovaCPX services ────────────────────────────────────
|
|
step "Stopping services"
|
|
systemctl stop novacpx-web 2>/dev/null && log "Stopped novacpx-web" || true
|
|
systemctl disable novacpx-web 2>/dev/null || true
|
|
|
|
# ── STEP 3: Remove hosting accounts ──────────────────────────────────────
|
|
step "Removing hosting accounts"
|
|
if [[ -f "$DB_PATH" ]]; then
|
|
while IFS='|' read -r username home_dir; do
|
|
[[ -z "$username" ]] && continue
|
|
# Remove Linux user and home dir
|
|
id "$username" &>/dev/null && userdel -r "$username" 2>/dev/null && log "Removed user: $username" || true
|
|
# Remove PHP-FPM pool
|
|
rm -f "/etc/php/8.3/fpm/pool.d/${username}.conf" 2>/dev/null || true
|
|
# Remove nginx vhost
|
|
rm -f "/etc/nginx/sites-available/novacpx-${username}.conf" \
|
|
"/etc/nginx/sites-enabled/novacpx-${username}.conf" 2>/dev/null || true
|
|
done < <(sqlite3 "$DB_PATH" "SELECT username, home_dir FROM accounts;" 2>/dev/null)
|
|
fi
|
|
|
|
# Also clean any remaining novacpx vhosts
|
|
rm -f /etc/nginx/sites-available/novacpx-*.conf \
|
|
/etc/nginx/sites-enabled/novacpx-*.conf 2>/dev/null || true
|
|
log "Nginx vhosts removed"
|
|
|
|
# Remove webacct if exists
|
|
id webacct &>/dev/null && userdel -r webacct 2>/dev/null || true
|
|
|
|
# ── STEP 4: Remove PHP-FPM pools ─────────────────────────────────────────
|
|
step "Removing PHP-FPM pools"
|
|
for f in /etc/php/*/fpm/pool.d/novacpx-*.conf /etc/php/*/fpm/pool.d/webacct.conf; do
|
|
[[ -f "$f" ]] && rm -f "$f" && log "Removed pool: $f" || true
|
|
done
|
|
systemctl reload php8.3-fpm 2>/dev/null || true
|
|
|
|
# ── STEP 5: Remove systemd units ─────────────────────────────────────────
|
|
step "Removing systemd units"
|
|
for svc in novacpx-web; do
|
|
systemctl stop "$svc" 2>/dev/null; systemctl disable "$svc" 2>/dev/null
|
|
rm -f "/etc/systemd/system/${svc}.service"
|
|
rm -rf "/etc/systemd/system/${svc}.service.d"
|
|
log "Removed: $svc"
|
|
done
|
|
systemctl daemon-reload
|
|
|
|
# ── STEP 6: Remove sudoers ────────────────────────────────────────────────
|
|
step "Removing sudoers rules"
|
|
for f in novacpx novacpx-firewall novacpx-panel novacpx-services; do
|
|
rm -f "/etc/sudoers.d/$f" && log "Removed sudoers: $f" || true
|
|
done
|
|
# Remove any novacpx entries added to main sudoers
|
|
sed -i '/Defaults:www-data !requiretty/d' /etc/sudoers 2>/dev/null || true
|
|
|
|
# ── STEP 7: Remove cron jobs ──────────────────────────────────────────────
|
|
step "Removing cron jobs"
|
|
rm -f /etc/cron.d/novacpx && log "Removed /etc/cron.d/novacpx" || true
|
|
# Remove root crontab entries added by NovaCPX
|
|
crontab -l 2>/dev/null | grep -v "novacpx" | crontab - 2>/dev/null || true
|
|
log "Root crontab cleaned"
|
|
|
|
# ── STEP 8: Remove nginx default override ────────────────────────────────
|
|
step "Restoring nginx defaults"
|
|
# Restore default site (remove 444 return we added)
|
|
cat > /etc/nginx/sites-available/default << 'NGINX'
|
|
server {
|
|
listen 80 default_server;
|
|
listen [::]:80 default_server;
|
|
root /var/www/html;
|
|
index index.html index.htm;
|
|
server_name _;
|
|
location / { try_files $uri $uri/ =404; }
|
|
}
|
|
NGINX
|
|
nginx -t 2>/dev/null && systemctl reload nginx && log "nginx restored"
|
|
|
|
# ── STEP 9: Remove mail/DNS config added by NovaCPX ──────────────────────
|
|
step "Removing mail/DNS config"
|
|
# Remove opendkim signing entries for hosted domains
|
|
[[ -f /etc/opendkim/signing.table ]] && > /etc/opendkim/signing.table || true
|
|
[[ -f /etc/opendkim/key.table ]] && > /etc/opendkim/key.table || true
|
|
rm -rf /etc/opendkim/keys/* 2>/dev/null || true
|
|
systemctl reload opendkim 2>/dev/null || true
|
|
log "DKIM config cleared"
|
|
|
|
# Remove DNS zones for hosted domains
|
|
rm -f /etc/bind/zones/db.novacpx.* 2>/dev/null || true
|
|
# Remove novacpx entries from named.conf.local
|
|
[[ -f /etc/bind/named.conf.local ]] && \
|
|
sed -i '/novacpx/d' /etc/bind/named.conf.local 2>/dev/null || true
|
|
systemctl reload named 2>/dev/null || true
|
|
log "DNS zones cleared"
|
|
|
|
# Postfix virtual mailbox maps
|
|
[[ -f /etc/postfix/novacpx_virtual_domains ]] && {
|
|
rm -f /etc/postfix/novacpx_virtual_domains /etc/postfix/novacpx_virtual_mailbox \
|
|
/etc/postfix/novacpx_virtual_aliases 2>/dev/null || true
|
|
postmap /etc/postfix/novacpx_* 2>/dev/null || true
|
|
systemctl reload postfix 2>/dev/null || true
|
|
log "Postfix virtual tables cleared"
|
|
}
|
|
|
|
# ── STEP 10: Remove all NovaCPX files ────────────────────────────────────
|
|
step "Removing NovaCPX files"
|
|
rm -rf /srv/novacpx && log "Removed /srv/novacpx"
|
|
rm -rf /opt/novacpx-src && log "Removed /opt/novacpx-src"
|
|
rm -rf /opt/novacpx && log "Removed /opt/novacpx"
|
|
rm -rf /var/lib/novacpx && log "Removed /var/lib/novacpx"
|
|
rm -rf /var/log/novacpx && log "Removed /var/log/novacpx"
|
|
rm -rf /etc/novacpx && log "Removed /etc/novacpx"
|
|
rm -f /etc/nginx/htpasswd.webacct 2>/dev/null || true
|
|
rm -f /usr/local/bin/novacpx* /usr/local/bin/novacpx-* 2>/dev/null || true
|
|
# Remove fail2ban filters
|
|
rm -f /etc/fail2ban/filter.d/novacpx-*.conf \
|
|
/etc/fail2ban/jail.d/novacpx*.conf 2>/dev/null || true
|
|
systemctl reload fail2ban 2>/dev/null || true
|
|
log "fail2ban filters removed"
|
|
|
|
# ── DONE ──────────────────────────────────────────────────────────────────
|
|
echo ""
|
|
echo -e "${GREEN}${BOLD}NovaCPX has been fully uninstalled.${NC}"
|
|
echo ""
|
|
echo "Backup archive preserved at: $BACKUP_ARCHIVE"
|
|
echo ""
|
|
echo "Services still running (not removed, NovaCPX didn't own these):"
|
|
echo " nginx, php8.3-fpm, postfix, dovecot, bind9, fail2ban"
|
|
echo " (stop/remove them separately if no longer needed)"
|
|
echo ""
|