Skip to content

DirectAdmin in 2025: The Lightweight cPanel Alternative

A client of mine ran 40 cPanel servers for a mid-sized shared hosting operation. In 2023, their licensing bill crossed $18,000/year — for accounts that were 80% idle WordPress sites. When I asked what features they actually used, the answer was “DNS, mail, PHP-FPM, and backups.” That’s it. They were paying enterprise-tier money for a control panel whose feature surface they touched maybe 10%.

They migrated to DirectAdmin over six weeks. Their licensing cost dropped to roughly a third. Nothing broke that mattered.

This guide is for sysadmins, hosting operators, and infrastructure engineers who are tired of the control panel tax and want a panel that gets out of the way. By the end, you’ll understand DirectAdmin’s architecture, know how to install and harden it properly, and have a realistic migration plan from cPanel or Plesk.

  • A clean server (AlmaLinux 9, Rocky 9, Debian 12, or Ubuntu 22.04/24.04) with at least 2GB RAM
  • Root SSH access and a valid DirectAdmin license key
  • Familiarity with systemd, firewalls, and the LAMP/LEMP stack
  • A staging box you can destroy without consequences

Since the Oakley Capital acquisition, cPanel moved to per-account pricing and the industry collectively groaned. Plesk went the other direction — tiered editions where every useful feature is an extension you pay extra for. Both are fine products. Both are also priced like you’re running a Fortune 500 datacenter when you’re running a VPS with 30 WordPress sites.

cPanel’s per-account model means a server with 1,000 accounts costs vastly more than one with 50, even though the resource footprint is nearly identical. Plesk’s “Web Admin Edition” doesn’t include the features most people actually want, so you upgrade to “Web Pro” and then buy extensions. DirectAdmin, by contrast, has kept flat per-server pricing and — as of this writing — still offers lifetime licenses through resellers if you look.

Here’s a rough licensing comparison. Prices change; verify against vendor sites before budgeting.

AccountscPanel (approx.)Plesk Web Pro (approx.)DirectAdmin
50~$25/mo~$20/mo~$15/mo
200~$45/mo~$20/mo~$15/mo
1000~$100+/mo~$20/mo~$15/mo

Plesk’s flat pricing is its advantage. DirectAdmin’s advantage is that it’s flat and cheaper, with a smaller resource footprint. On identical hardware, typical idle RAM for the control panel daemon alone runs roughly:

Terminal window
# Snapshot of control panel daemon memory on a freshly-booted box
ps aux --sort=-rss | grep -E 'directadmin|cpanel|sw-engine' | awk '{print $6/1024 " MB\t" $11}'

In testing, DirectAdmin’s core daemon typically sits under 30 MB RSS. cPanel’s stack (cpsrvd, cpanel-php-fpm, various Perl workers) commonly runs 300–500 MB. Plesk’s sw-engine plus sw-cp-server lands in the 200–400 MB range. That difference matters on a 2GB VPS.

Disk footprint is similarly lopsided. du -sh /usr/local/directadmin typically reports under 200 MB; cPanel’s /usr/local/cpanel regularly exceeds 1 GB.

Q: Is DirectAdmin actually cheaper at scale? Yes — for pure licensing, at 200+ accounts the savings are usually 50–70% versus cPanel’s per-account model. The catch is that you’re trading vendor support maturity and ecosystem depth for that savings.

Understanding what DirectAdmin is explains why it behaves the way it does. It’s a single daemon written in C++, not a sprawl of Perl scripts and PHP workers pretending to be one system.

The directadmin binary is the control plane. It listens on port 2222, exposes a task queue, and shells out to system tools. There’s no “cPanel PHP-FPM pool for the panel itself.” The service model is boring, and boring is a feature.

Terminal window
systemctl status directadmin --no-pager

Output looks roughly like:

● directadmin.service - DirectAdmin Web Control Panel
Loaded: loaded (/etc/systemd/system/directadmin.service; enabled)
Active: active (running) since Mon 2026-09-21 09:14:02 UTC
Main PID: 1842 (directadmin)
Tasks: 12 (limit: 4915)
Memory: 27.4M

Twelve tasks, 27 MB. Compare that to a cPanel box where systemctl list-units | grep cpanel returns a wall of services.

CustomBuild 2.0 is the build system. It compiles and manages Apache/nginx/LiteSpeed, PHP, MariaDB, Exim, Dovecot, and the rest. It’s driven by /usr/local/directadmin/custombuild/options.conf. Where cPanel’s EasyApache 4 gives you a GUI and a curated package set, CustomBuild gives you a config file and a build runner. The API is thinner — you won’t find a rich JSON API for everything. That’s the honest tradeoff.

DirectAdmin doesn’t run PHP as root. It defaults to per-user isolation via PHP-FPM pools or suPHP depending on your build. The directadmin service user has narrow privileges. A representative directadmin.conf with security-relevant flags:

Terminal window
# /usr/local/directadmin/conf/directadmin.conf (excerpt)
# Bind only to the management interface, not the public one
ethernet_dev=eth0
# Force SSL on the panel
ssl=1
# Disable the "demo" mode that lets anyone poke around
demo=0
# Require strong passwords for user creation
enforce_difficult_passwords=1
# Restrict API access
api_allow_ip=10.0.0.0/8
# Log verbosity — keep this at 1 in production unless debugging
log_level=1

Each flag here is doing real work. api_allow_ip in particular is often forgotten, leaving the panel API exposed to the world.

FeaturecPanelPleskDirectAdmin
Core languagePerl + PHPPHP + C++C++
Web server choiceApache/nginxnginx/ApacheApache/nginx/LiteSpeed/OLS/nginx_unit
PHP handler modessuPHP, FPMFPM, FastCGIsuPHP, FPM, mod_php, lsapi
Built-in backupYesYesYes
CLI-first workflowPartialPartialYes
Idle RAM (panel)300–500 MB200–400 MB<50 MB

Installation — Doing It Right the First Time

Section titled “Installation — Doing It Right the First Time”

Installation is where people screw up 90% of the time. The other 10% is CustomBuild configuration.

DirectAdmin wants a clean box. If you’ve got nginx, Apache, MySQL, or Postfix already installed, remove them first. The installer will happily half-install on top of an existing stack and leave you debugging for hours.

Disk layout: put /home on its own volume. Put /var on its own volume if you can. /usr/local/directadmin can live on the root volume — it’s small. Separating /home means a runaway user can’t fill your root filesystem and take down the panel.

After downloading the setup script from DirectAdmin’s official site:

Terminal window
# Fetch setup.sh and run with CustomBuild enabled
wget -O setup.sh https://www.directadmin.com/setup.sh
chmod 700 setup.sh
./setup.sh auto

The auto mode reads your license key from the environment or prompts for it, then runs CustomBuild to install the full stack. License keys are IP-bound by default — the panel checks the outbound IP against the license server. If you’re behind NAT, you need a hostname-bound license or a proxy config.

Post-install, harden immediately:

Terminal window
# Install CSF firewall (ConfigServer)
cd /usr/local/src
wget https://download.configserver.com/csf.tgz
tar -xzf csf.tgz
cd csf && sh install.sh
# Verify it will work with this kernel
perl /usr/local/csf/bin/csftest.pl

The csftest.pl step is important — it tells you whether iptables/nftables is actually usable on this kernel before you enable CSF and lock yourself out.

Terminal window
# Confirm the expected services are up
systemctl list-units --type=service --state=running | grep -E 'directadmin|exim|dovecot|httpd|php-fpm|named|mariadb'

If named isn’t running, DNS won’t resolve for new zones. If exim isn’t running, mail silently queues and dies. Check /var/log/directadmin/error.log for the usual suspects — often it’s a port conflict or a permissions issue on /home.

War story: A client once installed DA on a box with a stray nginx listening on port 80. The installer didn’t fail — it just skipped starting Apache. Six hours of “why won’t my sites load” later, ss -tlnp | grep :80 revealed the culprit. Always run ss -tlnp before installing.

CustomBuild 2.0 — Where You Earn Your Keep

Section titled “CustomBuild 2.0 — Where You Earn Your Keep”

CustomBuild is the single most important thing to understand. Get it wrong and you’ll fight your server for years.

This file drives every build decision. Here’s an opinionated baseline for 2025:

Terminal window
# /usr/local/directadmin/custombuild/options.conf (excerpt)
webserver=nginx_apache
nginx=yes
apache=yes
php1_release=8.3
php1_mode=php-fpm
php2_release=8.2
php2_mode=php-fpm
php3_release=8.1
php3_mode=php-fpm
php4_release=7.4
php4_mode=php-fpm
mysql=mariadb
mysql_inst=yes
mariadb=10.11
exim=yes
eximconf=yes
dovecot=yes
dkim=yes
spamassassin=yes

nginx_apache means nginx serves static content and proxies dynamic requests to Apache. This is the standard high-performance setup in 2025 — you get nginx’s efficiency for static assets and Apache’s .htaccess compatibility for the apps that need it.

After editing options.conf, rebuild:

Terminal window
cd /usr/local/directadmin/custombuild
./build update
./build php n
./build rewrite_confs

./build php n compiles PHP without prompting (the n answers “no” to the interactive questions). ./build rewrite_confs regenerates the web server configs to match your new setup. Skipping the second step is a classic mistake — the PHP binaries exist but the configs still point at the old versions.

Per-user PHP override:

/usr/local/directadmin/data/users/alice/user.conf
php1_release=8.2
php1_mode=php-fpm

Then ./build rewrite_confs again. This lets you pin a user to a specific PHP version without touching the global config.

ModePerformanceIsolationNotes
mod_phpHighNoneRuns as Apache user — avoid
suPHPLowGoodSlow, legacy, still used
php-fpmHighGoodDefault choice in 2025
lsapiHighestGoodLiteSpeed only

Use php-fpm unless you have a specific reason not to.

MariaDB over MySQL 8 for most workloads — it’s faster for typical hosting, has better default configs, and DirectAdmin’s tooling assumes it. Exim and Dovecot come configured reasonably; tune them once you hit volume. DKIM is non-negotiable:

Terminal window
# Generate DKIM keys for a domain via DA's built-in tool
/usr/local/directadmin/scripts/dkim_create.sh example.com

This writes the private key to /etc/virtual/example.com/dkim.private.key and gives you the public key to publish in DNS. If you skip DKIM, SPF, and DMARC, you will get blacklisted. Not “might” — will.

Q: Can I switch web servers after install? Yes, but it’s a rebuild. Change webserver= in options.conf, run ./build update && ./build rewrite_confs, and expect a few minutes of downtime. Test on staging first.

Q: How do I add a PHP version not in the default list? CustomBuild supports a limited set. For anything exotic, use the custom build path or compile PHP manually and register it with the panel — this is where the thinner API hurts compared to cPanel.

User Management, Resellers, and the Multi-Tenant Reality

Section titled “User Management, Resellers, and the Multi-Tenant Reality”

Reseller accounts are how hosting businesses scale. They’re also how hosting businesses get compromised when configured lazily.

Resellers get a package allocation and can create users underneath it. Never give resellers SSH by default. Never give them the ability to modify system configs. The panel’s permission model handles this, but you need to verify defaults.

Terminal window
# Create a reseller via the DA CLI
/usr/local/directadmin/da admin user_create reseller1 \
--passwd='[strong-random-password]' \
--email='ops@example.com' \
--package='reseller_basic' \
--reseller=yes

The --reseller=yes flag is what elevates them. Without it, you’ve just made a regular user.

open_basedir should be enforced for every PHP-FPM pool. DA does this by default in recent versions but verify. Disable shell for 99% of users:

Terminal window
# Disable shell access for a user
/usr/local/directadmin/da admin user_modify alice --shell=/bin/false

The classic public_html misconfiguration — world-writable directories — is still the most common cause of defacement I see. Check with:

Terminal window
find /home -type d -perm -0002 -name public_html 2>/dev/null

Anything that returns should be investigated.

DA’s built-in backup system works. It’s not great, but it works. The problem is people store backups on the same box. Don’t.

Terminal window
# DA backup cron with S3 offload
/usr/local/directadmin/da backup_create \
--domain=example.com \
--path=/home/admin_backups \
--s3_bucket=my-backups \
--s3_access_key=[key] \
--s3_secret_key=[secret]

For anything serious, use restic or borg on top of DA’s /home directories:

/usr/local/bin/da-restic-backup.sh
#!/bin/bash
export RESTIC_REPOSITORY="s3:s3.amazonaws.com/my-backup-bucket/da"
export RESTIC_PASSWORD_FILE="/root/.restic-pass"
export AWS_ACCESS_KEY_ID="[key]"
export AWS_SECRET_ACCESS_KEY="[secret]"
restic backup /home \
--exclude='/home/*/backups' \
--exclude='/home/*/.trash' \
--tag directadmin \
--host "$(hostname)"

War story: A client got hit with ransomware that encrypted their DA backups — because the backups lived on the same box and the attacker had root. Off-site or it doesn’t count.

Security Operations — The Part That Separates Pros From Tourists

Section titled “Security Operations — The Part That Separates Pros From Tourists”

Running DA without CSF, monitoring, and a patching cadence is malpractice. Here’s the baseline.

CSF + LFD is the standard. Install it, configure it, and enable the aggressive settings:

Terminal window
# /etc/csf/csf.conf (hardened baseline excerpt)
TCP_IN = "20,21,22,25,53,80,110,143,443,465,587,993,995,2222"
TCP_OUT = "20,21,22,25,53,80,110,113,443,587,993,995"
UDP_IN = "53"
UDP_OUT = "53"
# Rate limit SSH
LF_SSHD = "5"
LF_SSHD_PERM = "3600"
# Block port scans
LF_PORTSCAN = "1"
LF_PORTSCAN_PERM = "3600"
# Email alerts
LF_ALERT_TO = "ops@example.com"

After editing, csf -r to reload. Test with csf -l to see current rules.

At minimum, monitor directadmin, exim, dovecot, httpd/nginx, and mariadb. Node exporter plus a Prometheus scrape config:

# /etc/prometheus/prometheus.yml (excerpt)
scrape_configs:
- job_name: 'da-host'
static_configs:
- targets: ['da-host-01.internal:9100']
- job_name: 'mariadb'
static_configs:
- targets: ['da-host-01.internal:9104']

Ship logs to Loki or a central SIEM. If you’re not doing this, you have no forensic capability when something goes wrong.

Two schedules: OS updates via dnf-automatic, and DA/CustomBuild updates via cron.

Terminal window
# /etc/dnf/automatic.conf (excerpt)
[commands]
upgrade_type = security
apply_updates = yes
/etc/cron.d/da-update
0 3 * * 0 root cd /usr/local/directadmin/custombuild && ./build update && ./build update_da && ./build rewrite_confs

Run this weekly, not daily. Rebuilds can break things; you want them on a schedule you can react to.

Q: Does DirectAdmin have a WAF? Not built-in. You’ll want ModSecurity with the OWASP CRS, or Coraza if you’re on a newer stack. cPanel’s ModSecurity integration is more polished out of the box, but DA supports it fine with a bit of config.

Migration From cPanel/Plesk — The Real Talk

Section titled “Migration From cPanel/Plesk — The Real Talk”

Migration is where the cost savings either materialize or evaporate into a two-week firefight. Plan it properly.

Standard accounts, domains, mailboxes, databases, and DNS zones. SSL certs — don’t port them, just re-issue with Let’s Encrypt. It’s faster and cleaner.

Custom Apache configs, cPanel-specific PHP extensions (looking at you, ea-* packages), cron jobs with hardcoded cPanel paths, and .htaccess files that assume cPanel’s specific module set.

DA has a built-in cPanel restore tool. When it works, it’s great:

Terminal window
# Restore a cPanel backup tarball
/usr/local/directadmin/scripts/restore_backup.sh /path/to/cpmove-user.tar.gz

For everything else, rsync and imapsync:

Terminal window
# Sync /home directories
rsync -avz --delete --exclude='.cpanel' --exclude='.trash' \
root@old-cpanel:/home/user/ /home/user/
# Migrate mailboxes
imapsync --host1 old.example.com --user1 alice@example.com --password1 '[pass]' \
--host2 new.example.com --user2 alice@example.com --password2 '[pass]' \
--automap --useheader 'Message-Id'

DNS cutover: lower TTL to 300 seconds 24 hours before cutover. Run both boxes in parallel for a week. Keep the old box warm for rollback.

War story: A migration I consulted on forgot to recreate SPF records on the new box. Every outbound email bounced for 48 hours. Check your DNS records against the source before cutover — every single one.

DirectAdmin is not universally better. Be honest about your situation.

Use CaseRecommendation
10+ servers, technical staffDirectAdmin
Single server, cost-sensitiveDirectAdmin
Agency without sysadmin depthcPanel/Plesk
Heavy cPanel plugin dependencyStay on cPanel
Enterprise SLA requirementscPanel/Plesk
Managed hosting resellerPlesk

Q: Should I migrate from cPanel to DirectAdmin? If you have technical staff, 10+ servers, and you’re paying more than $200/month in cPanel licensing, yes. If you’re a one-person shop without CLI comfort, no — the support ecosystem and GUI polish aren’t there.

  1. Installing on a dirty box. Remove existing web stacks first. The installer won’t always fail loudly.
  2. Skipping ./build rewrite_confs. Your configs won’t match your binaries. Weird bugs follow.
  3. Backups on the same box. This is not a backup strategy. It’s a ransomware delivery mechanism.
  4. Not enforcing open_basedir. One compromised site becomes ten. Verify per-user isolation.
  5. Ignoring the DKIM/SPF/DMARC trifecta. You will land in spam. Every time.

Q: Is DirectAdmin secure enough for production? Yes, with caveats. The core is solid and the defaults are sane. The thinner ecosystem means you’re responsible for more of the hardening yourself — CSF, ModSecurity, patching. If you do that work, it’s production-grade.

Q: How does DA handle Let’s Encrypt? It has native Let’s Encrypt integration. Enable it per-domain in the panel or via CLI, and it handles issuance and renewal automatically. No certbot gymnastics needed.

Q: Can I run DirectAdmin on ARM? As of this writing, official support is x86_64 only. ARM builds exist in community forks but aren’t supported. Don’t run production on unsupported architectures.

Q: What’s the difference between DA’s Evolution skin and the classic one? Evolution is the modern, responsive UI introduced around 2019. Classic is the legacy interface. Evolution is the default and what you should use unless you have a specific reason not to.

Q: Does DA support Docker? Not natively. You can run Docker alongside it, but the panel doesn’t manage containers. If container orchestration is core to your workflow, DA isn’t the right panel.

Week 1: Stand up a test box. Install DA, break it, rebuild it. Learn CustomBuild. Week 2: Migrate one low-risk client. Run parallel with the old box. Week 3: Monitor, tune, document. Write your runbook. Week 4: Decision point. If it worked, plan the fleet migration. If it didn’t, you lost a month and learned something.

Ansible snippet for repeatable installs:

da-install.yml
- hosts: da_servers
become: yes
tasks:
- name: Ensure clean web stack
dnf:
name: ['httpd', 'nginx', 'mariadb-server']
state: absent
- name: Download DA setup
get_url:
url: https://www.directadmin.com/setup.sh
dest: /root/setup.sh
mode: '0700'
- name: Run installer
shell: /root/setup.sh auto
args:
creates: /usr/local/directadmin/directadmin

That’s the whole pitch. DirectAdmin isn’t glamorous. It’s cheaper, leaner, and boring in the best way — which is exactly what you want from a control panel.