feat: dedicated ports per panel tier (8880/8881/8882)

Each panel now has its own dedicated port and is fully self-contained:
- Port 8880: User panel (end-user hosting dashboard)
- Port 8881: Reseller panel (account/package management)
- Port 8882: Admin panel (datacenter/server manager)

Changes:
- install.sh: PORT_USER/PORT_RESELLER/PORT_ADMIN constants; three separate
  nginx/Apache vhosts; UFW opens all three ports; Fail2Ban jail per port;
  credentials file shows all three URLs
- config.ini: stores port_user/port_reseller/port_admin
- Core.php: defines PORT_USER/RESELLER/ADMIN, detects CURRENT_PORTAL from
  SERVER_PORT so the API knows which tier is being accessed
- Auth.php: portalUrl() maps role → correct port for cross-portal redirects
- auth.php endpoint: returns portal_url on login so JS redirects to right port
- index.php login: uses portal_url from API response (no hardcoded paths)
- admin/index.php: inline login form (port 8882 is self-contained, no redirect)
- user/index.php: inline login form (port 8880 self-contained)
- reseller/index.php: new full reseller panel with inline login (port 8881);
  sidebar with accounts, packages, DNS, branding, bandwidth report sections

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 05:35:48 +00:00
parent e94dc719c8
commit 716d292e77
9 changed files with 467 additions and 55 deletions
+15
View File
@@ -97,4 +97,19 @@ class Auth {
Response::error('Forbidden', 403);
}
}
/**
* Returns the correct panel URL for a given role
* Used by login redirect so each role lands on the right port
*/
public static function portalUrl(string $role, string $path = '/'): string {
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
$hostname = preg_replace('/:\d+$/', '', $host);
$port = match($role) {
'admin' => PORT_ADMIN,
'reseller' => PORT_RESELLER,
default => PORT_USER,
};
return "https://{$hostname}:{$port}{$path}";
}
}
+18 -8
View File
@@ -13,14 +13,24 @@ if (!$_cfg) {
die(json_encode(['error' => 'NovaCPX not configured. Run the installer.']));
}
define('DB_HOST', $_cfg['database']['host'] ?? 'localhost');
define('DB_NAME', $_cfg['database']['name'] ?? 'novacpx');
define('DB_USER', $_cfg['database']['user'] ?? '');
define('DB_PASS', $_cfg['database']['pass'] ?? '');
define('SECRET_KEY', $_cfg['panel']['secret'] ?? '');
define('PANEL_VER', $_cfg['panel']['version'] ?? NOVACPX_VERSION);
define('WEB_SERVER', $_cfg['web']['server'] ?? 'apache');
define('PHP_DEFAULT',$_cfg['web']['php_default'] ?? '8.3');
define('DB_HOST', $_cfg['database']['host'] ?? 'localhost');
define('DB_NAME', $_cfg['database']['name'] ?? 'novacpx');
define('DB_USER', $_cfg['database']['user'] ?? '');
define('DB_PASS', $_cfg['database']['pass'] ?? '');
define('SECRET_KEY', $_cfg['panel']['secret'] ?? '');
define('PANEL_VER', $_cfg['panel']['version'] ?? NOVACPX_VERSION);
define('PORT_USER', (int)($_cfg['panel']['port_user'] ?? 8880));
define('PORT_RESELLER', (int)($_cfg['panel']['port_reseller'] ?? 8881));
define('PORT_ADMIN', (int)($_cfg['panel']['port_admin'] ?? 8882));
define('WEB_SERVER', $_cfg['web']['server'] ?? 'apache');
define('PHP_DEFAULT', $_cfg['web']['php_default'] ?? '8.3');
// Detect which portal is being accessed by the request port
$requestPort = (int)($_SERVER['SERVER_PORT'] ?? 0);
define('CURRENT_PORTAL',
$requestPort === PORT_ADMIN ? 'admin' :
($requestPort === PORT_RESELLER ? 'reseller' : 'user')
);
function novacpx_log(string $level, string $msg, array $ctx = []): void {
$line = sprintf("[%s] [%s] %s %s\n",