- Apply step prints an explicit post-migration cleanup hint with the correct
uapi Mysql delete_database/delete_usercommands and the path of the source docroot to remove manually after validation. - New entry #17 in TROUBLESHOOTING.md documenting the orphan database metadata
issue that occurs when operators use
mariadb -e "DROP DATABASE"directly on the source instead of the cPanel API, leavingdbindex.db.jsonwith ghost entries that break JetBackup anduapi Mysql list_databases.
- Full record-level DNS diff after restore with automatic retry (up to 3 passes).
- Detection of the active DNS backend (PowerDNS vs BIND) for correct reload.
- External MX banner probe after Exim routing reconfiguration.
--verifynow compares the live zone against the pre-migration JSON snapshot.- Final DNS reconciliation pass after AutoSSL / httpd rebuild, catching late cPanel regenerations.
- Extensive header documentation of the 16 known failure modes and the function that compensates for each.
- DNS zone captured as full JSON (
whmapi1 dumpzone), not just the raw.dbfile. restore_dns_custom_records()re-applies every backup record viaaddzonerecordafter the migration, with+URL-encoded as%2Bto preserve SPF values.configure_exim_routing()moves the domain to/etc/remotedomainswhen the MX is external, so Exim does not intercept mail destined for M365/Google/Mailgun/etc.- Self-MX records injected by cPanel are stripped; A records colliding with restored CNAMEs are removed before replay.
- Auto-detection of source user via
/etc/userdomains(--frombecomes optional). - MySQL DB host health check in preflight (fails fast if
wp-config.phpreferences an unreachable external DB). - Email account detection on source — warns loudly about local mailboxes that the script does NOT migrate.
php_extract_constant()ignores commented-out//define,#define,* definelines.- Subdomain children with docroot nested inside the parent are detected, avoiding redundant rsync.
- Header comments removed and neutralized for public release.
- Default behavior: auto-migrate subdomain children (
--no-substo opt out). - RDAP (for
.br) and Cloudflare DoH (for other TLDs) sanity check in preflight, detecting expired / NXDOMAIN domains. --verifymode extended to deep health check (DB login viadefaults-file, WPsiteurlvia auto-detected$table_prefix, body smoke, cert SAN coverage).- Batch mode (
--batch-file=<path>) with consolidated Markdown report. - Smoke test switched from HEAD to GET with body error-signature matching.
- AutoSSL active wait loop with automatic LiteSpeed reload when the new cert is detected.
- DB password generator uses only
[A-Za-z0-9_]with aCpMigr_prefix to avoid URL-encoding issues inwhmapi1/uapiarguments. db_login_test()runs after DB creation; if login fails, the password is reset viauapi Mysql set_passwordand re-tested before the script continues.
- Initial release:
--dry-run,--apply,--verify, idempotent step sequence. whmapi1_must_succeed()parsesmetadata.resultfrom JSON responses (the CLI exit code is unreliable).- Dynamic DB prefix discovery via
uapi Mysql get_restrictions. - DNS zone backup (raw
.db+ JSON dump). - Correct sequence: delete source BEFORE create destination (cPanel rejects simultaneous ownership).
- rsync with
--backup-dirto preserve destination files that would be overwritten. wp-config.phpsed patch accepting single or double-quotedefine()syntax, with re-extraction verification.