Blog ·
How to sell web hosting with CloudPanel
CloudPanel is fast, free and built for one server, not for tenants. What its command line really does, and the three gaps that matter when you sell on it.
By Provibr
CloudPanel is the panel people install when they want a site running fast and nothing else in the way. It is free, it goes onto a fresh cloud instance in minutes, and what comes out is a plain NGINX and PHP-FPM stack with Let's Encrypt, a database and a Cloudflare integration. No mail server. No layers you did not ask for.
That focus is exactly why people like it, and it is also why selling hosting on it is a different exercise than on DirectAdmin or cPanel. CloudPanel manages sites on one server. It does not manage customers who pay you. Those are not the same problem, and the distance between them is what this page is about.
What CloudPanel is actually built around
One server, and the sites on it.
You create a site (PHP, static, Node.js, Python, or a reverse proxy) and CloudPanel writes an NGINX vhost, a PHP-FPM pool, a Linux site user and a home directory. You create a database next to it. You point a certificate at it. That is the loop, and it is a good one: a developer or an agency running twenty sites on one box gets a clean interface over exactly the things they touch.
What it does not have is the layer above that: a client who owns a set of sites, with a plan, a quota and a switch. CloudPanel has panel users with roles (admin, site manager, user), and those users can be scoped to specific sites. But that is access control for people who log in, not a commercial account you can bill and shut off.
The distinction sounds academic until the first customer stops paying.
The control surface is one command-line tool
CloudPanel has no REST API. Everything automation can do, it does through clpctl, the panel's own command-line tool, which runs on the host as root. It is properly scriptable, with flags instead of prompts and no interactive steps, and it covers the parts you would expect:
| What you want | clpctl |
|---|---|
| Create a PHP site | site:add:php --domainName=… --phpVersion=8.4 --siteUser=… --siteUserPassword=… |
| Create a static, Node.js, Python or proxy site | site:add:static / site:add:nodejs / site:add:python / site:add:reverse-proxy |
| Delete a site | site:delete --domainName=… --force |
| Add a database | db:add --domainName=… --databaseName=… --databaseUserName=… --databaseUserPassword=… |
| Install a certificate | site:install:certificate / lets-encrypt:install:certificate |
| Manage panel logins | user:add / user:delete / user:list / user:reset:password |
Two things in that table are worth noticing before you plan anything around it.
The first is that the identity of a site is its domain name. Not a numeric id, not an account handle. The domain. Everything you build keys off that, and it has to survive a customer who wants to move a domain between plans.
The second is more consequential, and it is what the next section is about: there is no verb in that table for turning a site off.
The three gaps that matter when you sell
There is no suspend
clpctl has site:add:* and it has site:delete. It has nothing in between. There is no site:suspend, no site:disable, no maintenance switch, and the panel interface has no equivalent either.
For a hosting business that is not a cosmetic gap, because "the invoice is thirty days overdue" is the single most common thing you will ever need to act on, and deleting the site is not the answer. Deleting is irreversible and takes the customer's data with it; a customer who pays on day thirty-one expects to find their website where they left it.
So anything that sells CloudPanel hosting has to invent suspension. The usual candidates are stopping the site's PHP-FPM pool, or editing the vhost so the site stops answering. Both work, and the second is the better of the two: a stopped pool produces a 502, which looks to your customer like your server is broken rather than like their invoice is overdue.
Editing a vhost well is a shorter list than it sounds. Wrap what you insert in begin and end comments so that resuming means deleting exactly those lines and nothing else. Do it in every public server block, because a vhost usually has one for port 80 and one for 443. A site that is suspended over HTTP and healthy over HTTPS is worse than one that is not suspended at all, since it looks like it worked. Run nginx -t before you reload, because this is a shared web server and a bad config takes every site on it down with you. Do those three and suspension becomes an ordinary, instant, fully reversible action. Provibr does exactly this: a marked return 403;, every public block, tested before reload.
What no arrangement fixes is that the panel does not know. CloudPanel has no concept of a suspended site, so it will list a suspended one as ordinary, and anyone with panel or host access can open the file and take the line out, including the customer you just suspended. You can make the state readable (the marker is a grep away, which is how Provibr notices a hand-edit) but you cannot make CloudPanel own it.
Decide what "off" means before the first customer, not after the first non-payer.
There are no packages
CloudPanel has no plans, no quotas and no per-site limits. No disk quota, no bandwidth cap, no "this site may have three databases". The closest thing to a package is a vhost template, which is an NGINX configuration: useful, but not a limit, and it will not stop anyone from using 400 GB.
That means your product catalogue cannot live in the panel. Whatever separates your €5 plan from your €15 plan has to be defined, enforced and measured somewhere above CloudPanel. If it is not enforced anywhere, it is not a plan. It is a suggestion.
There is no list of sites
There is user:list for panel logins. There is no site:list. The sites themselves live in the panel's own SQLite database on the host.
That matters more than it sounds, because a list is what reconciliation is made of. Without one you cannot answer "does what I am billing for still exist?", you cannot detect a site somebody deleted by hand, and you cannot import an existing server into anything at all.
The way out is to read that database directly: /home/clp/htdocs/app/data/db.sq3, one select over the site table, and you have every domain with its user, template and PHP version. It is what Provibr does, and it is what anything else serious will end up doing. Just know that you are reading an internal schema rather than an interface: it can change in a release without that being a broken promise, so it goes on the list of things to re-check after a panel upgrade.
And one design constraint underneath all of it
clpctl runs as root on the host. That is not an implementation detail you can route around: it writes NGINX configuration, creates Linux users and manages system services, and those need the privileges they need.
The consequence is that automating CloudPanel is a privilege question before it is an integration question. Anything driving clpctl (your own script, a cron job, a deployment tool) runs as root on a production web server that hosts other people's sites. Whatever you build, build it knowing that the credential involved is not a scoped API token; it is administrative access to the machine. Keep it narrow, keep it auditable, and keep it far away from anything a customer can reach.
What has to exist above the panel
Strip out the panel-specific detail and the list is the same for any control panel, which is the useful part, because it does not change if you switch panels later:
- An order form and a catalogue, with plans that mean something enforceable.
- A payment that triggers provisioning within seconds, not within a working day.
- A dunning path (overdue, warned, suspended, restored) with a defined action at each step.
- Capacity you can see, so you know how many accounts you are carrying and what they cost you before the invoice tells you.
- An audit trail, so that "who deleted that site" has an answer.
- A permission model for the people who work for you, so support can restart something without being able to delete everything.
None of that comes with CloudPanel, and none of it is what CloudPanel is trying to be.
Where Provibr fits
CloudPanel support is live. An agent inside your own network connects to the host over SSH and runs clpctl the way an administrator would by hand, so nothing is installed on the panel and no port has to face the internet. Creating a site, suspending it, resuming it and removing it all work, and sites that were already there are imported only when you tick them. Around that sits the layer described above: plans and capacity, a per-unit price, a permission model, an activity trail, and a REST API and WHMCS module to drive it from whatever you already bill with.
What the integration cannot do is wish away the gaps above, because they are properties of the panel. Suspension is the invented part: a marked NGINX rule that returns 403, injected into every public server block and tested before the reload, and resuming removes it so the site is byte-for-byte back. The vhost template is fixed once a site exists, so there is no package change: moving a site to another template or PHP version means recreating it, and Provibr says so instead of pretending a change happened. There is no console and no usage graph either, because CloudPanel measures neither.
What it will not do
Worth saying now rather than later: managing accounts is not managing the panel. Installing CloudPanel, updating it, changing server settings, tuning NGINX, and looking after the databases and certificates your customers create all stay on your side, in the panel, where they belong.
You do not have to bet the business on one panel. Provibr runs its control panels, hypervisors and game panels side by side, under one inventory, one permission model and one activity trail. A lightweight NGINX panel for the customers who want speed on a single box, something with a reseller tree for the ones who ask for cPanel by name, and one place where you can see both.