Skip to content
Pre-release. HostCraft is in testing and not yet for sale. These docs describe the current build and may change. Join the waitlist to hear when it launches.

cPanel Cutover

This runbook is the step-by-step procedure for moving one customer account from cPanel to HostCraft. It mirrors the Migrating from cPanel overview page but is written for the operator carrying out the migration, with exact commands and checkpoints.

Run this procedure once per account. Large-scale migrations execute this runbook for each account in dependency order.

Before starting, confirm all of the following:

  • You have a cpmove-<user>.tar.gz backup downloaded from the cPanel server. Generate it via:
    Terminal window
    # On the cPanel server
    /scripts/pkgacct <username>
    # Then download from /home/<username>/cpmove-<username>.tar.gz
  • The target plan on HostCraft exists with sufficient disk quota, mailbox limit, and DB limit for this account.
  • No domain collision: the account's primary domain and addon domains are not already present on the HostCraft server. Check:
    Terminal window
    hostcraftd domain list | grep example.com
  • You have at least 2x the account's disk size free on the HostCraft server.

Via the panel: Admin -> Restore -> Upload backup -> select the cpmove-*.tar.gz file.

Via the API:

Terminal window
curl -X POST https://panel.example.com/api/v1/restore/upload \
-H "Authorization: Bearer $HOSTCRAFT_TOKEN" \
-F "file=@/path/to/cpmove-username.tar.gz"

The API returns a restore_id you will use in subsequent steps. Note it down.

Run the restore in probe mode first. This parses the archive, maps cPanel concepts to HostCraft entities, and returns a preview with any flags raised. Nothing is applied to the system.

Terminal window
curl -X POST https://panel.example.com/api/v1/restore/probe \
-H "Authorization: Bearer $HOSTCRAFT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"restore_id": "<restore-id>"}'

Review the probe output carefully. The daemon flags 14 categories of edge cases. For each flag, decide the handling option:

Edge case What it means Common option
PHP version unavailable The account used PHP 5.6 or 7.0-7.3 Enable legacy mode on the plan, or snap to nearest supported version
Complex .htaccess directives Rules the nginx translator could not convert Review flagged rules manually after restore
Custom MX (Google Workspace, etc.) MX records point elsewhere Preserve exactly as-is, confirm with customer
mbox mailbox format Dovecot uses Maildir; mbox will be converted Conversion is automatic; no action needed
Incompatible password hashes Hash algorithm not portable A password-reset email will be sent to mailbox owners
External DNS (NS diverge) Domain resolves through Cloudflare, etc. Record export only; do not take DNS authority
Custom SSL certificate Uploaded cert (not AutoSSL) Import or re-request from Let's Encrypt
Apache Include directives Included config files Best-effort translate; complex ones are flagged for manual review
mod_security custom rules Custom WAF rules Default OWASP CRS only in v1; flag for customer notification
Per-account php.ini Custom PHP settings Translated to per-pool php_admin_value automatically
Quota exceeds plan Account disk use is over the target plan's limit Upgrade the plan or clean up data before restoring
Catch-all email cPanel catch-all mailbox Mapped to HostCraft catch-all automatically
Nested subdomain on addon Complex subdomain hierarchy Flattened; original hierarchy recorded in metadata
MariaDB vs MySQL collation mismatch Collation differences Imported with explicit charset and collation; log diffs reviewed

Set your chosen options as JSON flags to pass to the restore step.

Once the probe looks clean:

Terminal window
curl -X POST https://panel.example.com/api/v1/restore/run \
-H "Authorization: Bearer $HOSTCRAFT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"restore_id": "<restore-id>",
"options": {
"php_fallback": "snap",
"ssl": "letsencrypt",
"mail_password_reset": true
}
}'

This starts a workflow saga in the background. Watch progress in the panel:

Admin -> Restore -> the restore job -> workflow steps.

Or tail the daemon log:

Terminal window
journalctl -u hostcraftd -f | grep "restore"

The workflow covers: account creation, unix user, PHP-FPM pool, nginx vhost, file extraction, database import, DNS zone import, mailbox creation, SSL issuance, cron jobs, and per-site validation probes. Compensations run automatically if any step fails.

Do not cut DNS yet. The account is now on HostCraft but DNS still points to cPanel. This is intentional.

With both servers live, compare the output of the old and new server on the same URLs.

Run a curl comparison on the homepage and five key pages:

Terminal window
# Replace OLD_IP and NEW_IP with the actual IPs; send Host header to target the right vhost
OLD_IP="203.0.113.10"
NEW_IP="198.51.100.20"
DOMAIN="example.com"
for path in "/" "/about/" "/contact/" "/products/" "/shop/"; do
echo "--- $path ---"
echo "OLD:"
curl -s -o /dev/null -w "%{http_code} %{size_download} bytes" \
--resolve "${DOMAIN}:80:${OLD_IP}" "http://${DOMAIN}${path}"
echo ""
echo "NEW:"
curl -s -o /dev/null -w "%{http_code} %{size_download} bytes" \
--resolve "${DOMAIN}:80:${NEW_IP}" "http://${DOMAIN}${path}"
echo ""
done

Accept the restore as correct when:

  • HTTP status codes match.
  • Response sizes are within 10% (differences in minification are acceptable; large discrepancies need investigation).
  • No 5xx errors on the new server.

Also confirm:

  • Database-driven pages load correctly (product listing, user login if applicable).
  • SSL works: curl -v --resolve "${DOMAIN}:443:${NEW_IP}" "https://${DOMAIN}/" shows a valid chain.
  • Mail send works from a test mailbox on the new server (use hostcraftd mail test --account=<id>).

Once you are satisfied the new server is correct, lower the TTL on the domain's DNS records to 5 minutes. Do this on the source DNS (wherever the domain currently resolves, usually the cPanel server's DNS or an external registrar).

Wait for the existing high TTL to expire before proceeding. If the current TTL is 3600 seconds (1 hour), wait 1 hour after lowering it before cutting DNS.

Update the A record (and AAAA if applicable) to point to the HostCraft server's IP.

If the domain's DNS is managed by HostCraft after the restore (i.e., NS records point here), the panel manages this automatically. Otherwise, update the records at the external DNS provider.

Confirm propagation:

Terminal window
dig example.com A +short
# Should return the HostCraft IP

Mail in transit at cutover time may deliver to the old server. Monitor both:

Terminal window
# Postfix queue on the new server
postqueue -p
hostcraftd mail queue
# Watch for bounces or deferrals
journalctl -u postfix -f | grep -E "bounce|deferred|reject"

Alert on:

  • Any hard bounces from the new server (configuration problem).
  • Sustained deferrals from a specific receiving domain (reputation issue on the new IP, see IP Warmup).
  • Missing mail that should have arrived (check if the old server is still receiving; that is normal for up to 24 hours while DNS propagates).

Step 8: Keep the cPanel source live for 7 days

Section titled “Step 8: Keep the cPanel source live for 7 days”

Do not decommission the cPanel source immediately. Leave it running for 7 days as a fallback. Reasons:

  • Some DNS resolvers cache longer than the TTL.
  • If the customer reports a critical issue on HostCraft that cannot be fixed quickly, you can cut DNS back to cPanel while you investigate.
  • Mail that queued before cutover may arrive at the old server for up to 24 hours.

During the 7-day window, check the old server's mail queue periodically to ensure it empties cleanly.

After 7 clean days (no reported issues, old mail queue empty, DNS fully propagated):

  1. Disable the cPanel account on the source server (suspend, do not delete yet).
  2. Take a final backup of the cPanel account for archival.
  3. Delete the account from cPanel after confirming the backup was taken.

The account is now fully on HostCraft.

If a critical problem is found after DNS cutover and it cannot be fixed quickly:

  1. Change DNS back to the old cPanel IP. Because the TTL is already at 5 minutes, most users will see the change within 5 minutes.
  2. Diagnose and fix the issue on the HostCraft side.
  3. Re-run the side-by-side comparison (Step 4) before cutting over again.

The cPanel account is safe for 7 days specifically to enable this rollback. After that window closes, rollback is not possible without restoring from the archival backup.