Migration

Updated Oct 5, 2026 Markdown

Imports accounts over SSH from cPanel or DirectAdmin, the two sources measured end to end. The wizard also detects Plesk, HestiaCP, CyberPanel, CloudPanel and CWP on the source server, and it can import from another WHost server through that server's API (no SSH); those sources have not been measured yet and migration is experimental in the beta (see Known Limitations). An import from another WHost server writes the account's public_html (replaced) and mail (merged) through directory handles as the account's user — also when the account already exists here: a link the account placed at public_html is replaced by a plain folder, a link at mail makes that account's import fail rather than being written through. The panel follows each job by polling its status; the API also offers the progress as an SSE stream (GET /migration/status/{job_id}/stream).

1Source server credentials (SSH host, port, root/sudo user, password or key)
2Scan — agent pulls the account list and lets the operator pick which to migrate (filter by domain pattern)
3Start — per account, in this order: create the account here, copy the files (.htaccess rules checked, LSCache detected), the databases and the mailboxes (each can be skipped), then cron jobs and FTP accounts. SSL certificates are not carried over — issue them again here (see the FAQ)
4Follow the job until every account is finished or failed
5Cut-over — check the sites and mail here, then point the domains' DNS at this server; no DNS records are exported or compared for you

Failed accounts can be retried while the scan's SSH credentials are still in memory; accounts that finished are not run again. An agent restart does not resume a running job: it is marked failed ("Server restarted during migration") and the credentials are gone, so scan the source server again before retrying (400 MIGRATION_CREDENTIALS_EXPIRED otherwise). SSH credentials are AES-encrypted in memory and zeroed after the job completes.

Boundaries the transfer keeps. The source server's SSH host key is pinned on first use (/var/lib/whost/migration_known_hosts); a later mismatch aborts the connection with the fingerprint in the message. Files and mailboxes are unpacked on this server as the migrated account's own user, so nothing the source archive contains can reach outside what that account may already write. Only databases named inside the account's own prefix (<username>_*) are created locally; a source that reports any other name is skipped with a warning. Their dumps are imported the way a backup restore imports them — by the account's import user, which can write to the account's own databases only (see Backups — scope and settings): a dump that names another database is refused at that statement and the agent log names the database. The private/loopback/link-local address ranges are refused as a source host.

Restoring from an uploaded backup file is not available. Migrate over SSH with the steps above. The panel has no Upload tab, and POST /migration/upload and POST /migration/upload/restore answer 409 MIGRATION_UPLOAD_RESTORE_UNAVAILABLE without keeping the file.

API endpoints: POST /migration/scan, GET /migration/scan/{job_id}, POST /migration/start, GET /migration/status/{job_id}, GET /migration/status/{job_id}/stream (SSE), POST /migration/cancel/{job_id}, POST /migration/retry/{job_id}, GET /migration/history, GET /migration/history/{job_id}.

Still Need Help?

Our support team is here around the clock for anything you can't find above.