1, 'out' => 'N/A'];
// Timeout wrapper (Linux 'timeout' if available)
$timeout_bin = trim(shell_exec('command -v timeout 2>/dev/null')) ?: '';
$safe = $timeout_bin ? escapeshellcmd($timeout_bin) . " " . intval($timeout) . "s " . $cmd : $cmd;
$out = [];
$code = 0;
@exec($safe . ' 2>&1', $out, $code);
return ['code' => $code, 'out' => implode("\n", $out)];
}
function human_bytes($bytes) {
$u = ['B','KB','MB','GB','TB','PB'];
$i = 0;
while ($bytes >= 1024 && $i < count($u)-1) { $bytes /= 1024; $i++; }
return sprintf('%.1f %s', $bytes, $u[$i]);
}
function status_badge($status) {
$s = strtolower(trim($status));
if (in_array($s, ['online','active','up','running','listening'])) return ['success','Online'];
if (in_array($s, ['stopped','inactive','exited'])) return ['secondary','Stopped'];
if (in_array($s, ['errored','failed','dead'])) return ['danger','Error'];
if (in_array($s, ['unknown','n/a','not found'])) return ['dark','Unknown'];
return ['warning', ucfirst($status ?: 'Unknown')];
}
function parse_pm2() {
// Prefer JSON output
$res = run_cmd('pm2 jlist');
if ($res['code'] === 0 && strlen($res['out']) > 2) {
$json = json_decode($res['out'], true);
if (is_array($json)) return $json;
}
// Fallback: pm2 status tabular (parse minimally)
$res2 = run_cmd('pm2 list --no-color');
$apps = [];
if ($res2['code'] === 0) {
$lines = explode("\n", $res2['out']);
foreach ($lines as $ln) {
if (preg_match('/^\s*\|\s*(\S+)\s*\|\s*(\d+)\s*\|\s*([A-Z]+)\s*\|\s*(\d+)\s*\|\s*([\dms:\.]+)\s*\|\s*(\S*)/i', $ln, $m)) {
$apps[] = [
'name' => $m[1],
'pm_id' => $m[2],
'status' => strtolower($m[3]),
'cpu' => null,
'mem' => null,
'uptime' => $m[5],
'mode' => $m[6] ?? ''
];
}
}
}
return $apps;
}
function get_cpu_info() {
$model = trim(run_cmd("awk -F': ' '/model name/ {print \$2; exit}' /proc/cpuinfo")['out']);
$cores_p = intval(trim(run_cmd("getconf _NPROCESSORS_ONLN")['out'])) ?: 0;
$loadavg = trim(run_cmd("cut -d' ' -f1-3 /proc/loadavg")['out']);
return [$model ?: 'N/A', $cores_p, $loadavg ?: 'N/A'];
}
function get_mem_info() {
// /proc/meminfo (bytes -> kB)
$mem_total_kb = intval(trim(run_cmd("awk '/MemTotal/ {print \$2}' /proc/meminfo")['out']));
$mem_avail_kb = intval(trim(run_cmd("awk '/MemAvailable/ {print \$2}' /proc/meminfo")['out']));
$mem_used_kb = max(0, $mem_total_kb - $mem_avail_kb);
return [
'total' => human_bytes($mem_total_kb * 1024),
'used' => human_bytes($mem_used_kb * 1024),
'free' => human_bytes($mem_avail_kb * 1024),
'pct' => $mem_total_kb ? round(($mem_used_kb / $mem_total_kb) * 100) : 0
];
}
function get_disk_info() {
$res = run_cmd("df -h --output=target,size,used,avail,pcent -x tmpfs -x devtmpfs");
$rows = [];
if ($res['code'] === 0) {
$lines = explode("\n", trim($res['out']));
foreach (array_slice($lines, 1) as $l) {
$l = preg_replace('/\s+/', ' ', trim($l));
if (!$l) continue;
[$mount, $size, $used, $avail, $pct] = array_pad(explode(' ', $l), 5, '');
$rows[] = compact('mount','size','used','avail','pct');
}
}
return $rows;
}
function get_gpu_info() {
$nvsmi = trim(run_cmd('command -v nvidia-smi')['out']);
if (!$nvsmi) return [];
$q = '--query-gpu=name,driver_version,pstate,temperature.gpu,memory.total,memory.used,pcie.link.gen.current,pcie.link.width.current --format=csv,noheader';
$res = run_cmd("nvidia-smi $q", 4);
$out = [];
if ($res['code'] === 0) {
foreach (explode("\n", trim($res['out'])) as $line) {
if (!$line) continue;
$parts = array_map('trim', explode(',', $line));
$out[] = [
'name' => $parts[0] ?? 'NVIDIA GPU',
'driver' => $parts[1] ?? 'N/A',
'pstate' => $parts[2] ?? 'N/A',
'tempC' => $parts[3] ?? 'N/A',
'mem_total' => $parts[4] ?? 'N/A',
'mem_used' => $parts[5] ?? 'N/A',
'pcie_gen' => $parts[6] ?? 'N/A',
'pcie_w' => $parts[7] ?? 'N/A',
];
}
}
return $out;
}
function get_network_info() {
$hostname = trim(run_cmd('hostname')['out']);
$ips = trim(run_cmd("hostname -I")['out']);
$gateway = trim(run_cmd("ip route | awk '/default/ {print \$3; exit}'")['out']);
return [$hostname ?: 'N/A', $ips ?: 'N/A', $gateway ?: 'N/A'];
}
function get_os_info() {
$pretty = trim(run_cmd("awk -F'=' '/^PRETTY_NAME/{gsub(/\"/ ,\"\",\$2); print \$2}' /etc/os-release")['out']);
$kernel = trim(run_cmd('uname -r')['out']);
$arch = trim(run_cmd('uname -m')['out']);
$uptime = trim(run_cmd('uptime -p')['out']);
$boot = trim(run_cmd('who -b | awk \'{print $3, $4}\'')['out']);
$phpv = PHP_VERSION;
$nginx = trim(run_cmd('nginx -v 2>&1')['out']);
$nginx = $nginx ?: 'nginx not found';
return [$pretty ?: 'Linux', $kernel ?: 'N/A', $arch ?: 'N/A', $uptime ?: 'N/A', $boot ?: 'N/A', $phpv, $nginx];
}
function get_services_status($services = ['nginx','php-fpm','pm2']) {
$data = [];
foreach ($services as $svc) {
$cmd = "systemctl is-active $svc";
$r = run_cmd($cmd);
$status = $r['code'] === 0 ? trim($r['out']) : 'unknown';
$data[] = ['name' => $svc, 'status' => $status];
}
return $data;
}
function get_top_procs($limit = 8) {
$r = run_cmd("ps -eo pid,comm,%cpu,%mem --sort=-%cpu | head -n " . intval($limit + 1));
$rows = [];
if ($r['code'] === 0) {
$lines = explode("\n", trim($r['out']));
foreach (array_slice($lines, 1) as $ln) {
$ln = preg_replace('/\s+/', ' ', trim($ln));
if (!$ln) continue;
[$pid,$comm,$cpu,$mem] = array_pad(explode(' ', $ln), 4, '');
$rows[] = compact('pid','comm','cpu','mem');
}
}
return $rows;
}
function get_log_tail($path, $lines = 80) {
if (!is_readable($path)) return "Log not found or unreadable: $path";
$r = run_cmd("tail -n " . intval($lines) . " " . escapeshellarg($path));
return $r['code'] === 0 ? $r['out'] : "Unable to read log.";
}
// ---------- Page Settings ----------
$auto_refresh = isset($_GET['autorefresh']) ? (int)$_GET['autorefresh'] : 0;
$refresh_secs = ($auto_refresh > 0 && $auto_refresh <= 600) ? $auto_refresh : 0;
$custom_log = isset($_GET['log']) ? $_GET['log'] : '';
$log_path = $custom_log ?: '/var/log/nginx/access.log';
// ---------- Data ----------
[$os_name,$kernel,$arch,$uptime,$booted,$phpv,$nginxv] = get_os_info();
[$hostname,$ips,$gw] = get_network_info();
[$cpu_model,$cores,$load] = get_cpu_info();
$mem = get_mem_info();
$disks = get_disk_info();
$gpus = get_gpu_info();
$pm2 = parse_pm2();
$services = get_services_status(['nginx','php-fpm','pm2']);
$procs = get_top_procs(8);
$log_tail = get_log_tail($log_path, 100);
?>
🖥️ GhostAI Server Dashboard
Skip to content
💻System Overview
Host: = htmlspecialchars($hostname) ?>
= htmlspecialchars($os_name) ?> • Kernel = htmlspecialchars($kernel) ?> • = htmlspecialchars($arch) ?>
Uptime: = htmlspecialchars($uptime) ?> • Boot: = htmlspecialchars($booted) ?>
PHP: = htmlspecialchars($phpv) ?> • = htmlspecialchars($nginxv) ?>
IP(s): = htmlspecialchars($ips) ?> • GW: = htmlspecialchars($gw) ?>
🧠CPU
Model
= htmlspecialchars($cpu_model) ?>
Cores: = intval($cores) ?>
Load: = htmlspecialchars($load) ?>
📈Memory
Usage
= htmlspecialchars($mem['used']) ?> / = htmlspecialchars($mem['total']) ?>
Free: = htmlspecialchars($mem['free']) ?> (= intval($mem['pct']) ?>%)
🎮GPU
| Name | Driver | Temp | VRAM | PCIe | P-State |
| = htmlspecialchars($g['name']) ?> |
= htmlspecialchars($g['driver']) ?> |
= htmlspecialchars($g['tempC']) ?> |
= htmlspecialchars($g['mem_used']) ?> / = htmlspecialchars($g['mem_total']) ?> |
Gen = htmlspecialchars($g['pcie_gen']) ?> ×= htmlspecialchars($g['pcie_w']) ?> |
= htmlspecialchars($g['pstate']) ?> |
No NVIDIA GPU info (nvidia-smi not found or no GPU).
🗄️Disks
| Mount | Size | Used | Avail | Use% |
| = htmlspecialchars($d['mount']) ?> |
= htmlspecialchars($d['size']) ?> |
= htmlspecialchars($d['used']) ?> |
= htmlspecialchars($d['avail']) ?> |
= htmlspecialchars($d['pct']) ?> |
🧩Services
= htmlspecialchars($s['name']) ?>: = htmlspecialchars($b[1]) ?>
📊Top Processes (CPU)
| PID | Command | CPU% | MEM% |
| = htmlspecialchars($p['pid']) ?> |
= htmlspecialchars($p['comm']) ?> |
= htmlspecialchars($p['cpu']) ?> |
= htmlspecialchars($p['mem']) ?> |
🎛️PM2 Apps
0))): ?>
| Name | ID | Status | Mode | CPU | Mem | Uptime |
".htmlspecialchars($name)." |
".htmlspecialchars($pm_id)." |
".htmlspecialchars($b[1])." |
".htmlspecialchars($mode)." |
".($cpu !== null ? htmlspecialchars($cpu).'%' : 'N/A')." |
".htmlspecialchars($memh)." |
".htmlspecialchars($upt_h)." |
";
}
} else {
foreach ($pm2 as $app) {
$b = status_badge($app['status'] ?? 'unknown');
echo "
| ".htmlspecialchars($app['name'] ?? 'app')." |
".htmlspecialchars($app['pm_id'] ?? '')." |
".htmlspecialchars($b[1])." |
".htmlspecialchars($app['mode'] ?? '')." |
".htmlspecialchars($app['cpu'] ?? 'N/A')." |
".htmlspecialchars($app['mem'] ?? 'N/A')." |
".htmlspecialchars($app['uptime'] ?? 'N/A')." |
";
}
}
?>
PM2 not detected or no apps configured.
🪵Logs
= htmlspecialchars($log_tail) ?>