Email, websites, and databases, plus the domains they need. No root. No WHM. The old host is never touched.
Quick start · Why · Safety · Docs
Moving away from a cPanel host should not require root access, WHM access, a paid
migration ticket, or a weekend of manual rsync, mailbox repair, SQL dumps, and
DNS guesswork.
cPanel Self-Migration gives account owners, freelancers, and small hosting teams a repeatable way to move an account with only normal cPanel SSH credentials. It previews first, writes only to the destination, and verifies the result after the copy.
| Built for | What it means |
|---|---|
| Account owners | Move your own cPanel account without waiting on support. |
| Agencies | Repeat the same migration process across many small client accounts. |
| Host changes | Copy mail, sites, databases, and missing domains into a new cPanel account. |
| Low-risk cutovers | Dry-run first, apply later, verify before DNS cutover. |
| Area | What is handled |
|---|---|
| Mailboxes, folders, messages, password hashes, UIDs, and UIDVALIDITY. | |
| Websites | Full docroots streamed from source to destination. |
| Databases | MySQL data, users, grants, and supported CMS config rewrites. |
| Domains | Missing addon domains and subdomains created on the destination. |
Run everything together, migrate only one area with --mail, --file, or
--db, or narrow to a single domain (--domain) or a single mailbox
(--mailbox).
Your old host is never at risk. The SOURCE account is opened strictly read-only: the tool only reads from it and never writes to, deletes from, or modifies anything there. Every change is made on the DESTINATION, so even an interrupted or failed run cannot alter or endanger your source data.
- Source is read-only. The old host is only ever read from, never written to, deleted from, or modified, so your source data is never at risk; all writes go to the new host.
- Dry-run by default. Running
cpanel-self-migrationwith no flags previews the move and writes nothing. - Designed for retries. If a transfer is interrupted, run it again. Matching data is skipped and unfinished work continues.
- Verified after copy. Mailbox state, file trees, and database contents are
checked after migration. Use
--deep-verifyfor content-hash verification. - No server agent. The tool runs from your machine and connects over SSH to each cPanel account.
1. Install
curl -fsSL https://raw.githubusercontent.com/tis24dev/cPanel_self-migration/main/install.sh | bashThe installer downloads the latest signed release under ~/.local and adds it to
your PATH.
2. Configure
The installer already created your config from the template (as mode 600), next
to the binary:
~/.local/share/cPanel_self-migration/configs/host.yaml
Open it and fill in your source and destination cPanel SSH accounts:
src: # SOURCE, read-only
ip: "192.0.2.10"
port: 22
ssh_user: "your_cpanel_user"
ssh_pass: "********"
timeout: "10s"
dest: # DESTINATION, receives all writes
ip: "198.51.100.20"
port: 22
ssh_user: "your_cpanel_user"
ssh_pass: "********"
timeout: "10s"The binary finds this config next to itself, so you can run it from any directory.
(Building from source instead? Copy configs/host_template.yaml to
configs/host.yaml and chmod 600 it.)
3. Preview
See what would move without changing either account:
cpanel-self-migration4. Apply
When the preview looks right, migrate to the destination:
cpanel-self-migration --applyFor byte-level verification, run:
cpanel-self-migration --apply --deep-verifyThe tool is built around a simple rule: the source account is never the write target. The migration is a one-way flow from source to destination.
- Signed releases. Release artifacts are signed with ECDSA P-256 + SHA256 and ship with a CycloneDX SBOM.
- Secret-aware logging. Normal logs avoid secret values, and debug response logging redacts secret-shaped fields.
- Host-key protection. Unknown SSH host keys are accepted once and recorded; changed keys are rejected.
- CI coverage. The project runs unit tests, integration tests, race tests, CodeQL, govulncheck, GoSec, and dependency review in GitHub Actions.
cpanel-self-migration --apply --mail
cpanel-self-migration --apply --file
cpanel-self-migration --apply --db
cpanel-self-migration --apply --domain example.com # one domain (docroot + mail, no DB)
cpanel-self-migration --apply --mailbox [email protected] # one mailbox (copy + verify)
cpanel-self-migration --apply --deep-verify
cpanel-self-migration --apply-mirror --mail
cpanel-self-migration --config /path/to/host.yaml
cpanel-self-migration --version
and moreFull flag reference: docs/COMMAND.md. Cutover procedure and exit codes: docs/USAGE.md.
What happens, step by step
- Connect to source and destination.
- Analyze and compare the selected data source-to-destination, classifying
mailboxes, website docroots, and MySQL databases as
IDENTICAL / DIFFERS / TO MIGRATE into
logs/*_analysis.log. --apply: create domains. SRC domains missing on DEST are created as addon / subdomains via a temporary API token that is always revoked.--apply: migrate mailboxes. Idempotent account create/update preserving the password hash; fast-skip when count + UIDVALIDITY already match; maildir tar-streamed in batches. (--apply-mirrorinstead renames the dest mailbox aside to<user>-bakand re-copies in full, for an exact source mirror.)--apply: copy website files. Each docroot mirrored to DEST via the tar bridge (the destination docroot is emptied first, within a safety guard; an empty source backs the destination up aside instead of wiping it).--apply: migrate databases. Dumped and loaded viamysqldump | mysql, remapping the account prefix, then each site's config is rewritten to the new DB.--apply: verify each flow (mailbox count + UIDVALIDITY, docroot file count- bytes, database table/object counts) into
logs/migration_report.log.
- bytes, database table/object counts) into
Only the selected flows run. With none of --mail, --file, or --db, all flows
run. --domain DOMAIN narrows the run to a single domain (its docroot + mail,
never databases; compose with --mail/--file), and --mailbox local@domain
narrows it to a single mailbox (mail only).
Under the hood
- Native SSH. Built on
golang.org/x/crypto/ssh; no daemon or agent is installed on either server. - Streaming transfers. Web and mail data move through tar streams instead of per-file round trips.
- cPanel-aware operations. Domains, mail accounts, MySQL users, and API tokens are handled through cPanel user-level interfaces.
- CMS config rewrite. Supported site configs are rewritten to destination DB names, users, and passwords after database migration.
- Reports. Analysis and migration reports are written under
logs/.
Build and test
Build from source:
cp configs/host_template.yaml configs/host.yaml
make buildRun the local test suite:
make test
make test-raceThe tests include pure Go unit tests, golden report tests, and in-process SSH integration tests. No live cPanel host is required.
Project layout:
configs/ host.yaml (gitignored) + host_template.yaml
cmd/cpanel-self-migration CLI: flags, signal context, wiring
internal/config host.yaml loader (validated)
internal/sshx native SSH: client, pool, accept-new host keys, streaming bridge
internal/cpanel typed UAPI/api2 calls (RunUAPI[T]), domains/email/token/addon/mysql
internal/model Domain/Mailbox types + pure mapping (ActionFor, HashScheme)
internal/maildir mail: batch split, box stats, delta, tar-streaming transfer
internal/webfiles website files: docroot gather, plan, tar-streaming transfer
internal/dbmig databases: discovery, plan, mysqldump|mysql bridge, config rewrite
internal/wpconfig wp-config.php parse/rewrite (DB credentials)
internal/phpserialize minimal PHP unserialize (Softaculous registry)
internal/validate permissive path/identifier sanity checks
internal/logx progress logger (steps, colors, progress bar, debug)
internal/report analysis + migration_report renderers (mail / web / db)
internal/migrate orchestration of the migration phases
internal/version build metadata (injected via ldflags at release)
CI/CD and releases
The repository uses GitHub Actions for tests, coverage, race testing, CodeQL, govulncheck, GoSec, dependency review, Dependabot, and the governed release flow. Releases are built with GoReleaser and published with checksums, SBOM, signature, and provenance metadata.
- docs/USAGE.md: full setup, modes, cutover procedure, exit codes
- docs/COMMAND.md: complete flag reference
If this tool saved you a migration headache, consider supporting its development
Released under the MIT License.