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.
- Primary domain — virtual host, managed DNS zone and a fresh DKIM key.
- PHP version — the source per-domain version is matched to an installed one:
exact
X.Yif present, otherwise the newest minor of the same major, otherwise the server default (any downgrade is noted in the report). - Secondary domains — addon domains, domain aliases (parked) and subdomains, each with its own vhost.
- 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).
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 map each account to a CorePanel seller/package yourself.
- 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.
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 — its limits (disk, mailboxes, databases…) are applied to the imported account. Leave as Default for unlimited/server defaults.
- 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=3 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 - acme-labs.io addon
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.
- Re-run if needed. Imports are idempotent — re-running against an existing imported account resumes only the missing resources; it never duplicates them.