- 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
- Adminer installed at /adminer.php (MySQL + PostgreSQL)
- db-tools API now detects adminer.php file and returns its URL
- Tool cards: phpMyAdmin, Adminer (MySQL/PG), pgAdmin4
- Open buttons use API-provided URL (adminer.php for Adminer)
- Separate MySQL and PostgreSQL database sections in DB Manager
- PostgreSQL section has direct link to Adminer PG mode
- #42 Docker: already complete (full docker page with all tabs)
Previous merge accidentally deleted 38KB of page functions (accounts, packages,
DNS, etc.) by using wrong boundary. This time only removes the serverStatus()
function body. Dashboard now includes history chart + setTimeout to render it.
All other pages intact.
- Row badge updates to 'stopping…'/'starting…' instantly on click
- Buttons disabled while action runs so no double-clicks
- List stays visible while refreshing after action (no blank flash)
- container-remove changed to POST so body passes through proxies correctly
- removeImage now throws RuntimeException when docker rmi output contains
'Error' or 'conflict' so the API returns success:false with the message
- Added docker/sync-orphans endpoint (admin only) to register existing
Docker containers not tracked in the NovaCPX DB (e.g. after a restore)
Concurrent cron writes (collect-stats.php every 5min) caused DB lock errors
that aborted the entire stats response, leaving web/mail/FTP pages empty.
History insert is now non-fatal.
Using PORT_USER ?? 8880 threw Error in PHP 8 since the constant isn't defined
until Core.php is require_once'd later in the file. Every API request was
hitting the exception handler and returning 'An internal error occurred.',
breaking all logins and API calls.
#38 — User panel Account > Settings page: account info, resource usage
gauges, PHP config (version/memory/upload/exec), quick links to SSL/2FA/password.
#39 — AccountManager: dark-themed modern default index.html on account
creation; supports custom HTML template from admin Server Options
(saved as default_index_template setting, {domain}/{username} placeholders).
Admin Server Options: new card to set/reset the custom template.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LP9Q4kfCAYAjJnsbHBrViZ
Admin: global view of all subdomains/parked across accounts; nav items added
Reseller: filtered view scoped to their customers' accounts
User: create/remove subdomains and parked domains for own account
Backend already existed in api/endpoints/domains.php (add-subdomain,
add-alias, list, remove actions).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LP9Q4kfCAYAjJnsbHBrViZ
- CORS: replace open regex with explicit hostname allowlist + port whitelist
- Exception handler: only expose RuntimeException/InvalidArgumentException
messages; PDOException and others return generic 'internal error'
- Auth::portalUrl(): allowlist-validate HTTP_HOST before using it in
redirect URL — prevents open redirect via Host header injection
- _branding.php custom_css: strip HTML tags, js: URLs, @import, expression()
instead of just </style> which was trivially bypassable
- accounts create: check accounts table as well as users for username
uniqueness (TOCTOU fix); wrap user INSERT + provisioning in single
transaction so rollback is atomic on failure
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LP9Q4kfCAYAjJnsbHBrViZ