Importing cPanel accounts
CorePanel can take over hosting accounts from an existing cPanel/WHM server and recreate them natively — files, mail, databases, DNS, cron and SSL — while preserving the original passwords wherever the hash scheme allows, so most users never have to reset anything.
There are two ways to run an import, and they take different inputs:
| Admin panel (UI) | CLI | |
|---|---|---|
| Input | Live pull over SSH from the source WHM | A staged cpmove/backup archive already on the server |
| Scale | One or many accounts (batch) | One account per invocation |
| DNS cut-over | Optional, automatic | Not performed |
| Progress | Live, reconnectable | Printed to the terminal |
| Best for | Migrating a whole server, hands-off | Scripting, air-gapped transfers, a single archived account |
Both paths feed the same import engine, so the scope of what gets imported and how credentials are handled is identical.
What gets imported (scope)
Section titled “What gets imported (scope)”Everything below is provisioned automatically from one cPanel account:
- System account — the Linux user, its password hash (when compatible), and optionally its original UID/GID.
- Closed logins — a mailbox or FTP account the source had locked arrives closed: it is created inactive, and the password cPanel kept behind the lock marker is preserved, so reopening it later restores the login its owner already knows instead of replacing it. These are not listed as passwords needing a reset — there is nothing to reset, and acting on such a list would reopen an access somebody deliberately shut.
- Suspension state — an account cPanel had suspended is imported suspended, with the source’s own suspension date. That is not a detail of bookkeeping: importing it active would put a site somebody deliberately took down — for non-payment, for abuse — back on the internet. Its sites serve the suspension page and its logins stay closed until you lift it, which any edition can do.
- Primary domain — virtual host, managed DNS zone and a fresh DKIM key.
- PHP version — CorePanel runs one PHP version per account (the FPM pool belongs to
the account’s system user), so the primary domain’s source version sets the account’s:
exact
X.Yif installed, otherwise the newest minor of the same major, otherwise the server default. Any downgrade is noted in the report — and so is every domain that ran a different version on cPanel, because it now runs the account’s. A site left on its old server’s default records no version at all (cPanel writesinherit), and an archive does not carry that server’s configuration — so there is nothing to read it from. Such a domain is reported by name, and the account’s version is then decided by the rule above without it: another of its domains that does name one, otherwise the newest version installed here, which can be several releases newer than the site ran. Check it after the import and move the account withcorepanel account update <account> --php <version>if it needs another one. A whole-server transform has the source server in front of it and reads the answer instead of guessing. - Secondary domains — addon domains, domain aliases (parked) and subdomains, each
with its own vhost. cPanel does not store an addon as a domain: it creates an internal
subdomain of the primary (
addon.com→addon.example.com) and keeps the real vhost under that name. CorePanel imports the addon as a first-class domain carrying that vhost’s document root, PHP version and certificate, and does not recreate the internal hostname — the report notes it rather than standing up a second site on the same files. - Domains parked on an addon — a domain parked on top of an addon rather than on the account’s main site. cPanel files it as a second addon entry pointing at the same internal subdomain, so nothing but the name says which of the two is the site. CorePanel imports it as an alias of that addon: it serves the addon’s document root and its mail is redirected there, and the report says which addon it belongs to.
- Nested subdomains — a subdomain whose prefix is more than one label
(
dev.blog.example.com), imported as it is: one vhost, one record in the zone that owns it. Note a nested name is not covered by the parent’s wildcard certificate — a wildcard spans a single label — so CorePanel issues one of its own for it. - Mailboxes — with their messages (full Maildir) and passwords preserved.
- Mail extras — forwarders, autoresponders and mail filters (translated to CorePanel’s Sieve model).
- FTP accounts — the main account plus any extra ones, passwords preserved.
- MySQL — databases with their data, plus database users (their MySQL password hash is re-applied, so app config keeps working).
- Cron jobs — installed as panel-managed cron.
- SSL certificates — cert, chain and key installed via the certificate manager.
- DNS records — parsed from the source BIND zones and merged into the new zone; A/AAAA records that pointed at the old server IP are rewritten to this server’s IP, while MX, TXT/SPF, DKIM, CNAME and CAA are preserved.
- Home directory — the full site tree, restored and re-owned (with SELinux contexts fixed).
- WordPress installations — the import ends by scanning the account it just created, so every WordPress it brought over is already listed (and manageable) in WordPress when the job finishes. cPanel has no catalog of its own to copy: the sites are found on disk, exactly as the manual Scan does.
.htaccessrules — read where they are, not converted. Permalink blocks, front controllers,Deny from allfiles and password-protected directories keep working without anything being turned on. See .htaccess Support for what is applied and what is reported instead.
Where the sites end up
Section titled “Where the sites end up”Every site keeps serving from the path it had on the source server. The importer does not move the files into CorePanel’s own layout, it re-points the vhosts at where the restored home actually put them:
| On cPanel | On CorePanel after the import |
|---|---|
~/public_html (primary) | ~/public_html |
~/public_html/addon.com (addon, cPanel nests them) | ~/public_html/addon.com |
~/public_html/blog (subdomain, named after the label) | ~/public_html/blog |
~/dl.example.com (a site edited by hand to sit beside public_html) | ~/dl.example.com |
Only the home directory prefix changes, and only when the account gets a different
username here (a name conflict on import). A site provisioned by CorePanel afterwards
uses CorePanel’s own layout — ~/domains/<name> — but nothing already imported is
rewritten to match it.
This matters because absolute paths are baked into the sites themselves: wp-config.php,
compiled caches, .htaccess include paths, and the cron jobs the importer restores
alongside them. Moving the tree would break all of those silently. CorePanel instead
extends the two things that make a directory servable — its SELinux file context and the
PHP pool’s open_basedir — to cover the imported path.
What is not imported
Section titled “What is not imported”This is a one-shot import, not a two-way sync, and it only reads cPanel archives:
- Other panels (Plesk, DirectAdmin) — cPanel only.
- The cPanel reseller tree — you decide which CorePanel seller each account belongs to. Its package is resolved for you from the plan name when a package of that name exists.
- cPanel-specific state with no CorePanel equivalent —
cpbackupjobs, Softaculous installs, cPanel API tokens. - A mailbox on a domain that has no mail identity on this server (e.g. a mailbox under an alias or a subdomain) — it is reported as dropped, never silently lost.
- Per-domain PHP versions — CorePanel gives the whole account one version (see above). An addon still running an older PHP on cPanel moves onto the account’s version, and the report names every domain this affects so you can check those sites first. The account’s version can be changed afterwards if the importer’s choice turns out to be the wrong one.
How passwords are preserved
Section titled “How passwords are preserved”CorePanel imports the original password hashes verbatim whenever they can be verified later — no plaintext is ever needed or shown.
| Credential | Preserved when the hash is… | Otherwise |
|---|---|---|
| System / SSH / main FTP | SHA-512 $6$, SHA-256 $5$, MD5 $1$, bcrypt $2a/2b/2y$, yescrypt $y$ | Random password set, reset required |
| Mailbox & extra FTP | Same crypt families as above | Random password set, reset required |
| MySQL users | mysql_native_password / caching_sha2_password (re-applied at the MySQL layer) | — |
The system login is the strictest case: RHEL’s crypt(3) verifies the hash at SSH/FTP
login, so a scheme it can’t check (e.g. argon2) is treated as non-preservable — the account
gets a random password and is flagged for a reset, rather than becoming an account that can
never log in. When a credential can’t be preserved, the login still exists — the user
just has to set a new password. Those users are listed under Password resets required in
the report.
Procedure — Admin panel (live pull over SSH)
Section titled “Procedure — Admin panel (live pull over SSH)”Open Migration → Import account from cPanel in the panel. The import runs entirely on the CorePanel server, so you can close the browser and reconnect to it later.
1. Connect to the source server
Section titled “1. Connect to the source server”Enter the source WHM/cPanel hostname or IP, the SSH port, and root SSH credentials. The password is used only for the connection and is never stored.
2. Select the accounts
Section titled “2. Select the accounts”CorePanel lists every account on the source server with its primary domain, plan and disk usage. Verify the server’s host-key fingerprint matches the real source, search/filter, and tick one or many accounts (Select all acts on the current filter). Suspended accounts are flagged.
3. Choose options
Section titled “3. Choose options”-
Target hosting package — pick one to attach every imported account to it. Leave it unset and CorePanel resolves each account’s own cPanel plan by name, so accounts that came from different plans land on the matching CorePanel packages instead of all on one.
Either way, the limits an account arrives with are the ones the source recorded for that account — disk, bandwidth, mailboxes, databases, FTP, aliases, subdomains and addon domains — not the package’s. Both panels copy limits into the account when it is created and let you edit a single account afterwards, so an account whose database limit was raised by hand keeps the number it was running under. The package only supplies what the source left unsaid. Applications are the exception: cPanel’s Passenger limit is a different product, so imported accounts get no applications until you grant them.
-
Preserve UID / GID (recommended) — keep the source system user/group ids for a full-fidelity migration.
-
Point DNS to this server — when each account finishes, CorePanel logs into the source server (still authoritative during the switch) and repoints only the A records that pointed at the old IP, so live traffic follows the migration without waiting for a registrar change. Domains whose DNS lives elsewhere are left untouched and flagged as external.
-
If the account or domain already exists — Abort (fail) or Skip (do nothing).
4. Review and start
Section titled “4. Review and start”Confirm the summary and start. Accounts are imported one at a time on the server.
5. Watch live progress
Section titled “5. Watch live progress”Each account shows a phase tracker (Connect → Transfer → Restore → Done), the transfer size, a live count of created / reset / deferred / dropped / failed resources, and the full per-resource log. The import keeps running on the server if you navigate away — reopen the page and pick it up from Recent imports.
Procedure — CLI (from a staged archive)
Section titled “Procedure — CLI (from a staged archive)”Use the CLI when you already have a cpmove-<user>.tar.gz / backup-*.tar.gz archive (or
an extracted account directory). The archive path is resolved on the CorePanel server,
so stage it there first — the conventional location is /var/lib/corepanel/import/.
Preview first (--dry-run)
Section titled “Preview first (--dry-run)”A dry-run parses the archive and prints the plan — resource counts, credential compatibility, conflicts and warnings — without touching the system:
corepanel account import /var/lib/corepanel/import/cpmove-acme.tar.gz --dry-runcPanel import preview (dry-run)==============================Source: cpanel 110.0.5 @ web-oldhost-01.example.netAccount: acme (uid 1042, gid 1042)Domain: acme-store.comPlan: businessContact: admin@acme-store.com
Resources: domains=5 mailboxes=8 forwarders=4 databases=2 db-users=2 dns-records=27 ftp=3 cron=1 certificates=1
Credentials: system password: preserved mailbox/ftp: 9 preserved, 2 reset (of 11)
Domains: - acme-store.com primary [ssl] - shop.acme-store.com subdomain - dev.shop.acme-store.com subdomain - acme-labs.io addon - acme-labs.net alias of acme-labs.io
Conflicts: noneRun the import
Section titled “Run the import”corepanel account import /var/lib/corepanel/import/cpmove-acme.tar.gz \ --package 3 --preserve-uid --report /root/import-acme.jsonFlags:
| Flag | Purpose |
|---|---|
--dry-run | Parse and validate only; print the plan and touch nothing |
--seller <id> | Target seller id (default: the primary seller) |
--package <id> | Target hosting package; its limits drive the account |
--preserve-uid | Keep the source UID/GID via useradd -u/-g |
--on-conflict abort|skip | Policy when the user/domain already exists (default abort) |
--report <path> | Write the full JSON import report to this path |
The command prints the per-resource result and exits non-zero if the job status is
failed, so it fits cleanly into migration scripts:
cPanel import=============Job: #42Status: partialAccount: acme (id 17)Domain: acme-store.com
Resources: [created ] account:acme — system password preserved ($6$) [created ] domain:acme-store.com — primary domain, vhost and managed DNS zone [created ] mailbox:sales@acme-store.com — mailbox password preserved [reset ] mailbox:old@acme-store.com — mailbox password could not be preserved; a reset is required [created ] db:acme_shop — database restored
Password resets required (1): ! old@acme-store.comA running or finished job can also be polled with core.GetImportJob and listed with
core.ListImportJobs — the same jobs the panel’s Recent imports shows.
Reading the report
Section titled “Reading the report”Each resource ends in one of these states:
| Status | Meaning |
|---|---|
| created | Imported successfully, credential preserved |
| reset required | Imported, but the password couldn’t be preserved — the user must set a new one |
| deferred | Recognized and handled in a later phase (not lost) |
| dropped | Permanently not imported (e.g. a package limit was hit, or a mailbox with no mail identity here) |
| skipped | Already existed, or skipped by the conflict policy |
| failed | An error occurred provisioning this resource |
The overall job is completed only when every resource is created/deferred with no
forced resets; any reset, dropped or failed resource makes it partial.
Warnings sit beside those statuses and can also downgrade a job to partial — an
unmapped document root (see Where the sites end up) does,
because the domain exists but its site is not serving.
After the import
Section titled “After the import”- Hand out password resets. Everyone listed under Password resets required has a working login but a randomized password — send them a reset.
- Check DNS. If you didn’t use Point DNS to this server, update the A records (or the registrar’s nameservers) so the domains resolve to CorePanel. Domains flagged external always need a manual change.
- Verify the account. Confirm the site serves over HTTPS, mail authenticates
(STARTTLS + IMAP login), and the databases contain their data. An account that
arrived suspended is the exception: its site correctly shows the suspension
page and none of its logins work. The report says so, and the accounts list badges
it — lift the suspension if it
should be serving.
The report’s wordpress line says how many installations were cataloged; if it reads
deferred, the scan could not run — the sites are unaffected, run
corepanel wp scan <account>to list them. - Re-run if needed. Imports are idempotent — re-running against an existing imported account resumes only the missing resources; it never duplicates them.