mirror of
https://github.com/myronblair/novacpx
synced 2026-06-30 17:50:41 -05:00
feat: #40 Linux uninstaller
- Full backup before removal: DB, all account home dirs, nginx vhosts, SSL certs, DNS zones, mail config, logs, systemd units, cron jobs - Backup compressed to /tmp/novacpx-uninstall-backup-TIMESTAMP.tar.gz - Prints scp command + temp HTTP server option to download backup - Requires confirmation (or --yes flag to skip) - Removes: hosting accounts + Linux users, PHP-FPM pools, nginx vhosts, novacpx-web systemd unit, sudoers rules, cron jobs, opendkim keys, DNS zones, postfix virtual tables, fail2ban filters - Removes all NovaCPX directories: /srv/novacpx /opt/novacpx-src /opt/novacpx /var/lib/novacpx /var/log/novacpx /etc/novacpx - Restores nginx default site - Leaves base services (nginx, php-fpm, postfix, etc.) running - Usage: bash uninstall.sh [--yes]
This commit is contained in:
Executable
+220
@@ -0,0 +1,220 @@
|
||||
#!/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
|
||||
tar -czf "$BACKUP_ARCHIVE" -C "$(dirname $BACKUP_DIR)" "$(basename $BACKUP_DIR)" 2>/dev/null
|
||||
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" "/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 ""
|
||||
Reference in New Issue
Block a user