cPanel's Transfer Tool supports cPanel, Plesk, and a handful of legacy panels — but not
DirectAdmin. Every DA-to-cPanel migration is a hand-rolled job built from DA's admin
backup format, rsync, and whmapi1. There is no first-party converter and the
community scripts that exist are unmaintained enough that you should not point them at
production without testing on one account first.
This guide is the working sequence used for migrations in the 20–200 account range. It assumes you have root on both boxes, a fresh cPanel server with a valid cPanel license attached, and 48 hours of TTL room on your DNS.
Pre-flight on the cPanel side
Provision the target before you touch DirectAdmin. If you do not have a host yet, follow the cPanel VPS install guide — it bakes in the hostname, FQDN, and firewall steps that the WHM installer will otherwise refuse on.
Sanity-check four things on the new server:
df -h /home # 1.5x source /home usage, minimum
mysql --version # match or exceed source MySQL/MariaDB major
/usr/local/cpanel/bin/whmapi1 installed_versions | grep -E 'php|cpanel'
firewall-cmd --list-services # 80, 443, 2083, 2087 open
The MySQL major version match matters. DirectAdmin defaults to MariaDB 10.6 on most
installs since 2023; if your cPanel target ships MariaDB 10.5, recreate the dumps with
--compatible=mariadb105 or upgrade the target first. Mismatched majors silently break
utf8mb4_0900_ai_ci collations that DA's WordPress installs use.
Install matching PHP versions through EasyApache 4 ahead of time. If DA serves any domain on PHP 7.4 or 5.6, plan to use CloudLinux hardened PHP for legacy versions on the cPanel side — upstream PHP 7.4 has been EOL since 2022.
Inventory the DirectAdmin side
SSH to the DA box as root and dump the user list:
ls /usr/local/directadmin/data/users/ > /root/da-users.txt
wc -l /root/da-users.txt
For each user you need: primary domain, addon and sub domains, mailbox count, database
count, and package quotas. The user.conf file at
/usr/local/directadmin/data/users/USER/user.conf has the first three. Database names
are in mysql.conf. This inventory is what you reconcile against after restore — keep
it.
Generate DA admin backups
DirectAdmin's admin backups are tarballs containing user.conf, a Maildir tree, MySQL
dumps, and a home_dir.tar.gz. Trigger them from the CLI rather than the UI — the UI
times out on accounts over a few GB.
cd /usr/local/directadmin
echo "action=backup&local_path=/home/admin/admin_backups&owner=admin&type=admin&users=all&when=now&where=local&value=multiple" > data/task.queue
./dataskq d800
Watch /var/log/directadmin/system.log for completion. One .tar.gz per user lands
in /home/admin/admin_backups/. For very large accounts (>20 GB), back up the home
directory separately with rsync and use the DA backup only for metadata and mail —
DA's home_dir tar is single-threaded and slow.
Pull backups to the cPanel server
mkdir -p /home/_inbound
rsync -avP --bwlimit=50000 root@da.example.com:/home/admin/admin_backups/ /home/_inbound/
The --bwlimit keeps the source server's outbound link from saturating during business
hours. Drop it for the overnight final sync.
Restore strategy: rebuild then graft
cPanel's restorepkg will not read a DA tarball, so the working pattern is to create
the account empty on cPanel, then graft the DA contents on top.
Create the cPanel account
whmapi1 createacct username=acme domain=acme.example.com \
plan=default password="$(openssl rand -base64 18)" \
contactemail=ops@acme.example.com \
ip=n hasshell=n
Use a temporary password — you will reset it from the DA user.conf (see below) or
issue a customer-facing reset. Use plan=default first, then map DA packages to WHM
packages in a second pass with whmapi1 changepackage.
Restore the home directory
Extract the DA tarball to a scratch path:
mkdir -p /home/_inbound/extracted/acme
tar -xzf /home/_inbound/acme.tar.gz -C /home/_inbound/extracted/acme
The home_dir is a nested tar. Unpack it directly into the new cPanel home, preserving ownership:
tar -xzf /home/_inbound/extracted/acme/backup/home_dir.tar.gz \
-C /home/acme/ --strip-components=2
chown -R acme:acme /home/acme/public_html /home/acme/domains
cPanel uses /home/USER/public_html as the primary docroot; DA uses
/home/USER/domains/DOMAIN/public_html/. For the primary domain, copy the contents of
domains/PRIMARY/public_html/ into /home/acme/public_html/. Addon and sub domains
work as-is under /home/acme/.
Restore databases
DA dumps databases per-user under backup/USER/. cPanel expects the USER_ prefix
already in place:
for sql in /home/_inbound/extracted/acme/backup/acme/*.sql; do
dbname=$(basename "$sql" .sql)
whmapi1 create_database name="acme_${dbname}" user=acme
mysql "acme_${dbname}" < "$sql"
done
Grant the cPanel DB user on each database with whmapi1 set_privileges_on_database.
Then rewrite any wp-config.php, configuration.php, or .env files with the new
acme_ prefix — DA's prefix scheme is USER_dbname too, but the user value differs
across versions, so do not assume.
Restore mail
DA stores mailboxes under /home/USER/imap/DOMAIN/MAILBOX/Maildir/ on modern versions
and /home/USER/Maildir/ on pre-1.60 installs. cPanel uses
/home/USER/mail/DOMAIN/MAILBOX/{cur,new,tmp}/. Both are Maildir, so content moves
cleanly with rsync, but the path translation is per-mailbox:
for box in /home/_inbound/extracted/acme/backup/email/data/imap/*/*; do
domain=$(basename $(dirname "$box"))
mailbox=$(basename "$box")
mkdir -p "/home/acme/mail/${domain}/${mailbox}"
rsync -a "${box}/Maildir/" "/home/acme/mail/${domain}/${mailbox}/"
done
chown -R acme:acme /home/acme/mail
Recreate the mailbox accounts in WHM with whmapi1 add_pop so cPanel writes its own
shadow file.
Recreate DNS
DA's zone files at /var/named/DOMAIN.db are BIND-format and import directly:
scp da.example.com:/var/named/acme.example.com.db /tmp/
whmapi1 add_zone_record zone=acme.example.com \
name=mail.acme.example.com type=A address=192.0.2.10 ttl=300
Loop the add_zone_record calls from the parsed BIND file. Verify with
dig @localhost acme.example.com ANY before the cutover.
Cutover
Lower TTL on the DA-hosted zones to 300 seconds 48 hours before cutover. Run a final
rsync of /home/_inbound/ and a final mail-only restore the night of. Flip
nameservers or A records, then watch /usr/local/apache/logs/access_log on the cPanel
side for the first hits.
Run AutoSSL across all accounts immediately — AutoSSL failure modes covers what to do when the DCV checks fail on domains still resolving to DA.
Common gotchas
- Cronjobs live in
/usr/local/directadmin/data/users/USER/cron.conf, not in the user's home. Extract and feed tocrontab -u USERon cPanel. - Custom Apache vhost includes in DA's
custom_httpdtemplates do not map to EasyApache 4. Translate to cPanel'suserdatainclude system manually. - Mailing lists: DA uses Majordomo by default; cPanel uses Mailman. There is no clean converter — export subscriber lists and re-import.
- SSL certificates: copy from
/usr/local/directadmin/data/users/USER/domains/*.certinto WHM's SSL Storage Manager, or skip and let AutoSSL re-issue on cutover.
Does cPanel have a DirectAdmin importer?+
How long does a DirectAdmin to cPanel migration take?+
Can I run DirectAdmin and cPanel on the same server?+
Will email passwords survive the migration?+
Do I need a new cPanel license for the target server?+
Next steps
- WHM Transfer Tool for cPanel-to-cPanel moves — the easy path once you're inside the cPanel ecosystem.
- cPanel license tiers explained — match your account count to the right SKU before cutover.
- AutoSSL failures and how to fix them — the first thing that breaks post-cutover.