Dashboard

Monitor & control your XAMPP services

Apache
Idle
Port 80/443
MariaDB
Idle
Port 3306
Runners
0
Active
Total Actions
0
This session
Apache HTTP Server
Local web server
Idle
MariaDB Database
Database engine
Idle

Activity Log

[ System ] Ready to receive commands...
MariaDB Terminal — root@localhost
-- Meta Panel MySQL Terminal v3.0 (FIXED)
-- FIX: Queries auto-prefixed with USE <db> if database selected
-- Use "use db_name" to select database
-- Use "use none" to return without database
-- History navigation: Arrow Up / Arrow Down
-----------------------------------------------------------
MariaDB [(none)]>

Quick Queries

Query History

No queries yet...

Apache HTTP Server

Local web server — port 80 & 443

Idle
httpd.exe

MariaDB Database

SQL database engine — port 3306

Idle
mysqld.exe

Console Output

[ System ] Ready to receive service commands...

Project Runner

Run Laravel & PHP projects from your browser. Data is auto-saved.

No projects running yet

Link Notifier

Save important links & paths — synced to Database

API Key Management

Generate & manage API keys to secure your web.js

How it works: Each API key is generated for your user account. Add the key to your web.js so only your Meta Panel can access the API. Keys are auto-saved and validated per request.

Implementation in web.js

// Add this at the top of web.js after const http = require('http')
const VALID_API_KEYS = new Set([
  /* paste key here */
]);

// Inside createServer, add validation:
const reqKey = req.headers['x-api-key'];
if (!VALID_API_KEYS.has(reqKey)) {
  res.writeHead(401, {'Content-Type': 'application/json'});
  res.end(JSON.stringify({error:'Invalid API key'}));
  return;
}
Important: After adding the key to web.js, restart the server with node web.js. Meta Panel will automatically send the X-API-Key header on every request.

No API keys yet

Click "Generate New Key" to create one

Public Chat

Global chat room — visible to all users

Online

Installation & Setup

Steps to prepare your environment before using Meta Panel API.

1

Install XAMPP

Download XAMPP from Apache Friends. Make sure Apache and MariaDB are installed.

Path Note: This tutorial assumes XAMPP is in C:\xampp. Adjust XAMPP_PATH if different.
2

Install Node.js

Download Node.js LTS from nodejs.org.

node --version
npm --version
3

Create web.js File

Create a working folder, create a web.js file, and copy the code from the Source Code page.

4

Verify

After running node web.js, open http://localhost:8080/api/start-apache. If you see JSON output, installation is successful.

web.js Source Code

Copy this entire code into your web.js file.

Important: Adjust XAMPP_PATH to match your XAMPP installation location.
const { exec } = require('child_process');
const http = require('http');
const XAMPP_PATH = 'C:\\xampp';

const runBg = (cmd, msg) => {
  exec(`cmd /c "${cmd}"`, (err) => {
    if (err) console.error(`[ERROR] ${err.message}`);
    else console.log(`[OK] ${msg}`);
  });
};

const execStart = (cmd, msg, res) => {
  exec(`cmd /c "${cmd}"`, (err) => {
    if (err) res.end(JSON.stringify({ success: false, message: err.message }));
    else res.end(JSON.stringify({ success: true, message: msg }));
  });
};

const execStop = (cmd, msg, res) => {
  exec(cmd, () => res.end(JSON.stringify({ success: true, message: msg })));
};

const execStream = (cmd, res) => {
  const child = exec(cmd, { maxBuffer: 50*1024*1024 });
  res.setHeader('Content-Type', 'text/plain; charset=utf-8');
  res.setHeader('Transfer-Encoding', 'chunked');
  child.stdout.on('data', (d) => res.write(d));
  child.stderr.on('data', (d) => res.write(d));
  child.on('close', () => res.end());
  child.on('error', (e) => { res.write('Error: '+e.message); res.end(); });
  return child;
};

const server = http.createServer((req, res) => {
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Headers', '*');
  if (req.method === 'OPTIONS') { res.writeHead(200); res.end(); return; }
  const url = req.url;

  if (url === '/api/start-apache')  execStart(`${XAMPP_PATH}\\apache_start.bat`, 'Apache Started', res);
  else if (url === '/api/stop-apache')   execStop('taskkill /F /IM httpd.exe /T', 'Apache Force Stopped', res);
  else if (url === '/api/start-mysql')    execStart(`${XAMPP_PATH}\\mysql_start.bat`, 'MySQL Started', res);
  else if (url === '/api/stop-mysql')     execStop('taskkill /F /IM mysqld.exe /T', 'MySQL Force Stopped', res);

  else if (url.startsWith('/api/mysql-query?')) {
    let q = decodeURIComponent(url.split('query=')[1]);
    const blocked = 'GRANT,REVOKE,SHUTDOWN,LOAD_FILE,INTO OUTFILE'.split(',');
    if (blocked.some(b => q.toUpperCase().includes(b.trim()))) {
      res.end(JSON.stringify({success:false,message:'Command blocked.'})); return;
    }
    exec(`"${XAMPP_PATH}\\mysql\\bin\\mysql.exe" -u root -e "${q.replace(/"/g, '\\"')}"`,
      {maxBuffer:10*1024*1024}, (err,stdout,stderr) => {
        if (err && !stdout) res.end(JSON.stringify({success:false,message:stderr||err.message}));
        else res.end(JSON.stringify({success:true,result:(stdout||'').trim()}));
      });
  }

  else if (url.startsWith('/api/run-stream?')) {
    let params = new URL(`http://localhost${url}`).searchParams;
    let cmd = params.get('cmd');
    if (cmd) execStream(cmd, res);
    else res.end(JSON.stringify({error:'Missing cmd'}));
  }

  else if (url.startsWith('/api/run?')) {
    let params = new URL(`http://localhost${url}`).searchParams;
    let cmd = params.get('cmd');
    if (cmd) exec(cmd,{maxBuffer:50*1024*1024,timeout:30000},(err,stdout,stderr)=>{
      res.end(JSON.stringify({success:!err,result:(stdout||'').trim(),error:stderr||''}));
    });
    else res.end(JSON.stringify({error:'Missing cmd'}));
  }

  else if (url.startsWith('/api/kill-stream?')) {
    let params = new URL(`http://localhost${url}`).searchParams;
    let pid = params.get('pid');
    if (pid) exec(`taskkill /F /PID ${pid} /T`,()=>res.end(JSON.stringify({success:true})));
    else res.end(JSON.stringify({error:'Missing pid'}));
  }

  else res.end(JSON.stringify({error:'Endpoint not found'}));
});

server.listen(8080, () => {
  console.log(`Meta Panel API on http://localhost:8080`);
  runBg(`${XAMPP_PATH}\\apache_start.bat`, 'Apache started');
  runBg(`${XAMPP_PATH}\\mysql_start.bat`, 'MariaDB started');
});

process.on('SIGINT', () => {
  exec('taskkill /F /IM httpd.exe /T', () =>
    exec('taskkill /F /IM mysqld.exe /T', () => process.exit(0)));
});

How to Run the Server

Operational guide for Meta Panel API.

A

Starting the Server

Open CMD/PowerShell, navigate to your web.js folder:

cd C:\web
node web.js
Auto-Start: Apache & MariaDB will automatically start when the script is run.

Stopping the Server

Press Ctrl+C in the terminal. Do not close using the X button.

API Endpoints Reference

All available endpoints.

Method Endpoint Description
GET /api/start-apache Start Apache
GET /api/stop-apache Stop Apache
GET /api/start-mysql Start MariaDB
GET /api/stop-mysql Stop MariaDB
GET /api/mysql-query?query=... Execute SQL query
GET /api/run-stream?cmd=... Streaming command execution
GET /api/run?cmd=... Execute command (JSON)
GET /api/kill-stream?pid=... Kill streaming process

Fetch Implementation Examples

Examples of API integration into your web UI.

// Service control
async function control(endpoint) {
  const r = await fetch(`http://localhost:8080${endpoint}`);
  const d = await r.json();
  console.log(d.success ? d.message : 'Error: '+d.message);
}

// MySQL query (auto-prefixed with USE db if database selected)
async function query(sql, dbName) {
  let fullSql = dbName ? `USE \`${dbName}\`; ${sql}` : sql;
  const r = await fetch(`http://localhost:8080/api/mysql-query?query=${encodeURIComponent(fullSql)}`);
  const d = await r.json();
  if (d.success) console.log(d.result);
  else console.error(d.message);
}

// Streaming (Laravel/PHP)
async function runStream(cmd) {
  const r = await fetch(`http://localhost:8080/api/run-stream?cmd=${encodeURIComponent(cmd)}`);
  const reader = r.body.getReader();
  const decoder = new TextDecoder();
  while (true) {
    const {done, value} = await reader.read();
    if (done) break;
    process.stdout.write(decoder.decode(value));
  }
}

Troubleshooting

Common issues and their solutions.

ERR_CONNECTION_REFUSED

Solution: Make sure node web.js is running in a terminal.

"No database selected"

Solution: Type use database_name in the MySQL terminal. The latest version auto-prefixes USE.

Port 8080 Already in Use

Solution: Change const PORT = 8080 to another port.

Database Login Failed

Solution: Make sure popups are not blocked by your browser. Try incognito mode.

API Key 401 Unauthorized

Solution: Make sure the API key in web.js matches the one on the API Keys page. Keys are case-sensitive.