Skip to content

The cPanel migration check

Before moving anything, you can find out what a move would involve. The migration check is a single command you run on your cPanel server. It reads that server’s configuration and prints an inventory, a score, and the specific list of things that would need attention — then deletes itself.

Terminal window
curl -fsSL https://get.corepanel.net/check | sh

It must run as root, because the things worth reporting on — accounts, mailbox hashes, per-domain PHP versions — live in files only root can read.

CorePanel migration check
=========================
Server: cp.example.com
OS: AlmaLinux 9.8
cPanel: 11.136.0.35
Database: 10.11.19-MariaDB
PHP: ea-php81, ea-php82
DNS: powerdns
FTP: pure-ftpd
Inventory: 5 accounts, 11 domains, 4 mailboxes, 3 databases, 8 DNS zones, 9 certificates
Packages: 2 (default, starter)
Score: 100/100 — ready to transform
NOTES (3)
• JetBackup is installed on this server
→ account backups carry over as a capability: CorePanel has its own backup system…
────────────────────────────────────────────────────────────────────
✔ READY TO TRANSFORM
score 100/100 · nothing on this server stands in the way
────────────────────────────────────────────────────────────────────
WHAT COMES NEXT
PLAN the ordered list of steps, with how long each service is offline.
Read-only, like this check.
PREPARE installs CorePanel beside cPanel, with nothing going offline:
cPanel keeps serving every site throughout.
CUTOVER is the only offline window — seconds rather than hours, because
nothing is copied.
VERIFY checks that every domain, mailbox, database and zone answers.
'rollback' gives the server back to cPanel at any point until 'cleanup'.
Nothing on this server was modified.

Add -v to list every account individually, with its domains, mailboxes, databases, cron jobs, certificates and its own findings:

Terminal window
curl -fsSL https://get.corepanel.net/check | sh -s -- -v

The last thing the check prints is its answer, in one of three states:

BannerWhat it means
🟢READY TO TRANSFORMNothing on this server stands in the way
🟡READY TO TRANSFORM, WITH ITEMS TO REVIEWIt works, but some items degrade or need manual work — they are listed above the banner
🔴CANNOT BE TRANSFORMED IN PLACEOne or more blockers have to be resolved first. The banner deliberately offers no next command

The same answer appears next to the score at the top of the report; it is repeated at the end because on a server with dozens of findings the top has long scrolled away.

Colour is a convenience of the terminal, not part of the report: it is used only when the output is a terminal, so a run redirected into a file or pasted into a ticket is plain text. NO_COLOR turns it off, and --color=always forces it on.

Every finding carries one of three severities, and they mean genuinely different things.

MeaningWhat to do
BlockerThis server cannot be migrated as it standsEach blocker names its way out. The common one is the operating system: CorePanel runs on RHEL 8–10 and its rebuilds
WarningThe migration works, but something specific degradesRead it before you schedule anything. Most warnings are per-domain and name the file and the line
NoteReported for completeness, costs no scoreNothing to do. A note is there so nothing arrives as a surprise later

Below the findings, the check prints a section of its own: HANDLED BY THE CUTOVER. Your server is probably not just cPanel — it carries a WAF, a firewall, a backup product, maybe a proxy in front of Apache — and those are not problems to solve. CorePanel brings what each of them was doing, and the transformation stops them for you.

ProductWhat takes over
NGINX (cPanel’s NGINX Manager), Engintron, Varnish, LiteSpeedcorehttpd, which serves every site and caches pages itself
Imunify360 / ImunifyAV, BitNinja, cPGuardCorePanel’s WAF — included in every edition — and Pyxsoft Anti Malware for scanning
Bought ModSecurity rule sets (Comodo, Atomicorp, …)the same WAF. There is nothing to buy and nothing to install
JetBackupCorePanel’s own backups. Existing archives are not adopted — keep them reachable until the rollback window closes
SoftaculousCorePanel’s application installer. Installed applications keep working: they are just files
CSF/LFD, or PyxSoft’s pxfcorepanel-auth takes over brute-force protection. The firewall itself is turned off rather than kept — see below

Nothing on that list is uninstalled, and nothing on it needs doing before you start. Each is stopped, disabled and — for the ones that restart themselves — masked, so a rollback puts every one of them back.

CSF/LFD, or PyxSoft’s pxf, is disabled during the cutover — with csf -x and pxf disable, their own commands, because stopping the unit leaves every rule in the kernel. This is not offered as a choice, for two reasons: it opens cPanel’s ports and not CorePanel’s, so a server that keeps it is a server whose passive FTP does not work; and ConfigServer closed in August 2025, so CSF has no upstream — what is on the machine is unmaintained software configured for a panel that is about to be gone.

That leaves the server without a firewall until you put one back. The check and the cutover both say so in those words. firewalld is the one CorePanel manages, from the panel or the CLI, and it is what should be in front of the server before it is left to itself. If you roll the transformation back, csf -e and pxf enable are the exact reverse and rollback runs them for you.

It has one consequence that is worth knowing about, because nothing on the server announces it: on a dual-stack machine, taking the firewall down can change which of the server’s two addresses its outbound connections leave from. With no policy in /etc/gai.conf, the C library prefers IPv6 to IPv4 for every destination that offers both — so a server that had been seen at its IPv4 for years starts being seen at its IPv6, and everything licensed against the address (WHMCS, Softaculous, LiteSpeed, JetBackup) starts failing its licence check. Not at the cutover: each product runs on a cached verdict for hours, so the first symptom is a licence error in the middle of the night on a server whose migration went perfectly. The cutover pins the preference back to IPv4 for you, right after the firewall goes down. If you have written your own policy into /etc/gai.conf the run leaves it alone and tells you to re-check those licences yourself.

cPanel’s Exim offers authentication on port 587 without requiring TLS first, and CorePanel installs Postfix the other way round, because requiring it is the right default for a server nobody has migrated anything onto. That difference is invisible until it isn’t: an application on the server configured to send mail unencrypted to its own host — a billing system, a WordPress plugin, a shop — simply stops sending, with an authentication error that has nothing to do with its credentials.

The cutover reads what your mail server advertises before it stops it, and configures Postfix to match. A server whose Exim allowed it keeps allowing it; one that already required TLS stays strict. Either way STARTTLS is offered, so mail clients go on encrypting, and a CorePanel server installed from scratch is unaffected.

It is a compatibility setting, not a target state. Once those applications are moved onto STARTTLS, this puts the strict default back:

Terminal window
postconf -P 'submission/inet/smtpd_tls_security_level=encrypt'
systemctl reload postfix

Three things the transformation deliberately does not decide for you, because each would cost something silently:

  • MailScanner holds mail in a spool of its own, and the cutover flushes Exim’s queue rather than that one. Let it drain and stop it before the window.
  • MailChannels relays your outbound mail by configuring Exim. Postfix takes the mail at the cutover, so from that moment the server sends directly from its own address — check your SPF and your reputation first.
  • A block-level backup agent (R1Soft, Acronis) keeps running, but its policy names cPanel’s paths. Repoint it, or the first backup after the cutover silently protects nothing.

The check asks each of this server’s own sites for its homepage, the way a visitor would, and tells you about the ones that are not working right now, before anything has been transformed:

• billing.example.com is not working right now, before anything has been
transformed: the ionCube loader is missing…
→ fix it before the cutover or accept that it stays broken afterwards

It is not scored. Nothing about a customer’s broken site makes this server harder to move, and the transformation neither causes it nor repairs it. It is reported because of what happens if nobody says it out loud: the site is still broken afterwards, the health gate at the end of the cutover finds it, and it reads as a fresh failure — over a page that was an error message before the run started.

Two kinds turn up:

  • A page that announces its own failure with HTTP 200. Encoded software — WHMCS and most billing systems — prints “the ionCube Loader needs to be installed” and stops, and PHP calls that a successful request. Nothing about the status code shows it.
  • A homepage that is a PHP error and nothing else. cPanel runs suPHP with display_errors on, so the error is the page and it is served as a 200. CorePanel runs PHP-FPM with it off, so the same fault becomes an honest 500. The site is no worse afterwards — it stops pretending to work, which is worth knowing before you see the 500 and reach for the rollback.

--no-dns turns this pass off along with the domain lookups, for when you are scanning a copy of a server rather than the live one.

CloudLinux is a blocker, and the check gives you the removal command. It is not a capability problem: the limit people buy LVE for is the entry process, and that is what corehttpd does per account — with the same 508 — alongside per-request memory and time ceilings and a global one that protects the box. See PHP Isolation and Limits.

It has to come off first for two reasons that have nothing to do with what CorePanel can host: removing it swaps the kernel and needs a reboot, so it cannot happen inside the cutover window; and CageFS shows each user a different filesystem, which makes every measurement taken under it a measurement of a server nobody serves.

Run CloudLinux’s own procedure while cPanel is still installed, then run the check again. It moves your sites off alt-php, so check each domain’s PHP version afterwards — and on CloudLinux 7 you will land on CentOS 7, which needs one more step: cPanel’s elevate, as far as AlmaLinux 9.

The score is the weighted result of those findings. It is not a marketing number: it is computed from a versioned rule set built into the binary, so it always reflects what the current CorePanel actually supports rather than what a brochure claims.

The check reports which database engine the server runs and what a transformation would do with it. There are three answers, and which one applies is decided by the engine itself:

EngineWhat happensCost
MariaDB 10.11 or neweradopted exactly where it is — same data directory, same server, same versionseconds, whatever the data size
MariaDB older than 10.11upgraded in place with mariadb-upgrade over the same data directoryminutes; nothing is copied
MySQL (any version)dumped and restored onto MariaDBthe only step whose downtime grows with the amount of data

10.11 is a minimum, not a target. CorePanel keeps its own data in SQLite and never uses MySQL — the database on a hosting server belongs to the sites. So a server already running MariaDB 11.4 or 11.8 is left on it: nothing is reinstalled, no repository is swapped, and no downgrade is ever performed. You get a note saying so, which costs no score, and the server transforms like any other.

The one direction that does not exist is backwards. MariaDB upgrades in place but never downgrades, and nothing in a transformation asks it to.

A server whose accounts belong to resellers gets a note saying so, naming each reseller and how many accounts it owns. This is not a warning, because nothing is lost: cPanel resolves an account’s direct owner and stops, so one level is the source, and each reseller becomes a CorePanel seller owning the same accounts.

Two things are worth knowing before the transformation runs:

  • The seller is created from the reseller’s name alone. It arrives with no contact email and no login — the reseller’s own contact details live in their own account’s metadata, which is not the migrating account’s to read. Give the seller both once the transformation is done.
  • If a reseller is itself owned by another reseller, a second note says the ownership is read as one level. cPanel allows that shape but does not treat it as a hierarchy anywhere, so nothing is being simplified away.

The billing system that provisions this server

Section titled “The billing system that provisions this server”

If a WHMCS has been provisioning this server over the WHM API, the check reports the credentials it finds under CARRIED OVER — and carried over is exactly what happens to them.

cPanel stores a WHM API token as its SHA-512 and never the token itself: the plaintext was shown once, at creation, and the only party that still holds it is the billing system sending it in every request. That digest is all CorePanel needs to accept the same token, so the transformation carries it across and nothing changes on the WHMCS side — no new token, no server entry to edit, and nobody here ever learns it.

The old access hash is carried too, but only where the server still honours it. cPanel turned it off by default; where allow_deprecated_accesshash is off, WHM answers Access denied to it, and importing it would mean CorePanel accepting a credential the old server refused.

The WHM API itself stays closed. Port 2087 is the most attacked port in shared hosting, so nothing opens it as a side effect — not the installer, not the transformation. When you are ready:

Terminal window
corepanel whmcompat enable # serve the WHM API on :2087 (Business)
corepanel whmcompat selftest # drive a real WHM API request and report what came back

More websites than the free edition allows

Section titled “More websites than the free edition allows”

CorePanel Personal — the free edition — hosts 20 websites. Primary and addon domains count; subdomains, parked names and aliases do not. If the check finds more than 20 it says so, and it says so here rather than as a blocker, because the way out is free and takes one command.

It matters that you see it before you start. The import registers accounts until the cap and refuses every one after it with “website limit reached for this edition” — which happens during PREPARE, with cPanel still serving and nothing lost, but it stops the transformation halfway through an evening you set aside for it.

Pro and Business have no website cap, and a 14-day trial of either is free: no card, no key. Once PREPARE has installed CorePanel and before the import runs:

Terminal window
corepanel license trial --edition business --email you@example.com

The most useful thing the check does is the .htaccess audit. CorePanel does not run Apache, so every .htaccess on the server is read and classified: rules that are compiled and applied (the WordPress and standard-CMS shapes, redirects, access rules, Basic auth), rules that are deliberately not applied and are panel settings in CorePanel instead (Header, ErrorDocument, DirectoryIndex, SetEnv, the Expires* family), and the handful that genuinely need a human — mod_security, RewriteMap, SetHandler, Action, SetEnvIf, SSI. Only the last group costs score.

The one-liner downloads the binary, runs it and removes it — that is what “leaves nothing behind” means, and it applies to the tool itself. To go further than the check, ask the same one-liner to keep it:

Terminal window
curl -fsSL https://get.corepanel.net/check | sh -s -- --install

That installs /usr/local/bin/corepanel-transform from the copy it has already downloaded and verified. --keep does the same thing and prints the check first.

Run the installed tool with no arguments and it walks the whole transformation as one guided sitting, stopping to ask before every stage:

Terminal window
corepanel-transform
Stage
1CHECKreads this server and says whether it can be transformed — read-only
2PLANwrites the ordered steps and the offline window — read-only
3PREPAREinstalls CorePanel beside cPanel; nothing goes offline
4CUTOVERthe offline window: cPanel stops, CorePanel takes over
5VERIFYproves every domain, mailbox, database and zone answers

Before each stage it prints what that stage does to this server — what goes offline and for roughly how long, the steps it runs, whether it can be reversed — and then asks. Enter goes on, q stops.

Stopping costs nothing. Every step records its outcome before the next one starts, so corepanel-transform again picks up exactly where it stopped, and a stage already finished is skipped rather than offered again. That is also what survives a dropped SSH session or a reboot.

Two stages still ask for a word to be typed, after the prompt and before anything in them runs: I-HAVE-A-BACKUP for PREPARE and TRANSFORM for CUTOVER.

The guided flow never offers to remove cPanel. cPanel stays installed and disabled after VERIFY — that is what keeps corepanel-transform rollback available — and removing it is corepanel-transform cleanup, a separate command for another day.

If you would rather drive it yourself, every stage is its own subcommand: check, plan, run --phase prepare|cutover|verify, resume, status, rollback, cleanup. The guided form refuses to run without a terminal and names those instead, so a pipeline gets the subcommands rather than a wizard answering its own questions.

By default nothing is written. To keep a copy — to read later, or to send to us with a question — ask the binary for the file:

Terminal window
corepanel-transform check --report /root/migration-report.json

report.json is written owner-only and carries counts, finding codes and domain names. It contains no password hashes, no keys, no secrets and no file contents — by construction, and there is a test in the build that fails if that ever stops being true.

Every command of the tool — the check, and each stage of a transformation — sends an anonymous summary of what it did. --no-telemetry on any of them, or COREPANEL_NO_TELEMETRY=1 in the environment, stops it:

Terminal window
corepanel-transform check --no-telemetry
corepanel-transform --no-telemetry # the whole guided transformation
COREPANEL_NO_TELEMETRY=1 corepanel-transform # the same, for a script

What is sent, in full, is on the Anonymous usage statistics page. The short version: versions, counts, finding codes, which stage ran, how long it took and which step stopped it if one did — and no hostname, domain, account name or error message, because there is no field for any of them.

The check answers with its status too, so it can be run from a script:

0The server can be transformed
2It carries a blocker; the report names it and its way out
1The check itself could not run

The shim you pipe into sh carries the SHA-256 of each published binary and checks the download against it before running anything; a mismatch aborts without executing the file. If you would rather verify by hand, read the script first — it is short, and this is exactly the kind of thing worth reading before running it as root:

Terminal window
curl -fsSL https://get.corepanel.net/check | less

Today the check answers one question: what would moving this server involve?

For moving accounts onto a CorePanel server you already have, the answer is the cPanel importer: it pulls accounts over SSH from the live WHM, or takes a staged cpmove archive, and recreates them natively while preserving passwords. That is available now, and the check’s inventory is a good way to see what it would find.

Transforming a cPanel server into a CorePanel server in place — same machine, same IPs, no data copied, seconds of downtime instead of hours — is in development. The check is the first part of it and is useful on its own: the score, the inventory and the findings are the same ones that work will act on.