Skip to content

Releases: BrowserlessAPI/VortexPanel

VortexPanel v3.4.0 — Go/Node.js Project Manager, FFmpeg & Memcached, Website Import, Nine-Distro Reliability

Choose a tag to compare

@BrowserlessAPI BrowserlessAPI released this 08 Jul 11:36

VortexPanel v3.4.0 — Go/Node.js Project Manager, FFmpeg & Memcached, Website Import, Nine-Distro Reliability

Release date: July 2026

The biggest release since v3.2.0's security overhaul. Two entirely new deployment managers (Go and Node.js binary/app hosting — something none of cPanel, Plesk, aaPanel, or HestiaCP offer out of the box), a full Website Import wizard for migrating off other panels, two new App Store modules, and a broad reliability pass across all nine supported distros and both x86_64/arm64 architectures.


🚀 Go Projects & Node.js Projects — New Deployment Managers

VortexPanel can now host compiled Go binaries and Node.js applications directly, with the same one-click simplicity as a WordPress install.

Go Projects

  • Binary-only deployment — point at a compiled Go binary, VortexPanel handles the rest
  • Go SDK manager — install/switch between multiple Go versions side by side, GOPROXY configuration (official/goproxy.io/goproxy.cn/direct)
  • systemd service — auto-restart on crash, enable-on-boot, journal logging
  • Reverse proxy on all 4 webservers — nginx, Apache, OpenLiteSpeed, and Caddy, auto-detected
  • WebSocket support — proper Upgrade/Connection header handling on nginx and Apache (needed for gorilla/websocket, gRPC-Web, etc.) — the shared nginx $connection_upgrade map is written once and reused across every proxied project
  • Let's Encrypt SSL per domain — nginx/Apache use certbot's native plugin, OpenLiteSpeed uses certonly + manual vhost wiring, Caddy is detected as already-automatic (no action needed)
  • Resource limitsMemoryMax / CPUQuota in the systemd unit, so a runaway process gets capped instead of taking down the whole server
  • On-demand health checks — real TCP connect to the app's port, catching the case Restart=always can't: a hung process still holding the port open
  • Binary version history + rollback — every start/restart snapshots the binary (skipped if unchanged, via SHA-256 hash), keeps the last 5 versions, one-click revert
  • Firewall integration (UFW + firewalld), all 9 supported distros

Node.js Projects

  • PM2 + systemd — choose either process manager per project
  • nvm-based version switching — install and switch Node versions without affecting other projects
  • Same reverse-proxy-on-all-4-webservers support as Go Projects
  • Current LTS reality reflected: v24 Active LTS default, v22 Maintenance, v18/v20 correctly blocked as EOL

📥 Website Import Wizard — Migrate from cPanel, aaPanel, HestiaCP

A new "Import Website" flow on the Websites page, upload-based (no SSH pull required):

  1. Upload the backup archive exported from your old panel
  2. Detect — VortexPanel extracts it and makes a best-effort guess at the domain, PHP version, document root, and database dump
  3. Confirm — every detected field is editable before anything happens; nothing is auto-executed blind
  4. Import — creates the site + nginx vhost (the exact same code path as "New Website", so imported sites are indistinguishable from natively-created ones), copies files, creates the database and imports the dump, generates a fresh random DB password (originals are never in a backup dump, so there's nothing to recover)

Supports cPanel (cpmove/full-backup format, userdata YAML domain detection), aaPanel (domain-folder detection + .sql/.sql.gz filename matching), and HestiaCP (v-backup-user's nested web.tar/mysql.tar format). Files + database only in this release — email, cron, and SSL migration are not yet included.


📦 App Store — 2 New Modules

  • FFmpeg Manager — install multiple FFmpeg versions side by side (7.1, 8.1, and nightly master), each with its own command alias (ffmpeg7, ffmpeg8). Sourced from BtbN/FFmpeg-Builds — the provider ffmpeg.org's own download page links to for Linux static builds — with full x86_64 and arm64 support
  • Memcached — full management UI: Service (start/stop/restart/reload), Config File editor, Switch Version, Load Status (live stats via Memcached's own stats protocol), and Optimization (bind IP/port/cache size/max connections)

App Store module count: 27 (up from 25).


🖥 Dashboard & Monitoring

  • Realtime charts — CPU/RAM history and Network I/O, client-side rolling window, no backend polling changes needed
  • Global SSL expiry banner — aggregates certificate expiry across every site, warns at 14 days with severity-graded colour coding (yellow → orange → red-for-expired)
  • Settings → Audit Log viewer — last 200 login attempts (time/status/IP/user/note) — the backend already existed, it just had no UI until now
  • Per-site disk usage — lazy-loaded (only fires when you open a site's Directory tab, so it doesn't slow down the Websites list on servers with many/large sites)

🛠 Reliability — RHEL-Family & arm64 Fixes

A full audit turned up (and fixed) install-time failures that were silently breaking on real-world server configurations:

  • RHEL/CentOS/Fedora/AlmaLinux/Rockynginx, MySQL, Caddy, MongoDB, and PostgreSQL were previously completely uninstallable on any RHEL-family distro. The install scripts only had a Debian-specific GPG-keyring + sources.list code path; on RHEL this produced garbage commands (dpkg -i on a distro with no dpkg, Debian package names fed to dnf, etc.). All 5 now have proper distro-aware install paths — MySQL uses RHEL's built-in AppStream module stream (no external repo needed at all), PostgreSQL correctly disables the conflicting built-in module before installing PGDG's versioned packages.
  • arm64 — MongoDB and PostgreSQL RHEL install paths had hardcoded x86_64 in the repo URLs, silently breaking on ARM servers. MongoDB now uses dnf's auto-resolving $basearch; PostgreSQL detects the real architecture via uname -m.
  • A pre-existing Caddy bug (not new — this predates the audit) was piping a fetched GPG key into rm -f instead of gpg --dearmor, producing an empty/invalid keyring on Debian too, not just RHEL. Fixed.
  • All module install/uninstall cycles audited for safety on repeat runs — GPG keys and repo files are now properly cleaned up on uninstall, preventing reinstall failures.

🎨 UI System — Modal & Layout Fixes

A cluster of related frontend bugs, all traced to the same root causes and fixed together:

  • Modal centering — the underlying issue was position:fixed breaking when nested inside a scrolling ancestor (overflow-y:auto containers). All modals are now rendered as direct children of <body> via a shared global portal pattern, using explicit width:100vw;height:100vh so they're immune to any ancestor's overflow settings.
  • Horizontal scrollbar shifting the entire panel — a classic flexbox min-width:auto trap: .main-area and .page-content were flex:1 with no min-width:0, so a single unconstrained <select> dropdown with long option text (App Store version pickers) could force the whole layout wider instead of scrolling internally. Fixed at the source, plus a body-level safety net.
  • Cross-component scoping bugs — several modals had their interactive functions defined inside the wrong Alpine.js component (a page's own scope instead of the global scope the portal actually renders in), causing buttons to silently do nothing. Standardized on the same pattern used by toast()/get()/post(): plain global functions, reachable from any component.
  • Eight pages (dashboard, docker, settings, files, mail, bandwidth, security, caddy) had dead method calls in their tab-refresh event listeners from an earlier bulk edit — switching to those tabs was silently failing. All fixed.

🔩 Smaller Fixes

  • Self-hosted SVG brand logos for all App Store modules — zero CDN dependency for icons
  • nginx version bump — Stable 1.30.3, Mainline 1.31.2 (security patch)
  • Update-check false positive (was comparing git hash against semver)
  • Databases page now auto-detects MongoDB/PostgreSQL correctly with engine-aware columns
  • Install/uninstall hang fixes — proper timeouts (10min install, 5min uninstall, 8min switch), service-stop-before-remove ordering
  • install.sh now clones to a permanent /root/Vortexpanel instead of /tmp (which gets wiped on reboot, silently orphaning git tracking) — and auto-generates a correctly-pathed deploy.sh during install

VortexPanel v3.3.0 — Visual Design, Multi-Webserver HTTP/3, Live Terminal, Mail & Bandwidth

Choose a tag to compare

@BrowserlessAPI BrowserlessAPI released this 22 Jun 09:30

VortexPanel v3.3.0 — Visual Design, Multi-Webserver HTTP/3, Live Terminal, Mail & Bandwidth

Release date: June 2026

A broad quality-of-life release covering visual polish, long-standing bugs, and several features that were half-built in earlier versions and are now complete and properly tested.


🎨 Visual Design Overhaul

The dashboard and sidebar were reworked to feel intentional rather than generic.

  • Stat cards — each of the four dashboard metric cards now has its own colour identity: CPU (blue), RAM (purple), Disk (amber), Uptime (green). Each card has a left accent bar, a tinted progress bar, a coloured metric value, and a ghost emoji icon. The old design used a single cyan colour across all four.
  • Sidebar icon pills — every nav item now has a small coloured pill behind its icon (unique colour per section). Active item switches to blue with a filled pill, matching the style used by aaPanel and modern control panels.
  • Active nav colour — changed from cyan (#0e7490) to blue (#2563eb) for stronger contrast.
  • Semantic stat colour variables--stat-cpu, --stat-ram, --stat-disk, --stat-uptime added to theme.css for consistent use across the panel.
  • App Store settings sidebar — the floating settings window tabs now use the same coloured icon pill pattern as the main sidebar, replacing the previous plain text-only tabs.

⚡ HTTP/3 — Full Multi-Webserver Support

The previous HTTP/3 toggle only worked on nginx and showed a static "go install it yourself" warning for everything else. It now handles all four supported webservers correctly:

  • nginx (nginx.org official package, 1.25+): Enable/Disable toggle. Writes listen 443 quic reuseport and Alt-Svc header. Automatically opens UDP 443 in UFW or firewalld.
  • nginx (distro package, 1.25+): Detects that the package lacks --with-http_v3_module. Shows a one-click "Upgrade to nginx.org Mainline" button that installs the official package, preserving all existing vhost configs.
  • nginx (< 1.25): Clear error message — too old, no upgrade path within the distro.
  • Caddy: Shows "Always On" — Caddy enables HTTP/3 automatically when SSL is active. Panel checks and opens UDP 443 if needed.
  • OpenLiteSpeed: Same as Caddy — HTTP/3 is default-on. Panel ensures UDP 443 is open.
  • Apache: Clear "Not Supported" message explaining why and suggesting switching to nginx or Caddy.
  • UDP 443 firewall — opening UDP 443 is now done automatically on enable for all supported webservers across UFW (Debian/Ubuntu) and firewalld (RHEL/Fedora/Alma/Rocky).

🔧 Bug Fixes — SyntaxWarnings in modules.py

Seven invalid escape sequences in modules.py that would break on strict Python builds (Python 3.12+ raises SyntaxWarning, future versions will error):

  • Lines 368, 405, 421: \., \s, \K in regular strings → raw strings (r'''...''')
  • Lines 1065, 1217, 1405: \s, \K, \S in f-strings → raw f-strings (rf"...")

🔄 Session Persistence — Survives Restarts

Root cause: Flask's default client-side signed cookie sessions are invalidated when gunicorn restarts, because each worker independently generates a secret key if the file doesn't exist yet — causing a race condition where workers end up with different keys in memory.

Fix: Enabled flask-session (already in requirements.txt but never activated) with SESSION_TYPE = 'filesystem'. Session data is now stored as files in /opt/vortexpanel/sessions/. The session cookie holds only a signed session ID. Sessions survive gunicorn restarts, nginx reloads, and worker recycling. Sessions can be individually invalidated server-side on logout.


📊 Live Installation Terminal — All App Store Actions

The App Store previously showed no progress when switching versions — the button would appear to do nothing for several minutes, then either succeed or fail with no output.

Root cause chain (three separate bugs):

  1. switch_version used blocking sh() calls with no output streaming
  2. Jobs were stored in an in-memory dict (_jobs = {}), but gunicorn runs with --workers 4 — each worker has its own memory space, so the SSE stream (potentially on worker 2) couldn't see jobs created on worker 1
  3. The SSE stream opened before the job file was created, immediately got "Job not found", and closed silently — leaving the terminal blank forever

Fix: Full rewrite of the job system:

  • All three actions (install, uninstall, switch version) now use the same SSE streaming pipeline
  • Jobs stored as JSONL files in /tmp/vortex_jobs/ — append-only, shared across all workers via the filesystem
  • SSE stream waits up to 5 seconds for the job file to appear before giving up
  • subprocess output streams line-by-line in real time via Popen with bufsize=1
  • 8-minute process timeout kills hung operations (e.g. apt-get update waiting on a slow mirror)
  • apt-get network timeout set to 30 seconds per mirror on all switch scripts

Terminal colours: All output lines now have explicit hex colours so they're readable on the black terminal background: regular apt output (#d1fae5), info lines (#67e8f9 cyan), success (#4ade80 green bold), warnings (#fbbf24 amber bold).


🗄 MariaDB — Settings & Versions Fixed

  • Optimization tab was blanksave_module_settings() never defined mod, causing a NameError in the run_switch closure. Added mod = _get_mod(mod_id) at the top of the handler.
  • MariaDB settings response missing fields — the GET handler returned status, version, conf_path, conf_content, logs, port but was missing optimization, current_status, slow_log, log_path, datadir. All fields now match the MySQL handler.
  • save_optimization had no MariaDB handler — nginx, Apache, and OLS had handlers; MySQL/MariaDB fell through silently. Now reads the correct .cnf path per distro, updates existing keys with regex, appends new keys under [mysqld] if missing, then restarts the service.
  • Versions updated: Added MariaDB 12.3.2 (Latest), 11.8.8, keeping 11.4 LTS, 10.11 LTS, 10.6 LTS. Previous list was missing the entire 12.x series.

🔒 Database Version Switching — Removed (Uninstall-First Approach)

Following aaPanel's approach: switching a running database engine version in-place risks data corruption, especially on downgrades. The "Switch Version" tab has been removed from MariaDB, MySQL, PostgreSQL, and MongoDB settings modals.

The safe workflow is: Uninstall → Install new version from App Store. Version switching remains available for non-database modules (Redis, nginx, Apache, OLS, Caddy, Node.js, BIND9, pure-ftpd).


🌐 Two-Webserver Conflict Detection

If two webservers (e.g. nginx + apache2) are both active simultaneously — causing port 80/443 conflicts and unpredictable routing — the dashboard now shows a red warning banner with a "Fix Now →" button linking directly to Services. Detection runs in parallel with the existing CPU/disk/services poll on every dashboard stats request.


📧 Mail — Forwarding & Logs Completed

  • Forwarding tab previously broke silently because selDomain was only set when the user clicked a domain in the Mailboxes tab. The Forwarding tab now has its own domain selector dropdown, independent of the Mailboxes tab.
  • Mail logs now support: line count selector (100/300/500), log type filter (All/Postfix/Dovecot), real-time client-side search/filter, RHEL log path (/var/log/maillog) with journalctl fallback, configurable via ?lines= query param.

🟢 Node.js — Versions Corrected, Switch Bug Fixed

  • EOL versions removed: v18 (EOL Oct 2023) and v20 (EOL Apr 2026) removed from all version lists.
  • Default install updated: Was setup_20.x (EOL). Now setup_24.x (Active LTS).
  • Active LTS labelled correctly: v24 "Krypton" is Active LTS; v22 "Jod" is Maintenance LTS; v26 is Current (non-LTS until Oct 2026).
  • Switch version bug fixed: Switching from v26 to v24 previously installed v26 again because the old nodesource repo was still active and apt resolved to v26. Fix: old nodesource repo, list, and GPG keys are removed before the new version's setup script runs.
  • nodejs_install_script() default in os_utils.py updated from '22''24'.

🚀 nginx Install — UDP 443 + Stream Block

nginx_install_script() in os_utils.py now runs two post-install steps automatically:

  • stream {} block added to /etc/nginx/nginx.conf if missing (required for TCP load balancing to work at all — was causing silent failure on fresh installs).
  • UDP 443 opened in UFW (Debian/Ubuntu) and firewalld (RHEL/Fedora/Alma/Rocky) — required for HTTP/3 QUIC. Idempotent; safe to run if firewall is not active.

🔌 nginx Stream Module — Auto-Install All 9 Distros

The TCP Load Balancer previously showed a static warning telling users to run apt install libnginx-mod-stream manually. It now installs automatically:

  • Debian/Ubuntu: apt install libnginx-mod-stream, with retry after apt update if first attempt fails.
  • RHEL/Fedora/AlmaLinux/Rocky/CentOS: Checks if .so already exists (nginx.org packages bundle it). Falls back to dnf install nginx-mod-stream if not found.
  • After install: ensures load_module directive exists in nginx.conf, runs nginx -t, reloads nginx.
  • Detects Debian's auto-created modules-enabled/50-mod-stream.conf symlink and skips manual injection when present.
  • Compatible with nginx 1.24 through 1.31.x.

Upgrading

cd /root/Vortexpanel
git pull
cp -r panel/ web/ app.py /opt/vortexpanel/
mkdir -p /opt/vortexpanel/sessions
systemctl restart vortexpanel

Or fresh install:

wget -O install.sh https://raw.githubusercontent.com/BrowserlessAPI/VortexPanel/main/install.sh ...
Read more

VortexPanel v3.1.0 — WP Toolkit, firewalld, Performance

Choose a tag to compare

@BrowserlessAPI BrowserlessAPI released this 17 Jun 01:26

VortexPanel v3.1.0 — WP Toolkit, firewalld, Performance

Release date: June 2026

This is a large release. The headline addition is the WP Toolkit — a full WordPress management module with a better UI than aaPanel's, built entirely free with no Pro tier required. There are also critical bug fixes that affected every fresh install via install.sh.


🔷 New: WP Toolkit

Full WordPress lifecycle management — install, manage, secure, stage, back up — without needing a separate plugin or paid add-on.

Install

  • One-command WordPress install: downloads core, creates DB, writes wp-config.php, runs the installer, creates the vhost, sets file ownership, configures SSL, and enables system cron — all in one click
  • PHP 7.4 → 8.5 support with automatic FPM socket detection across all distros
  • Nginx, Apache, OpenLiteSpeed, Caddy — correct vhost template per webserver including permalink rewrite rules
  • MariaDB and MySQL — auto-detected
  • Auto-generates a non-default admin username and randomised table prefix (security defaults)
  • Detects which webservers are actually installed — warns and blocks if you select one that isn't

Manage

  • Site cards grid: WP version, PHP badge, SSL status, plugin/theme counts, update count
  • Slide-in drawer with 7 tabs: Overview, Plugins, Themes, Security, Staging, Backups, Settings
  • One-click admin login (wp-cli user session create → auto-login URL, no password needed)
  • Plugin management: list, activate, deactivate, update, delete, bulk update all
  • Theme management: list, activate, update, delete
  • Core update with database migration

Security scanner

  • 9-point scan: admin username strength, file permissions, WP version, SSL, debug mode, XML-RPC exposure, wp-config.php HTTP access, plugin versions, login URL exposure
  • A/B/C grade with score (0–100)
  • One-click fix buttons for every failed check

Staging

  • Full site clone (rsync files + DB export/import + URL search-replace)
  • Creates a vhost for the staging domain automatically
  • Push staging → live: auto-creates a backup of live first, then syncs files + DB + URL rewrite
  • Pull live → staging

More

  • Backup/restore: tar.gz of files + DB dump
  • Settings: site title, email, password reset, language, PHP version switch, debug mode, maintenance mode, search engine visibility, system cron
  • wp-cli auto-installed if not present

🔥 New: firewalld support (Fedora / RHEL / AlmaLinux / Rocky / Oracle / CentOS / CloudLinux)

The Firewall module previously only supported UFW (Debian/Ubuntu). Every RHEL-family distro uses firewalld, so the Firewall page showed inactive/empty and all actions silently no-op'd on those systems.

Now fully supported on both:

  • UFW path (Debian/Ubuntu): unchanged
  • firewalld path (Fedora/RHEL-family): --list-ports, --list-services, --list-rich-rules merged into a unified numbered list; --add-port for simple allow rules, --add-rich-rule for deny/reject/source-restricted rules; presets (webserver, mailserver, database) via rich rules; toggle enable/disable via systemctl

Also fixed on all distros: the frontend sent protocol but the backend read proto — UDP rules silently became TCP. Now fixed in both UFW and firewalld paths.


🐛 Critical bug fixes

app.py — gunicorn entrypoint crash-loop on every fresh install

app = create_app() was only defined inside if __name__ == '__main__'. The systemd service created by install.sh runs gunicorn ... app:app, which imports the module — that block never executed. Every fresh install via install.sh produced a crash-looping service that would never start. Fixed by defining app = create_app() at module level.

Pages not loading after login (browser refresh required)

All page components (x-data="websitesPage()" etc.) were initialised by Alpine.js at page load time — before login — so every init() hit 401 and stored empty data, which was never re-fetched after login. Added document.addEventListener('vortex-logged-in', ...) to all 22 page component init() functions. _onLoggedIn() already dispatched this event; now every page listens for it.

Dashboard Disk card showing blank / wrong bar width

ramPct() and diskPct() were called in the Dashboard template as methods but never defined in dashboardPage(). Alpine threw a silent ReferenceError, leaving the Disk card value empty and the bar fill defaulting to nearly-full regardless of actual usage.

dashboard/stats — 10× performance improvement

Replaced top -bn1 (800–1500ms per request, waits for a CPU measurement cycle) with /proc/stat 100ms sample. RAM, load, uptime, and network now read from /proc (instant). Services detection changed from 8 sequential systemctl is-active calls to one batch call. Added 1.5s TTL cache. Total dashboard stats response: ~103ms (was ~1000ms).

security.py — two 500 Internal Server Errors

  • GET /api/security/modsecurity: sh() returns a 3-tuple in this file but rules_count was assigned the whole tuple and passed to int() — TypeError
  • PUT /api/security/loadbalancer: same issue — tuple assigned to variable then .lower() called on it — AttributeError

Load Balancer config corruption bug

The server-parsing regex also matched the virtual host's server { block declaration, adding a phantom {address:'{'} upstream entry. On re-save this wrote server { weight=1; into the nginx config before testing it — if nginx -t failed, the broken config stayed on disk. A future server restart would break nginx (all sites down). Fixed regex + made saves atomic (backup existing config, write new, test, rollback on failure).

phpMyAdmin php_version save always failing

phpMyAdmin's PHP-version dropdown checked /usr/bin/php{v} (CLI binary), but only php{v}-fpm may be installed — leaving the dropdown empty, currentPhp='', and Save always failing with "Config not found or PHP version missing". Fixed to check /run/php/php{v}-fpm.sock instead.

PHP 8.5 FPM socket permission denied (502 Bad Gateway)

php_install_script() in os_utils.py never aligned new PHP-FPM pool listen.owner/listen.group with nginx's actual worker user. Package defaults (www-data on Debian) didn't match a server running nginx as user nginx, causing 502 for every site on that PHP version. Fixed for both Debian and RHEL-family.

phpMyAdmin link opening on localhost

Databases page button hardcoded href="http://localhost:8082" — clicking from a browser opened port 8082 on the user's own machine, not the VPS. Fixed to use location.hostname.

bandwidth.py — vnstat install broken on RHEL-family

/api/bandwidth/install-vnstat hardcoded apt-get install -y vnstat, non-functional on all RHEL-family distros. Fixed to use pkg_install() + EPEL enablement.

Roundcube PHP version switcher never worked

Frontend posted {action:'set_php'} but save_module_settings() had no set_php handler — always returned Unknown action. Added the missing handler.

DDNS Manager Uninstall button

DDNS Manager's check command is echo found (it's a built-in feature). The Uninstall button ran apt-get remove ddclient (unrelated package) and the check still reported "found" — appearing as if uninstall silently failed. Added builtin:True flag, threaded through the API, hidden the Uninstall button for built-in modules.

Websites refactor (websites.py 1266-line → 8 modules)

Split monolithic websites.py into 8 focused modules. Added ensure_web_ownership() in websites_core.py to fix wp-config.php write-permission failures on new site creation.


⚡ Performance & UX

  • Gzip compression via Flask-Compress: app.js 150KB → ~40KB, index.html 350KB → ~70KB over the wire
  • /api/modules response cached (30s TTL) — App Store page loads instantly on revisit; cache invalidated on install/uninstall
  • Modal positioning fixed — WP Toolkit and other modals now use .modal-overlay CSS class instead of inline position:fixed, which was getting trapped by Alpine's stacking context
  • Dashboard services list expanded — now includes all PHP-FPM versions, fail2ban, supervisor

Upgrading

cd /your/vortexpanel/source
git pull
cp -r panel/ web/ app.py /opt/vortexpanel/
pip install -r requirements.txt  # adds flask-compress
systemctl restart vortexpanel

Or fresh install:

wget -O install.sh https://raw.githubusercontent.com/BrowserlessAPI/VortexPanel/main/install.sh && bash install.sh

What's next (v3.2 roadmap)

  • Per-site website analytics (nginx access log → traffic/top-URIs/status-codes dashboard)
  • Alerting — CPU/RAM/SSL-expiry push notifications (Telegram/Discord/email/webhook)
  • Disk usage analyzer
  • Multi-user / RBAC
  • LB node health checks