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
- Cleans orphaned DB user records before recreating webacct
- Handles both orphaned-Linux-user and orphaned-DB-user cases
- Pulls latest NovaCPX code + runs migrations
- Bumps PHP-FPM pm.max_children to 20 if still at default 5
- Creates /tmp/_nova_create_webacct.php helper separately (avoids here-doc PHP issues)
- Deploys both index.html and notes.php from web-dashboard repo
- Disables Apache2 if running
- --no-git flag to skip code pull
- Comprehensive logging with ✓/⚠ indicators
deploy-runner.sh was rsyncing panel/public/ but VERSION lives at repo
root — web root /srv/novacpx/public/VERSION was perpetually stale.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Settings page now loads current values from DB and saves via save-option API
- check-novacpx-update reads update_channel setting, checks origin/main or origin/beta
- apply-novacpx-update pulls from channel branch, fixes backup dir (/tmp), fixes SQLite migration syntax, records new version in novacpx_version table + settings.panel_version
- deploy-runner.sh reads update_channel from DB, pulls correct branch, records version after deploy
- webhook.php accepts pushes to both main and beta branches
- Updates page shows channel badge and latest remote version
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Switches migration tracking from MySQL to SQLite (panel.db), reads DB path
from config.ini with fallback to /var/lib/novacpx/panel.db. Re-creates the
webhook symlink after each rsync deploy so it survives --delete.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- novacpx-webserver-switch: new helper script that manages ports 80/443
only; panel ports 8880-8883 are never touched
- system.php: save-option web_server now calls the helper script instead
of stopping all web servers (which killed the panel)
- admin.js: server options shows live Apache/Nginx status badges and notes
that the panel always runs on Apache
- Notifier.php + test-notify: use plain email address in 'from' field
(CyberMail rejects "Name <email>" format)
- deploy-runner.sh: rsync panel/api/ and panel/lib/ to web root after
panel/public/ sync; also syncs panel/bin/ to /opt/novacpx/bin/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- firewall.php: auto-detect server IPs (loopback, all interface IPs,
private /24 subnets) for Fail2Ban ignoreip; f2b-ignoreip-list/add/
remove/reset actions; write to jail.local directly (www-data owns it);
f2b_set_ignoreip() reloads fail2ban after every change
- auth.php: log failed logins to /var/log/novacpx/access.log in format
fail2ban filters expect — "FAILED LOGIN from <IP> [portal]"
- deploy/fail2ban/: filter.d conf files for all 4 NovaCPX jails
- install.sh: auto-detect local IPs → ignoreip in jail.local; install
filter files; create access.log (www-data:www-data 664)
- admin.js: Fail2Ban Whitelist section in firewall page — chip list with
add/remove/reset; loopback shown with lock icon and non-removable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>