M
MangoPanel DOCS
Home Docs
Overview

Introduction

MangoPanel is a lightweight, self-hosted, hPanel-style shared hosting control panel. It provides a complete web hosting control plane designed for real account stacks, queued jobs, DNS management, SSL certificates, email services, databases, file managers, and backups.

Core Philosophy

MangoPanel uses a zero-external-framework Python HTTP API backed by SQLite WAL mode. Desired infrastructure state is written to SQLite, while a dedicated local Node Agent processes privileged operations asynchronously.

Key Platform Highlights

  • Account Isolation: One dedicated Docker Compose stack per customer account (OpenLiteSpeed, MariaDB, phpMyAdmin, Filebrowser, SFTP, Mail).
  • Audited Control Plane: Single SQLite database (`mangopanel.sqlite3`) tracking users, websites, databases, mailboxes, and job logs.
  • Built-in Security: Signed JWT session tokens, mandatory TOTP multi-factor authentication, and short-lived launch tokens for sub-services.
  • Dual-Port Panel Architecture: Separate listening ports for Client (`8000`) and Admin (`8001`) to isolate administrative API routes.
Prerequisites

Requirements

Before installing MangoPanel, ensure your server or development environment satisfies the following system specifications:

Component Minimum Requirement Recommended
Operating System Linux (Ubuntu 22.04 / 24.04 LTS, Debian 12) or macOS Ubuntu 24.04 LTS Server
Python Python 3.10+ Python 3.12+
Container Engine Docker Engine 24.0+ & Docker Compose v2 Docker Engine 26.0+
System Tools `git`, `make`, `curl`, `tar`, `sqlite3` `git`, `make`, `curl`, `rsync`
Network Ports `8000` (Client), `8001` (Admin) Public IPs for 80, 443, 53 (DNS), 587 (SMTP), 993 (IMAP)
Setup

Installation

Choose one of the following methods to install MangoPanel on your host system.

Option A: Automated One-Line Install (Recommended)

Fresh clone and auto-installation using `git`:

git clone https://github.com/servermango/MangoPanel.git MangoPanel && cd MangoPanel && bash scripts/install.sh

Option B: Archive Install (If Git is unavailable)

mkdir MangoPanel && curl -fsSL https://codeload.github.com/servermango/MangoPanel/tar.gz/refs/heads/main | tar -xz -C MangoPanel --strip-components=1 && cd MangoPanel && bash scripts/install.sh

Option C: Manual Makefile Step-by-Step

cd MangoPanel

# 1. Install system prerequisites, Python venv, Docker tools & pre-pull images
make install

# 2. Check Python, Docker, and listening ports
make dev-init

# 3. Start the client and admin panel services (seeds dev data on first run)
make dev-up
Getting Started

Quick Start

Once installation finishes, MangoPanel runs as a local background daemon or development server.

Interface URL Default Credentials
Client Portal `http://127.0.0.1:8000/` `[email protected]` / `ChangeMe-DevOnly-123!`
Admin Panel `http://127.0.0.1:8001/admin` `[email protected]` / `ChangeMe-DevOnly-123!`
Client Signup `http://127.0.0.1:8000/signup` Self-service client registration
System Status `http://127.0.0.1:8000/status` Public platform feature state page
Development 2FA Code

In development mode (`MP_DEV_AUTH_TEST_MODE=true`), the universal TOTP verification code is 000000.

Guide

Basic Setup

Follow these steps to configure your initial administrative credentials, define hosting plans, and provision your first customer accounts.

1. Admin Setup & Recovery

When starting MangoPanel on a fresh database with zero admins, visiting `http://:8001/admin` automatically routes to the First-Admin Setup Page (`/admin/setup`).

  • Fill in the admin email address and password.
  • The system generates an initial TOTP authenticator secret and displays an `otpauth://` QR code.
  • Scan the QR code in Google Authenticator / 1Password and verify a code before completing setup.
  • Once an admin exists, public first-admin setup is permanently locked.

CLI Admin Recovery Tool

If an administrator loses password or 2FA access, run `scripts/admin_recovery.py` directly on the server host:

# Reset admin password
sudo python3 scripts/admin_recovery.py --email [email protected] --set-password

# Generate new TOTP secret & display QR setup URI
sudo python3 scripts/admin_recovery.py --email [email protected] --enable-totp

# Disable TOTP requirement for emergency login
sudo python3 scripts/admin_recovery.py --email [email protected] --disable-totp

2. Creating Hosting Plans

Before customer accounts can be provisioned, define at least one active Hosting Plan in the Admin Panel under Plans (`/admin#plans`).

Plan Field Description Example Value
Name & Slug Human readable label and identifier `Starter Plan` (`starter`)
CPU & RAM Limit Per-account container execution limits `1.0 CPU` / `512 MB RAM`
Storage & Inodes Disk quota in MB and file count limit `10000 MB` / `250000 inodes`
Website Count Maximum allowed hosted domains `5 websites`
Databases & Mailboxes Max MySQL/PostgreSQL DBs and email accounts `5 DBs` / `10 mailboxes`
DNS Policy DNS provider selection (Local PowerDNS / Cloudflare) `Cloudflare Managed`

3. Provisioning Customer Clients

Customer accounts can be created through two primary workflows:

Workflow A: Self-Service Signup Page (`/signup`)

  1. User visits `http://:8000/signup`.
  2. Enters email, password, and selects an available hosting plan.
  3. API executes `POST /api/public/signup`, generates customer credentials, sets up 2FA, and assigns an account ID (e.g., `u000001`).

Workflow B: Admin Dashboard Provisioning

  1. Admin opens Admin Panel > Clients.
  2. Clicks Create Client Account.
  3. Enters user email, password, and selects the hosting plan.
  4. The system creates the user, generates account directory structure under `user_files/accounts//`, and queues container deployment.
DNS Integration

Cloudflare as DNS - Setup Instructions

MangoPanel supports Cloudflare as an authoritative DNS provider for managed domains. Configure Cloudflare credentials in the Admin panel under DNS Settings.

Cloudflare API Prerequisites

  • Account ID: Found in the right sidebar of the Cloudflare Dashboard on any domain's Overview page.
  • API Token: Generated under My Profile > API Tokens in Cloudflare.
Required Token Permissions

The Cloudflare API Token must include these explicit permissions:
• Zone > Zone > Edit (or Zone:Read for zone verification)
• Zone > DNS > Edit (for managing DNS records)
• Zone > Page Rules > Edit (Required: allows MangoPanel to automatically create ACME HTTP-01 challenge bypass rules for SSL Auto-Issuance on Cloudflare-proxied domains)

Automated ACME Challenge Page Rules

When a website is added or connected to MangoPanel using Cloudflare DNS, MangoPanel automatically creates a Cloudflare Page Rule targeting http://*example.com/.well-known/acme-challenge/* with action always_use_https: off. This prevents Cloudflare from redirecting Let's Encrypt HTTP ACME challenges to HTTPS port 443 before Caddy has issued an SSL certificate, eliminating HTTP 525 (SSL Handshake Failed) deadlocks.

Syncing Existing Websites

To add missing Cloudflare Page Rules to existing websites, you can use any of the following methods:

  • API Endpoint (Client Area): POST /api/client/dns/sync-cloudflare-rules
  • API Endpoint (Admin Area): POST /api/admin/dns/sync-cloudflare-rules
  • CLI Script: Run python scripts/sync_cloudflare_rules.py on your server
DNS Routing

Domain & Subdomain DNS Setup

To instruct users to set up a server domain or subdomain for MangoPanel and tool access, create DNS A-records pointing to your server's IP address.

Domain Setup Example

For example, if you want your users to reach the panel from hosting.servermango.com, create the following DNS A-records pointing to your server's public IP address:

Type Name / Host Target / Value Purpose
A hosting.servermango.com (or @) <SERVER_IP> Main panel and web traffic
A *.files.hosting.servermango.com (or *.files) <SERVER_IP> Per-account Filebrowser tool subdomain routing

Once configured, access MangoPanel at:

  • Admin Panel: http://hosting.servermango.com:8001/admin
  • Client Panel: http://hosting.servermango.com:8000/client (or http://hosting.servermango.com:8000/)
Architecture

Current Build Features

  • Python standard-library HTTP API with zero framework overhead.
  • SQLite WAL-mode schema with versioned development seed data.
  • Public client signup (`/signup`), client portal (`/`), admin panel (`/admin`), and status page (`/status`).
  • Full coverage for websites, MySQL, PostgreSQL, mailboxes, SFTP, cron jobs, backups, Git deployments, and audit logs.
  • Node-agent job runner with simulated and Docker Compose execution modes.
  • Account-stack generator for OpenLiteSpeed, Filebrowser, phpMyAdmin, MariaDB, cron, SFTP, and shared mail scaffolding.
CLI Tooling

Service Command

MangoPanel includes a portable service wrapper at scripts/service that manages background panel processes and agent workers without requiring `systemd`:

# Service lifecycle management
bash scripts/service mangopanel start
bash scripts/service mangopanel status
bash scripts/service mangopanel restart
bash scripts/service mangopanel stop

# Makefile wrapper equivalent
make service ACTION=start
make service ACTION=status
Production startup

On a production server, run the systemd service so the panel uses Docker mode and asynchronous agent jobs. This does not delete website content:

cd /root/MangoPanel
sudo systemctl start mangopanel.service
sudo systemctl status mangopanel.service --no-pager

# The service must define:
# MP_ENV=production
# MP_AGENT_MODE=docker

Do not start a second manual python -m mangopanel.app process on ports 8000/8001.

Internals

How It Works

Request flow in one line:

Browser → Panel API (writes SQLite + enqueues job) → Local Agent (provisions files & containers) → Status reported back to SQLite → UI displays result

Filesystem

Data Layout

All persistent control-plane state and customer hosting data lives under user_files/:

user_files/
  accounts/                 # per-customer hosting files  (MP_ACCOUNT_ROOT)
    u000001/
      account.json
      domains/<domain>/public_html/
      databases/  mail/  backups/  ssl/  git/  .runtime/
  data/                     # control-plane database       (MP_DATA_DIR)
    mangopanel.sqlite3
Maintenance

Server Migration

Because all database state and customer files live inside `user_files/`, migration to a new server takes 5 simple steps:

  1. Stop Services: bash scripts/service mangopanel stop on old server.
  2. Install on New Server: Run installation script on destination machine.
  3. Transfer `user_files/`: rsync -avzP /path/to/old/user_files/ root@new-server:/path/to/new/user_files/
  4. Start Services & Provision Stacks: bash scripts/service mangopanel start & run agent stack rebuild.
  5. Update DNS: Point A-records to the new server IP.
Developer

Local & Docker Development

# Start lightweight dev server (Simulated Mode)
make dev-up

# Start full Docker hosting stack (OpenLiteSpeed, MariaDB, SFTP containers)
make dev-up-docker

# Run unit tests
make test

# Run API smoke test suite
make dev-smoke
Research

Thesis Integration Direction

MangoPanel is evaluated as a case study for Tariq Abdullah's Cloud Definition Language (CDL) M.Tech thesis research, exploring how shared-hosting platform intent can be compiled into explainable infrastructure artifacts.

Roadmap

Implementation Roadmap

  • Phase 1 (Implemented): Shared interfaces and control-plane schema.
  • Phase 2 (Implemented): Local PowerDNS adapter, ACME provider, and mail edge scaffolding.
  • Phase 3 (Implemented): Hardening, auth validation, and client dashboard metrics integration.
Developer API

Client Area API Reference & Parameters

MangoPanel provides a clean REST API for managing websites, DNS records, databases, mailboxes, cron jobs, files, SSL, and monitoring resource usage using API keys or Bearer JWT tokens.

1. API Key Guide — Client Panel

How to Generate a Client API Key

Client API keys are scoped to a hosting account, not just a user. There are two ways to create one:

  • In the UI: Log in to the Client Area (port 8000), go to Account Settings > API Tokens, click Generate Token, and enter a descriptive name.
  • Via API (authenticated session or existing token):
    POST /api/client/api-tokens
    Content-Type: application/json
    Authorization: Bearer mp_EXISTING_TOKEN
    
    {"name": "My Automation Key"}
    Response:
    {"id": 3, "name": "My Automation Key", "token": "mp_a1b2c3d4e5f6..."}
Plan Requirement: API Access Must Be Enabled

Client API tokens will be rejected at authentication time with 403 api_access_disabled_for_plan unless the hosting account's plan has API Access enabled (allow_api_access = true). An admin must enable this flag on the plan. The API also blocks token creation at POST /api/client/api-tokens if the plan flag is off.

Token Format

Client tokens are prefixed with mp_ (without admin or reseller in the name), e.g. mp_a1b2c3.... The token is derived from secrets.token_hex(32) and SHA-256 hashed before storage — only shown once on creation.

Token Lifetime

Client tokens have no expiry by default (the expires_at field is NULL unless set). Use DELETE /api/client/api-tokens/{id} to revoke them.

Authentication Methods

# Option A: Bearer Header (Recommended)
Authorization: Bearer mp_YOUR_API_KEY

# Option B: X-API-Key Header
X-API-Key: mp_YOUR_API_KEY

# Option C: Query Parameter
GET /api/client/websites?api_key=mp_YOUR_API_KEY

# Optional: Scope to a specific hosting account (multi-account users)
X-Hosting-Account-ID: 2

Managing Client API Tokens via API

Method & EndpointDescription
GET /api/client/api-tokensList all tokens for the current hosting account
POST /api/client/api-tokensGenerate a new token — requires {"name": "label"} body
DELETE /api/client/api-tokens/{id}Revoke a token by ID

2. Code Snippets

cURL Example

# Create a new website
curl -X POST "http://your-server:8000/api/client/websites" \
     -H "Authorization: Bearer mp_YOUR_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{"domain": "mysite.com", "php_version": "8.3"}'

Python Example

import requests

API_KEY = "mp_YOUR_API_KEY"
BASE_URL = "http://your-server:8000"
headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}

# Add a new DNS A-record
payload = {
    "domain_id": 1,
    "name": "sub",
    "type": "A",
    "value": "127.0.0.1",
    "ttl": 300,
    "proxied": True
}
res = requests.post(f"{BASE_URL}/api/client/dns-records", headers=headers, json=payload)
print(res.json())

3. Complete Client Endpoint & Parameter Reference

Method & Endpoint Description Parameters & Payload Fields
GET /api/client/home Account overview, quotas, and resource summary None (Optional query: account_id)
GET /api/client/resource-usage CPU, Memory, Disk, and Inode trend metrics Query: range (30m | 24h | 7d | 30d)
POST /api/client/recalculate-usage Trigger immediate disk and inode usage recalculation None
GET /api/client/analytics Web access and bandwidth analytics Query: website_id (int), range (24h | 7d | 30d)
GET /api/client/php-info Fetch PHP configuration for a website Query: website_id (required, int)
GET /api/client/sync-jobs List background stack sync jobs for account None
GET /api/client/websites List all websites on account None
POST /api/client/websites Create a new website domain (string, required)
php_version (string: "8.1", "8.2", "8.3")
document_root (string, optional)
index_enabled (bool, default true)
modsec_enabled (bool, default true)
analytics_enabled (bool, default true)
PATCH /api/client/websites/{id} Update website settings php_version (string)
index_enabled (bool)
modsec_enabled (bool)
analytics_enabled (bool)
DELETE /api/client/websites/{id} Delete website and document root None
POST /api/client/websites/{id}/connection-check Test website OLS & PHP-FPM connectivity None
GET /api/client/php-versions List supported server PHP versions None
GET /api/client/domains List account domains None
POST /api/client/dns/check-domain Check domain DNS availability & Cloudflare zone status domain (string, required)
POST /api/client/dns/sync-cloudflare-rules Sync and ensure Cloudflare ACME challenge page rules for websites website_id (int, optional)
POST /api/client/domains/{id}/nameservers Update domain registrar nameservers nameservers (array of strings, required)
POST /api/client/domains/{id}/dns/rebuild Rebuild and publish authoritative DNS zone None
POST /api/client/domains/{id}/dns/verify-nameservers Verify nameservers resolution via public DNS None
GET /api/client/domains/{id}/dns/export Export DNS zone file in BIND format None
POST /api/client/domains/{id}/dns/migrate-provider Migrate DNS provider (Local vs Cloudflare) provider_key (string: "local-dev-dns", "cloudflare")
cloudflare_account_id (int, required if Cloudflare)
GET /api/client/dns-records List DNS records Query: domain_id (optional int filter)
POST /api/client/dns-records Add a DNS record domain_id (int, required)
name (string, required e.g., "sub" or "@")
type (string: "A", "AAAA", "CNAME", "MX", "TXT", "NS", "SRV")
value / content (string, required)
ttl (int, default 300)
priority (int, optional for MX/SRV)
proxied (bool, optional for Cloudflare)
PATCH /api/client/dns-records/{id} Update existing DNS record name, type, value, ttl, priority, proxied
DELETE /api/client/dns-records/{id} Delete a DNS record None
GET /api/client/databases List MySQL / MariaDB databases None
POST /api/client/databases Create a MySQL database name (string, required)
DELETE /api/client/databases/{id} Delete a MySQL database None
GET /api/client/database-users List MySQL database users None
POST /api/client/database-users Create a MySQL user username (string, required)
password (string, minimum 8 characters)
PATCH /api/client/database-users/{id} Change MySQL user password password (string, required)
DELETE /api/client/database-users/{id} Delete a MySQL user None
POST /api/client/database-grants Grant MySQL user database privileges database_id (int, required)
user_id (int, required)
privileges (string, default "ALL")
DELETE /api/client/database-grants/{id} Revoke database user grant None
GET /api/client/pg-databases List PostgreSQL databases None
POST /api/client/pg-databases Create a PostgreSQL database name (string, required)
DELETE /api/client/pg-databases/{id} Delete a PostgreSQL database None
GET /api/client/mailboxes List email mailboxes None
POST /api/client/mailboxes Create an email mailbox email (string, required e.g., "[email protected]")
password (string, minimum 8 characters)
quota_mb (int, default 1024)
PATCH /api/client/mailboxes/{id} Update mailbox password/quota password (string, optional)
quota_mb (int, optional)
DELETE /api/client/mailboxes/{id} Delete an email mailbox None
GET /api/client/mail-forwarders List email forwarders None
POST /api/client/mail-forwarders Create an email forwarder source_email (string, required)
destination_email (string, required)
DELETE /api/client/mail-forwarders/{id} Delete an email forwarder None
GET /api/client/ssh Get SSH access status & connection details None
POST /api/client/ssh/toggle Enable or disable SSH shell access enabled (bool, required)
POST /api/client/ssh/password Change account SSH / SFTP password password (string, minimum 8 characters)
GET /api/client/ftp-accounts List custom FTP accounts None
POST /api/client/ftp-accounts Create a custom FTP account username (string, required)
password (string, minimum 8 characters)
path (string, relative directory path)
DELETE /api/client/ftp-accounts/{id} Delete an FTP account None
GET /api/client/files/launch Generate single sign-on URL for File Manager Query: path (optional directory path)
GET /api/client/cron-jobs List scheduled cron jobs None
POST /api/client/cron-jobs Create a scheduled cron job schedule (string, standard 5-part cron syntax e.g. "0 * * * *")
command (string, required e.g. "php /home/public_html/cron.php")
DELETE /api/client/cron-jobs/{id} Delete a cron job None
POST /api/client/ssl/issue Issue Let's Encrypt SSL certificate for a website website_id (int, required)
POST /api/client/ssl/custom Install custom SSL certificate website_id (int, required)
certificate (PEM string, required)
private_key (PEM string, required)
GET /api/client/backups List website backup archives None
POST /api/client/backups Create a full website backup archive website_id (int, required)
POST /api/client/hotlink-protection Configure image hotlink protection website_id (int, required)
enabled (bool, required)
allowed_domains (array of strings)
POST /api/client/ip-blocking Configure IP blocking rules website_id (int, required)
blocked_ips (array of IP strings)
POST /api/client/directory-privacy Password protect a website directory (.htpasswd) website_id (int, required)
path (string, relative directory path)
username (string, required)
password (string, required)
GET /api/client/api-tokens List generated Client API keys None
POST /api/client/api-tokens Generate a new Client API key name (string, required descriptive label)
DELETE /api/client/api-tokens/{id} Revoke/delete a Client API key None
Admin Panel

Admin API

The Admin API is available on port 8001 and is accessible only to authenticated admin accounts. All endpoints are prefixed with /api/admin/. Authenticate using a long-lived API token generated from the Admin panel.

API Key Guide — Admin Panel

How to Generate an Admin API Key

Admin API keys are scoped to the individual admin account that created them. There are two ways to create one:

  • In the UI: Log in to the Admin Panel (port 8001), go to Settings > API Tokens, click Generate Token, enter a name and optional permission scopes.
  • Via API (requires an active admin session or existing admins.manage token):
    POST /api/admin/api-tokens
    Content-Type: application/json
    Authorization: Bearer mp_admin_EXISTING_TOKEN
    
    {"name": "CI/CD Pipeline Key", "permissions": ["clients.manage", "hosting.manage"]}
    Response (token is shown only once):
    {"id": 5, "name": "CI/CD Pipeline Key", "token": "mp_admin_a1b2c3d4...", "permissions": ["clients.manage", "hosting.manage"]}
Requires admins.manage Permission

Creating or deleting Admin API tokens via POST /api/admin/api-tokens requires the acting admin to hold the admins.manage permission (or the wildcard * / all). super_admin accounts always pass this check. system_admin and support_admin roles do not hold this permission by default.

Token Format

Admin tokens are prefixed with mp_admin_ (e.g. mp_admin_a1b2c3...). The prefix is used at authentication time to route the request to the correct token table. The raw hex suffix is SHA-256 hashed before storage — only shown once on creation.

Token Lifetime

Admin tokens have no expiry by default (the expires_at column is NULL unless explicitly set). Revoke with DELETE /api/admin/api-tokens/{id}. last_used_at is updated on every successful request.

Authentication Method

# Bearer header (only supported method for admin tokens)
Authorization: Bearer mp_admin_YOUR_API_KEY

# X-API-Key header also accepted
X-API-Key: mp_admin_YOUR_API_KEY

# Query parameter also accepted
GET /api/admin/dashboard?api_key=mp_admin_YOUR_API_KEY

Permission Scopes (for API Token Access Control)

When creating an Admin API token you can restrict it to a subset of operations by passing a permissions array. The available permission strings are:

PermissionGrants Access ToDefault for Role
* or allFull admin access (wildcard)super_admin
clients.manageCreate, update, delete, impersonate clientssystem_admin
clients.readRead-only access to client datasupport_admin
hosting.manageProvision, suspend, unsuspend, change planssystem_admin
hosting.readRead-only access to hosting accountssupport_admin
dns.manageDNS settings, domain operationssystem_admin
dns.readRead-only DNS datasupport_admin
system.manageStorage, networking, nodes, agent, status pagesystem_admin
admins.manageCreate admins, manage API tokens, manage 2FAsuper_admin only
plans.manageCreate and update hosting plans and reseller planssystem_admin
impersonateLogin-as a client or resellersuper_admin only
billing.manageBilling-related operationssystem_admin

A token's effective permission is the intersection of the token's own permissions array and the admin's role permissions. Granting ["*"] on a support_admin token still limits it to the role's base permissions.

Managing Admin API Tokens via API

Method & EndpointDescription
GET /api/admin/api-tokensList tokens belonging to the authenticated admin
POST /api/admin/api-tokensCreate a new token — admins.manage required
DELETE /api/admin/api-tokens/{id}Revoke a token by ID — admins.manage required

Admin API Endpoint Reference

Method & Endpoint Description Parameters & Payload Fields
POST /api/admin/auth/login Authenticate admin and obtain a session token email (string, required)
password (string, required)
POST /api/admin/auth/totp/verify Verify TOTP 2FA code to complete login code (string, 6-digit TOTP)
POST /api/admin/auth/logout Invalidate the current admin session None
GET /api/admin/dashboard Admin dashboard overview with counts, jobs, and system stats None
GET /api/admin/users List all client users None
GET /api/admin/account-stacks List all account Docker Compose stacks with runtime state None
GET /api/admin/clients List all clients with hosting account details None
POST /api/admin/clients Create a new client account email (string, required)
password (string, min 8 chars)
full_name (string, optional)
PATCH /api/admin/clients/{id} Update client email, name, or status email (string, optional)
full_name (string, optional)
status ("active" | "suspended")
DELETE /api/admin/clients/{id} Delete a client and all associated resources None
POST /api/admin/clients/{id}/login-as Impersonate a client and get a redirect URL to their panel None
GET /api/admin/hosting-accounts List all hosting accounts with plan and node details None
POST /api/admin/hosting-accounts Provision a new hosting account for a client user_id (int, required)
plan_id (int, required)
node_id (int, required)
POST /api/admin/hosting-accounts/{id}/suspend Suspend a hosting account None
POST /api/admin/hosting-accounts/{id}/unsuspend Unsuspend a previously suspended hosting account None
PATCH /api/admin/hosting-accounts/{id}/plan Change a hosting account's plan plan_id (int, required)
PATCH /api/admin/hosting-accounts/{id}/dns-provider Override DNS provider for a specific hosting account dns_provider (string: "local-dev-dns" | "cloudflare")
dns_provider_account_id (int, optional)
GET /api/admin/plans List all hosting plans None
POST /api/admin/plans Create a new hosting plan name (string, required)
storage_mb (int)
memory_mb (int)
cpu_limit (float)
max_websites (int)
max_databases (int)
max_mailboxes (int)
max_cron_jobs (int)
dns_default_provider (string)
PATCH /api/admin/plans/{id} Update an existing hosting plan Same fields as POST plus:
apply_to_existing_accounts (bool)
migrate_existing_domains (bool)
POST /api/admin/plans/{id}/recalculate_usage Queue usage recalculation job for a specific plan None
POST /api/admin/plans/recalculate_usage Queue usage recalculation for all plans (or specific plan) plan_id (int, optional)
GET /api/admin/nodes List all registered server nodes None
POST /api/admin/nodes Register a new server node name (string, required)
hostname (string, required)
quota_backend (string, default "dev-simulator")
GET /api/admin/admins List all admin accounts None
POST /api/admin/admins Create a new admin account email (string, required)
password (string, min 8 chars)
full_name (string, optional)
role ("support_admin" | "system_admin" | "super_admin")
POST /api/admin/admins/{id}/reset-password Reset an admin account's password password (string, required)
POST /api/admin/admins/{id}/disable-2fa Disable TOTP 2FA for an admin account None
POST /api/admin/admins/{id}/enable-2fa Enable and re-generate TOTP secret for an admin None
GET /api/admin/api-tokens List Admin API tokens for the authenticated admin None
POST /api/admin/api-tokens Generate a new Admin API token name (string, required)
permissions (array of strings, default ["*"])
DELETE /api/admin/api-tokens/{id} Revoke an Admin API token None
GET /api/admin/reseller-plans List all reseller plans None
POST /api/admin/reseller-plans Create a new reseller plan name (string, required)
max_storage_mb (int, default 50000)
max_clients (int, default 10)
max_hosting_accounts (int, default 20)
max_ram_mb (int, default 8192)
max_websites (int, default 50)
max_databases (int, default 50)
max_subplans (int, default 10)
PATCH /api/admin/reseller-plans/{id} Update a reseller plan Same fields as POST
DELETE /api/admin/reseller-plans/{id} Delete a reseller plan None
GET /api/admin/reseller-users List all reseller users None
POST /api/admin/reseller-users Create a new reseller user email (string, required)
password (string, min 8 chars)
full_name (string, optional)
reseller_plan_id (int, optional)
PATCH /api/admin/reseller-users/{id} Update reseller user status, name, or plan status ("active" | "suspended")
full_name (string, optional)
reseller_plan_id (int, optional)
DELETE /api/admin/reseller-users/{id} Delete a reseller user account None
POST /api/admin/reseller-users/{id}/login-as Impersonate a reseller and get a redirect URL to their panel None
GET /api/admin/dns-settings Get global DNS provider configuration None
PATCH /api/admin/dns-settings Update global DNS provider settings DNS provider configuration payload
GET /api/admin/domains List all domains across all accounts None
POST /api/admin/domains Add a domain for a client account user_id (int, required)
domain (string, required)
account_id (int, optional)
register (bool, trigger registrar registration)
registrar_provider_id (int, optional)
POST /api/admin/domains/{id}/dns/rebuild Rebuild and publish the authoritative DNS zone for a domain None
POST /api/admin/domains/{id}/dns/verify-nameservers Verify nameserver propagation via public DNS None
GET /api/admin/domains/{id}/dns/export Export DNS zone in BIND format None
POST /api/admin/domains/{id}/dns/migrate-provider Migrate a domain to a different DNS provider dns_provider (string: "local-dev-dns" | "cloudflare")
dns_provider_account_id (int, optional)
POST /api/admin/domains/dns/bulk-migrate-provider Bulk migrate all (or selected) domains to a new DNS provider dns_provider (string, required)
domain_ids (array of ints, optional)
all (bool, migrate all domains)
POST /api/admin/domains/{id}/registrar-nameservers Update domain nameservers via the registrar API nameservers (array of 2–4 nameserver strings)
GET /api/admin/registrars List all configured domain registrar providers None
POST /api/admin/registrars/{key} Configure a registrar provider (e.g. resellerclub) api_key (string, required)
settings (object, provider-specific)
reseller_id (string, required for ResellerClub)
POST /api/admin/dns/sync-cloudflare-rules Sync and ensure missing Cloudflare ACME challenge page rules system-wide website_id (int, optional)
account_id (int, optional)
POST /api/admin/dns-providers/cloudflare/accounts Add a Cloudflare account for DNS management display_name (string, required)
api_token (string, required)
account_name (string, optional)
external_account_id (string, optional)
PATCH /api/admin/dns-providers/cloudflare/accounts/{id} Update a Cloudflare account configuration display_name (string)
api_token (string, optional – rotates token)
status ("active" | "disabled")
DELETE /api/admin/dns-providers/cloudflare/accounts/{id} Remove a Cloudflare account (must not be in use by any plan) None
POST /api/admin/dns-providers/cloudflare/accounts/{id}/migrate-local Migrate all domains in a Cloudflare account to local PowerDNS None
POST /api/admin/dns-providers/{id}/test Test DNS provider connectivity and credentials provider_account_id (int, optional)
GET /api/admin/storage/df Get server disk filesystem usage summary None
GET /api/admin/storage/live Get live disk I/O read/write metrics None
GET /api/admin/storage/live/stream Server-Sent Events stream of live disk I/O metrics None
GET /api/admin/storage/quotas List per-account storage quota usage None
GET /api/admin/storage/paths Get size breakdown by major filesystem paths None
POST /api/admin/storage/cleanup Run storage cleanup for Docker, logs, and temp files clean_docker (bool, default true)
clean_logs (bool, default true)
clean_tmp (bool, default true)
GET /api/admin/storage/alerts Get storage alert threshold settings None
POST /api/admin/storage/alerts Update storage alert threshold settings Storage alert configuration payload
GET /api/admin/network/overview Network overview including interface stats None
GET /api/admin/network/live Live network I/O throughput metrics None
GET /api/admin/network/live/stream Server-Sent Events stream of live network I/O None
GET /api/admin/network/ips List all registered server IP addresses None
POST /api/admin/network/ips Add a new server IP address IP address configuration payload
PUT /api/admin/network/ips/{id} Update a server IP address record IP address configuration payload
DELETE /api/admin/network/ips/{id} Remove a server IP address record None
POST /api/admin/network/assign-account-ip Assign (or clear) a dedicated IP for a hosting account account_id (int, required)
ip_id (int, optional – omit to clear)
GET /api/admin/jobs List recent background agent jobs (last 100) None
GET /api/admin/job-events List recent job event log entries (last 100) None
POST /api/admin/jobs/{id}/retry Retry a failed or queued agent job None
POST /api/admin/agent/run-once Trigger the agent to process one pending job None
POST /api/admin/agent/run-all Trigger the agent to process all pending jobs None
GET /api/admin/security/audit Run and return a live server security audit report None
GET /api/admin/audit-logs List audit log entries (last 100) None
GET /api/admin/system/default-page Get the default landing page HTML content None
POST /api/admin/system/default-page Set custom default landing page HTML content default_page_content (string HTML, required)
POST /api/admin/system/default-page/reset Reset the default landing page to the system default None
GET /api/admin/status Get the public status page payload including health checks None
POST /api/admin/status/incidents Create a new status incident title (string, required)
severity ("minor" | "major" | "critical")
state ("investigating" | "identified" | "monitoring" | "resolved")
message (string, optional)
published (bool, default true)
GET /api/admin/status/incidents List all status incidents with their update history None
PATCH /api/admin/status/incidents/{id} Update an incident's title, severity, state, or visibility title (string)
severity (string)
state (string)
published (bool)
DELETE /api/admin/status/incidents/{id} Delete a status incident and all its updates None
POST /api/admin/status/incidents/{id}/updates Add an update to an existing incident state (string, required)
message (string, optional)
POST /api/admin/status/maintenance Schedule a maintenance window title (string, required)
state ("scheduled" | "in_progress" | "completed")
starts_at (datetime string)
ends_at (datetime string)
message (string, optional)
PATCH /api/admin/status/maintenance/{id} Update the state or message of a maintenance window state (string, optional)
message (string, optional)
POST /api/admin/status/components Update a status page component's health status component_id (int or string)
status ("operational" | "degraded" | "partial_outage" | "major_outage")
PATCH /api/admin/status/components/{id} Update a specific status component by ID status (string, required)
POST /api/admin/status/checks/{id}/run Manually trigger a status health check None
Reseller Panel

Reseller API

The Reseller API is available on port 8002 (or the configured reseller port) and is accessible to reseller accounts. All endpoints are prefixed with /api/reseller/. Authenticate using a long-lived Reseller API token.

API Key Guide — Reseller Panel

How to Generate a Reseller API Key

Reseller API keys are scoped to the reseller user account. There are two ways to create one:

  • In the UI: Log in to the Reseller Panel (port 8002), go to Settings > API Tokens (shown under the Admins page), click Generate Token, and enter a name.
  • Via API (requires an active reseller session or existing reseller token):
    POST /api/reseller/api-tokens
    Content-Type: application/json
    Authorization: Bearer mp_reseller_EXISTING_TOKEN
    
    {"name": "Provisioning Bot", "permissions": ["*"]}
    Response (token is shown only once):
    {"token_id": 2, "token": "mp_reseller_a1b2c3d4...", "name": "Provisioning Bot"}

Token Format

Reseller tokens are prefixed with mp_reseller_ (e.g. mp_reseller_a1b2c3...). The prefix routes the token to the reseller_api_tokens table at authentication time. The raw 20-byte hex suffix is SHA-256 hashed before storage — only shown once on creation.

Token Lifetime

Reseller tokens are created with an expiry of 365 days from creation (expires_at = now + 31536000). After expiry the server returns 401 reseller_api_token_expired. Generate a new token to replace an expired one.

Authentication Methods

# Bearer header (recommended)
Authorization: Bearer mp_reseller_YOUR_API_KEY

# X-API-Key header also accepted
X-API-Key: mp_reseller_YOUR_API_KEY

# Query parameter also accepted
GET /api/reseller/dashboard?api_key=mp_reseller_YOUR_API_KEY

Permission Scopes

When creating a Reseller API token you can pass a permissions array to narrow its scope. Reseller tokens do not map to named roles — the permissions field is stored as a JSON array and compared directly. Use ["*"] for full reseller access.

Reseller Scope Is Always Enforced

Regardless of the token's permission array, all reseller routes are automatically scoped to resources owned by that reseller. A reseller token can never read or modify another reseller's clients, plans, or accounts. The reseller_id from the authenticated token is injected into every query.

Managing Reseller API Tokens via API

Method & EndpointDescription
GET /api/reseller/api-tokensList all tokens for the authenticated reseller
POST /api/reseller/api-tokensCreate a new token — any authenticated reseller can do this
DELETE /api/reseller/api-tokens/{id}Revoke a token by ID
Admin API Fallback

Unmatched reseller routes automatically fall through to the Admin API handler (with the reseller acting as a scoped admin). This means most admin-level read operations are also accessible via the /api/reseller/ prefix.

Reseller API Endpoint Reference

Method & Endpoint Description Parameters & Payload Fields
POST /api/reseller/auth/login Authenticate reseller and obtain a session token email (string, required)
password (string, required)
POST /api/reseller/auth/totp/verify Verify TOTP 2FA code to complete reseller login code (string, 6-digit TOTP)
POST /api/reseller/auth/logout Invalidate the current reseller session None
GET /api/reseller/dashboard Reseller dashboard overview with sub-client, account, and storage stats None
GET /api/reseller/users List all sub-clients created by this reseller None
GET /api/reseller/account-stacks List all hosting accounts belonging to reseller's sub-clients None
GET /api/reseller/job-events List recent background job events (last 50) None
GET /api/reseller/clients List all sub-clients with their hosting accounts None
POST /api/reseller/clients Create a new sub-client under this reseller email (string, required)
password (string, min 8 chars)
full_name (string, optional)
PATCH /api/reseller/clients/{id} Update a sub-client's status or name status ("active" | "suspended")
full_name (string, optional)
DELETE /api/reseller/clients/{id} Delete a sub-client account None
GET /api/reseller/plans List all hosting plans created by this reseller None
POST /api/reseller/plans Create a new sub-plan (limits enforced by the reseller's master plan) name (string, required)
storage_mb (int, ≤ master plan limit)
memory_mb (int, ≤ master plan limit)
max_websites (int, ≤ master plan limit)
max_databases (int, ≤ master plan limit)
max_mailboxes (int)
max_cron_jobs (int)
POST /api/reseller/hosting-accounts Provision a hosting account for a sub-client using a reseller sub-plan user_id (int, must belong to this reseller)
plan_id (int, must be a reseller sub-plan)
GET /api/reseller/storage/df Get aggregated storage usage across all reseller sub-accounts None
GET /api/reseller/storage/live Live disk I/O metrics scoped to reseller accounts None
GET /api/reseller/storage/quotas Per-account storage quota usage for reseller sub-accounts None
GET /api/reseller/storage/paths Size breakdown by major filesystem paths None
POST /api/reseller/storage/cleanup Run storage cleanup for Docker, logs, and temp files clean_docker (bool, default true)
clean_logs (bool, default true)
clean_tmp (bool, default true)
GET /api/reseller/storage/alerts Get storage alert threshold settings None
GET /api/reseller/network/overview Network overview for reseller-scoped accounts None
GET /api/reseller/network/live Live network I/O metrics scoped to reseller accounts None
GET /api/reseller/network/ips List all server IP addresses None
GET /api/reseller/dns-settings Get global DNS provider configuration None
GET /api/reseller/domains List all domains belonging to reseller sub-clients None
GET /api/reseller/dns-providers/cloudflare/accounts List Cloudflare DNS accounts visible to this reseller None
GET /api/reseller/registrars List domain registrar providers None
GET /api/reseller/security/audit Run and return a live server security audit report None
GET /api/reseller/admins Get the reseller's own profile and API token list None
GET /api/reseller/api-tokens List Reseller API tokens None
POST /api/reseller/api-tokens Generate a new Reseller API token name (string, required)
permissions (array of strings, default ["*"])
DELETE /api/reseller/api-tokens/{id} Revoke a Reseller API token None
GET /api/reseller/status Get the current system and service status payload None
GET /api/reseller/default-page Get the default landing page content None