Skip to content

Blog ·

How to sell web hosting with CyberPanel

CyberPanel has an API, but creating a site reports success before it knows. What the API really returns, the traps that bite first, and how to build on it.

By Provibr

CyberPanel is the panel most often named alongside DirectAdmin by hosters running OpenLiteSpeed. Measured on GitHub on 21 August 2026: 2,007 stars, 723 forks, and 362 open issues, against a slower release cadence than most of its peers.

It has a REST API, and everything you need to sell hosting on it (create a site, suspend it, change its package, delete it) is part of that API. What it does not have is anything that decides when to do those things, and what it does have is a set of answers that are easy to misread.

Before anything: API access is off

On a fresh CyberPanel the API is switched off, and that holds for your main administrator too. You turn it on under Users → API Access, for the user admin. Nothing else is needed; you sign in with the login you already have.

Leave it off and every call comes back as API Access Disabled. whatever you send. The part that costs an afternoon is the ordering: CyberPanel checks that flag before it checks the password, so with it off a correct password and a wrong one return the identical 403. Everything points at your credentials while the problem is one checkbox further along.

Once the flag is on, the contract underneath is clean and genuinely useful:

text
correct password  → HTTP 200  {"verifyConn": 1}
wrong password    → HTTP 401  {"verifyConn": 0, "error_message": "Invalid password."}
unknown user      → HTTP 404  {"error_message": "Administrator not found."}

Three situations, three different actions for the customer, all distinguishable.

The administrator has to be called admin

Not a setting but a condition, and it comes from CyberPanel rather than from anything built on top of it. Part of its API is guarded by a literal name check that refuses every user other than admin, and that part is precisely the one that lists the websites on the panel and reports how far a new one has come.

Both are unavoidable if you want to sell hosting on it: you need the list to know what exists, and you need the progress reporting for the reason in the next section. An administrator that was renamed cannot be used, and anything you build should say so during the connection test, before your first order finds out for you.

An account is a domain, not a username

This is the structural difference from DirectAdmin, cPanel and Virtualmin, and it changes how you model the product.

CyberPanel's website record has a unique domain field, and every command aims at it: delete takes domainName, suspend and package change take websiteName, and all three look the site up by domain. There is no username to address. The unix user is generated, not chosen: five letters extracted from the domain plus four random digits. Measured for provibr-test-1.example.com: provi7346, with the home directory named after the domain, not the user. You cannot pick that name, cannot predict it, and it appears in exactly one API response and in no listing at all.

One consequence worth knowing before your hundredth account: creating a website also creates a panel login underneath it, with API access enabled, and that login survives deleting the website. Measured after a delete: unix user gone, home directory gone, vhost gone, database row gone; the owner login still there. CyberPanel's cleanup path is guarded by a check that cannot succeed at the moment it runs, and the resulting error is swallowed. If nothing above the panel removes it, every cancelled customer leaves a login behind.

Creating a website reports success before it knows

This is the single most important thing to understand about CyberPanel's API.

createWebsite answers in about three seconds with:

json
{"status": 1, "createWebSiteStatus": 1, "error_message": "None",
 "tempStatusPath": "/home/cyberpanel/2424", "LinuxUser": "provi7346"}

That arrives before most of the work has happened: the endpoint builds a command line, starts it without waiting, and returns. Real progress lives in a status file, readable through a separate call. Measured, one real creation:

text
+ 2.8s   10%  Creating DNS records..
+ 4.8s   25%  Setting up directories..
+ 6.9s   70%  Setting up SSL..        ← sits here for 28 seconds
+35.3s   80%  Creating mail child domain..
+49.5s  100%  Website successfully created. [200]

Roughly fifty seconds, of which about twenty-eight are an SSL attempt the panel makes whatever you send along, because the API overrides that flag unconditionally and there is no way to create a site without one. On a domain that does not resolve publicly yet, that is twenty-eight seconds of waiting for a certificate that will not arrive.

And the first answer is not a verdict. Measured with deliberately bad input:

CaseThe HTTP answerWhat actually happened
Domain already existscreateWebSiteStatus: 1 (success)This website already exists. [404] in the status file
Unknown packagecreateWebSiteStatus: 1 (success)Package matching query does not exist. [404]
Malformed domaincreateWebSiteStatus: 0, "Invalid domain."refused up front
Malformed emailcreateWebSiteStatus: 0, "Invalid email."refused up front

Only the shape of the domain and the email is checked immediately. Whether the domain is free, and whether the package exists, is only visible in the status file. An integration that trusts the first answer will report a successful order for a domain that was already taken.

Two more details make polling it harder than it looks. Reading a completed status deletes the file, so a second poll returns "no such file" with a "not finished" flag. A client that polls once too often sees "still working" forever, for a creation that succeeded. And the status call lives only on the admin-only surface, which is why the admin name requirement above is not optional.

Suspension is a web server trick, not an account lock

Suspend and resume are the well-behaved part of this API: both take effect immediately, and the panel's own list shows the new state at once.

But know what it does. CyberPanel rewrites the site's vhost configuration to a suspension page and restarts the web server. The unix user is not locked out; FTP, mail and databases keep working. The website becomes unreachable and nothing else does. That differs from DirectAdmin, and it matters the moment you use suspension to enforce payment.

One more thing, worth a constant in your code rather than a variable: the implementation is if state == "Suspend": … else: <resume>, with no validation on the value. Measured on a real site:

text
1. state:"Suspend"  → list: Suspended
2. state:"suspend"  → {"websiteStatus": 1, "error_message": "None"}
3. list:            → Active     ← a lowercase letter resumed the site

A typo silently reactivates a suspended customer and reports success.

Changing package changes the bookkeeping, and nothing else

changePackageAPI returns in about 270 milliseconds and the panel shows the new package name. Measured from inside the server afterwards, with a package carrying deliberately different limits: the disk quota was unchanged (soft 0, hard 0) and the vhost configuration still carried the old package's memory and process limits.

Nothing was applied. The whole operation is a database field update. Read the package name in CyberPanel as administration, not as a limit that moved with it, and anything above the panel should say so rather than imply an upgrade took effect.

There is no usage data

CyberPanel is the only control panel in Provibr without usage graphs, and that is not an omission in the integration: the panel does not measure it.

Bandwidth is calculated and then discarded. It never reaches the listing. Disk usage comes out of a cache stored on the website record, and on a freshly created site that field is empty, so the reported value falls back to zero. A zero from an empty cache cannot be told apart from a site that genuinely uses nothing. A graph that sits at zero forever looks like a measurement; that is why there is none.

What Provibr does with it

Provibr connects through an agent inside your own network that dials outbound, so the panel needs nothing exposed. It asks for four things: the panel address including port 8090, the username admin, that administrator's password, and the SHA-256 fingerprint to pin to while the panel still uses the certificate it shipped with.

That last one is not optional in practice. Every fresh CyberPanel presents the same self-signed certificate, issued to www.example.com and signed by CyberPanel itself. A browser calls it wrong rather than self-signed, and the chain never validates. Pinning the fingerprint means trusting that one certificate instead of switching verification off. Put your own certificate on the panel's hostname and the chain validates by itself; then leave the field empty.

Be aware of what the password is. CyberPanel has no API token covering these commands: inside its own API the token route is enabled or disabled per endpoint, and the four that create, suspend, repackage and remove a site all require the password. So this is the full password of your main administrator.

With that in place: packages become sellable as web plans under a name and price of your own, orders create sites and wait for the real outcome rather than the first answer, suspend and resume work on demand and when you exceed capacity, and websites that already exist can be imported.

What it does not do

Provibr manages websites, not the panel: it does not install CyberPanel, does not update it, and does not change server settings. There is no console. DNS, mailboxes and databases stay untouched, because CyberPanel does all of that itself and nothing above it drives them. And there are no usage graphs, because there is nothing honest to draw.

You do not have to bet on one panel. Provibr runs its control panels, hypervisors and game panels side by side today. They share one inventory, one permission model and one activity trail.

Start with one host and one agent

Create an account, install the agent with a single command and connect your first Proxmox host. The trial runs for 14 days and asks for no payment details.