Introduction
cPanel and WHM are the control panel pair behind most shared and reseller hosting on the internet. cPanel is the end-user interface a hosting client logs into to manage their own domain — email, files, databases, SSL. WHM (Web Host Manager) is the administrative layer on top of it, used by the server owner or a reseller to create, suspend, package, and terminate those cPanel accounts, and to configure server-wide settings like DNS, backups, and PHP versions.
Running 400+ live domains on shared and reseller hosting day to day means the work is rarely glamorous: onboarding a new client, chasing down why a mailbox is bouncing, renewing a certificate that silently failed to auto-renew, or explaining to a client why their site broke after a server migration changed the default PHP version. This guide covers that exact operational surface — the WHM/cPanel screens, the whmapi1 / uapi CLI equivalents, and the troubleshooting instincts that come from having actually fixed these tickets.
Who this is for
- Support engineers and sysadmins handling shared/reseller hosting tickets.
- Anyone managing a portfolio of client domains on a WHM server.
- Engineers moving from cloud-native infra into traditional hosting operations.
Prerequisites
You should have the following before working through the commands in this guide:
- Root SSH access to a WHM server, or WHM admin credentials with sufficient ACLs.
- At least one cPanel account created on that server to practice against.
- A domain you control, with the ability to point its nameservers or A record at the server.
- Comfort with basic Linux shell usage — cPanel/WHM sit on top of a normal Linux box.
- An active cPanel/WHM license (from cPanel, L.L.C.) if you're standing up a new server.
OS support
As of this writing, cPanel & WHM only installs on AlmaLinux, CloudLinux, and RHEL(specific major versions per cPanel's supported-OS matrix) — never on Ubuntu/Debian. CloudLinux is the most common choice for shared hosting because of its per-account resource limiting (LVE) and CageFS isolation.Theory
cPanel vs. WHM
Think of WHM as the landlord's office and cPanel as each tenant's apartment. WHM runs with root privileges and is where the server owner (or a reseller with delegated privileges) creates accounts, assigns hosting packages(disk quota, bandwidth, number of domains/databases/email accounts allowed), configures server-wide DNS and mail settings, and manages backups. cPanel is scoped to a single account — a client logged into cPanel can only ever see and modify their own domain's files, email, databases, and DNS zone, never another tenant's.
A reseller sits in between: a WHM user without root access, restricted to creating/managing a bounded set of cPanel accounts under their own resource limits. Reselling is how many hosting companies package and re-sell capacity on a single physical or VPS server.
The account isolation model
Every cPanel account maps to one real Linux system user, with a home directory under /home/username. That mapping is what makes multi-tenant hosting on a single server safe:
| Mechanism | What it isolates |
|---|---|
| One UID per account | Standard Unix file permissions keep one client's files unreadable by another. |
| suEXEC / mod_ruid2 | PHP and CGI scripts execute as the account's own user, not as the Apache/Nginx user. |
| CageFS (CloudLinux) | Each account sees a virtualized filesystem — it cannot see other users' processes or files at all, even via a shell. |
| LVE (CloudLinux) | Per-account CPU/memory/IO limits so one runaway site can't starve the whole server. |
| Disk quotas | Filesystem-level quotas (XFS/ext4) tied to each UID, enforced by the package assigned in WHM. |
| Per-account MySQL users | Database and user names are prefixed with the cPanel username, and DB users are scoped only to their own databases. |
Packages drive the limits
A WHM package(Account Packages in WHM) is the template applied at account creation — disk quota, bandwidth, max add-on/parked domains, max email accounts, max databases, and which features (like shell access) are enabled. Editing a package later doesn't retroactively change existing accounts unless you explicitly update them.Architecture
A single WHM server can host multiple resellers, each managing their own set of cPanel accounts, each of which in turn owns its own domains, email, and databases:
WHM/root → resellers → cPanel accounts → domains, email, databases per account
Not every server has resellers
Plenty of WHM servers run in a flat model — root creates cPanel accounts directly with no reseller layer. Resellers matter mainly for hosting companies that sub-package capacity, or agencies managing several client sites under one umbrella account.Installation
The two installation paths you'll actually run: a clean install on a freshly provisioned server, or restoring a complete server's accounts onto new hardware (a migration).
# Confirm supported OS and version (AlmaLinux / CloudLinux / RHEL)
cat /etc/os-release
# Set the hostname before installing — cPanel ties licensing to it
hostnamectl set-hostname server1.yourhostingco.com
# Ensure the server resolves its own hostname
echo "127.0.0.1 server1.yourhostingco.com server1" >> /etc/hosts
# Download and run the official installer (takes 30-90 minutes)
cd /home
curl -o latest -L https://securedownloads.cpanel.net/latest
sh latest
# After install: log in to WHM to run the first-time setup wizard
# https://server1.yourhostingco.com:2087
# -> accept license, set nameservers, set resolvers, configure mail routingLicense activation
A freshly installed server needs a valid cPanel license tied to its primary IP before WHM fully unlocks. If you're testing on a throwaway VM, cPanel offers a limited free trial license via the WHM setup wizard.Configuration
Accounts: create, suspend, terminate
In WHM: Account Functions → Create a New Account. You choose the domain, username, password, and package. Suspending (not terminating) is the correct first move for anything non-payment related — it disables the site and mail but keeps all data intact for reinstatement.
# Create an account under a package via whmapi1
whmapi1 createacct username=clientco domain=clientco.com \
plan=business_pkg contactemail=admin@clientco.com
# Suspend (site + mail disabled, data untouched)
whmapi1 suspendacct user=clientco reason="Non-payment - invoice #4521"
# Reinstate
whmapi1 unsuspendacct user=clientco
# Terminate — irreversible without a backup
whmapi1 removeacct clientcoTerminate is destructive
removeacctdeletes the home directory, databases, mail, and cron jobs. Always confirm a recent backup exists (WHM's own backups, or run /scripts/pkgacct manually) before terminating a client account.DNS: the Zone Editor
Each cPanel account owns a DNS zone once its domain's nameservers point at the server. Clients edit records for their own domain in cPanel's Zone Editor; WHM exposes the same capability server-wide.
# Add an A record via WHM's DNS API
whmapi1 adddns domain=clientco.com ip=203.0.113.10
# Dump a zone to inspect all records
whmapi1 dumpzone domain=clientco.com
# Edit a specific record (e.g. update an MX record's priority)
whmapi1 editzonerecord domain=clientco.com line=14 priority=10 \
address=mail.clientco.com.| Record | Purpose |
|---|---|
A | Hostname → IPv4 address |
AAAA | Hostname → IPv6 address |
CNAME | Alias to another hostname |
MX | Mail server(s) for the domain, with priority |
TXT | SPF, DKIM, DMARC, domain verification strings |
NS | Delegates a subdomain, or sets reseller-branded nameservers |
PHP version selection: MultiPHP Manager
WHM's MultiPHP Managerlets each domain (not just each account) run a different PHP version — critical when one client's legacy app needs PHP 7.4 while everything else has moved to 8.x. MultiPHP INI Editor tunes per-domain php.ini directives without touching the shared system default.
# List installed PHP versions (EasyApache 4 / ea-php packages)
whmapi1 php_get_installed_versions
# Set a specific domain to a specific PHP version
whmapi1 php_set_vhost_versions version=ea-php81 vhost=clientco.com
# Bulk-set an entire account's domains at once
whmapi1 php_set_vhost_versions version=ea-php82 vhost=acmeinc.com,shop.acmeinc.commemory_limit = 256M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 120
max_input_vars = 3000
display_errors = OffSSL: AutoSSL and custom certificates
AutoSSLissues and auto-renews free domain-validated certificates (Let's Encrypt or Sectigo, depending on the configured provider) for every domain on the server with no manual steps, as long as the domain's DNS actually resolves to the server and port 80 validation succeeds.
# Force an AutoSSL run for one user right now
whmapi1 start_autossl_check_for_users user=clientco
# Check AutoSSL's current provider and settings
whmapi1 fetch_autossl_config
# Install a purchased/custom certificate via uapi (run as the account, or
# with whmapi1's equivalent as root)
uapi SSL install_ssl domain=clientco.com \
cert="$(cat clientco.crt)" \
key="$(cat clientco.key)" \
cabundle="$(cat clientco_bundle.crt)"Force HTTPS redirects
cPanel's Domainspage has a "Force HTTPS Redirect" toggle per domain once a valid cert is installed — it writes the redirect into an.htaccess-equivalent config so you don't have to hand-edit vhost includes.Commands
whmapi1 — root/reseller-level API
whmapi1 listaccts # every account on the server
whmapi1 accountsummary user=clientco # quota, package, IP, suspension status
whmapi1 create_user_session user=clientco service=cpaneld
# generate a one-time login URL into a
# client's cPanel, for support without
# asking for their password
whmapi1 modifyacct user=clientco DOMAIN=clientco.com QUOTA=10240
whmapi1 restartservice service=exim # restart a service safely
whmapi1 servicestatus service=mysqluapi — account-scoped API (also usable by the account itself)
uapi --user=clientco Email list_pops
uapi --user=clientco Email add_pop email=sales domain=clientco.com \
password='S0meStrongPass!' quota=1024
uapi --user=clientco Mysql create_database name=clientco_wp
uapi --user=clientco Mysql create_user name=wpuser password='AnotherStrongPass!'
uapi --user=clientco Mysql set_privileges_on_database user=wpuser \
database=clientco_wp privileges=ALL
uapi --user=clientco DomainInfo domains_dataShell commands run directly on the box
# Mail queue and delivery
mailq # Exim queue summary
exim -bpc # count of messages in the queue
exiqgrep -i # message IDs only, useful for scripting
exim -Mvl <message-id> # view a message's delivery log
exim -Mrm <message-id> # remove one stuck/spam message
# Disk usage and quotas
repquota -a # quota usage for every user
du -sh /home/clientco/* | sort -rh | head
/scripts/fixquotas # rebuild quota tables after corruption
# Account/service housekeeping
/scripts/mailperm # fix broken mail directory permissions
/scripts/upcp # manually trigger a cPanel update
/usr/local/cpanel/scripts/autorepair inodeusage # inode issues on an account
tail -f /usr/local/cpanel/logs/error_log # cPanel's own error logExamples
Onboarding a new hosting client end-to-end, from sale to a live, secured site:
Create the account in WHM
whmapi1 createacctwith the client's domain and an appropriate package, or the equivalent WHM UI form. Note the generated nameservers or confirm the domain will point its A record at the server's IP.Point DNS
Either the client updates nameservers at their registrar to yours, or (if keeping their existing DNS provider) they add anArecord pointing at the server IP you give them.Migrate or upload the site
Restore from the old host's backup via/scripts/restorepkg, or have the client upload files via cPanel's File Manager / FTP, then import their database through phpMyAdmin.Set the correct PHP version
Use MultiPHP Managerto match whatever version the client's application actually needs, rather than leaving the server default.Issue SSL and force HTTPS
Confirm DNS has propagated, then runwhmapi1 start_autossl_check_for_usersand enable "Force HTTPS Redirect" once the cert is live.Create mailboxes and set MX
Create the client's email accounts in cPanel → Email Accounts, and confirmMXrecords point at the server (unless they use an external mail provider like Google Workspace).Hand off credentials and confirm
Send cPanel login details separately from any password, and do a final check: site loads over HTTPS, a test email sends/receives cleanly, and backups are scheduled.
Screenshots
WHM — Create a New Account, showing domain, package, and resource limit fields
Screenshot placeholder
cPanel — Email Accounts screen, showing mailbox quota usage per address
Screenshot placeholder
Real World Example
Scenario:a client reports "customers say our order confirmation emails never arrive" — a classic deliverability ticket, and one of the most common tickets in shared hosting.
Confirm the mail actually left the server
Checkmailqandtail -f /var/log/exim_mainlogfor the recipient's address. If it's sitting in the queue with repeated retries, it's a delivery/rejection problem, not a code problem.Read the actual rejection reason
exiqgrep -ito get the message ID, thenexim -Mvl <id>to read the receiving server's bounce text — usually something like "550 5.7.1 SPF check failed" or a blacklist reference.Check SPF, DKIM, and DMARC
whmapi1 dumpzone domain=clientco.comto verify aTXTSPF record exists and includes the sending server's IP/mechanism, that DKIM signing is enabled for the domain in cPanel → Email → Authentication, and that aDMARCrecord isn't set top=rejectwhile SPF/DKIM are still misaligned.Check the server's own IP reputation
Query the sending IP against major blacklists (Spamhaus, Barracuda). A shared IP can get blacklisted because of one other tenant's compromised account sending spam — this is a real, frequent cause on shared hosting.Fix and verify
Correct the SPF/DKIM records via the Zone Editor, request delisting if blacklisted, then send a fresh test message and confirm clean headers with a tool like a mail-tester style report before closing the ticket.
Common Issues
Disk quota exceeded
Symptoms range from failed uploads to WordPress silently failing to write cache files. Check withrepquota -a or whmapi1 accountsummary user=clientco, then either clean up (old backups, log files under public_html) or raise the package/account quota with whmapi1 modifyacct.Email bouncing due to SPF/DKIM failure
Receiving servers reject or spam-folder mail when the sending domain's SPF record doesn't authorize the server's IP, or DKIM signing isn't enabled. Verify both in cPanel → Email → Authentication and in the domain's DNS zone before assuming it's a server-wide problem.SSL not auto-renewing via AutoSSL
AutoSSL silently fails when the domain's DNS no longer resolves to the server, when a firewall blocks the HTTP-01 validation request on port 80, or when a CAA record on the domain doesn't permit the configured CA. Runwhmapi1 start_autossl_check_for_users and read the AutoSSL log in WHM rather than guessing.MySQL "too many connections"
Usually a leaking application (no connection pooling, or a stuck cron) rather than genuine traffic. Check current connections withSHOW PROCESSLIST;, raise max_connections in /etc/my.cnfonly as a stopgap, and fix the application's connection handling as the real solution.Wrong PHP version breaks a site after a server migration
A restored account inherits whatever PHP version the new server defaults to if MultiPHP wasn't explicitly re-applied. Always re-check MultiPHP Manager per domain immediately after a/scripts/restorepkgor Transfer Tool migration — don't assume it carried over.Best Practices
- Suspend before you terminate — suspension is reversible, termination is not.
- Keep WHM's own backup system configured with an off-site destination (S3, remote FTP/SFTP) in addition to any client-side backup plugin.
- Standardize on one or two supported PHP versions server-wide, and track which client domains are pinned to an EOL version so they can be migrated deliberately, not during an incident.
- Re-run AutoSSL checks and confirm DNS right after any DNS or IP change — don't assume certificates renew themselves silently.
- Document which accounts share a physical/VPS server so a noisy-neighbor CPU or IP-reputation issue is easy to trace back to its source.
- Use WHM's reseller ACLs to give support staff exactly the privileges they need — not full root — for day-to-day account work.
Security Hardening
- CSF (ConfigServer Security & Firewall) — default-deny firewall with login-failure daemon (LFD) that auto-blocks brute-force attempts against SSH, cPanel, FTP, and mail.
- Disable unused services — turn off FTP entirely in favor of SFTP where clients don't need it, and disable any service (Dovecot, old mail protocols) nobody actually uses.
- ModSecurity — enable the OWASP Core Rule Set per-account in WHM's ModSecurity Configuration, tuning false positives per domain rather than disabling it server-wide.
- Two-factor authentication for WHM — enforce via WHM's Two-Factor Authentication feature for every root/reseller login, not just cPanel end users.
- Regular off-site backups — WHM backups stored only on the same server are lost with the server; always replicate to a separate host or object storage.
- PHP hardening — set
open_basedirper account to confine scripts to their own home directory, and disable dangerous functions (exec,shell_exec,passthru) viadisable_functionsin MultiPHP INI Editor unless a client specifically needs them. - CageFS + LVE (CloudLinux) — keep these enabled; they're the strongest isolation guarantee between tenants on a shared box.
Interview Questions
Cheat Sheet
# --- Accounts (WHM) ---
whmapi1 createacct username=<u> domain=<d> plan=<pkg> contactemail=<e>
whmapi1 suspendacct user=<u> reason="<reason>"
whmapi1 unsuspendacct user=<u>
whmapi1 removeacct <u>
whmapi1 listaccts ; whmapi1 accountsummary user=<u>
whmapi1 modifyacct user=<u> QUOTA=<mb>
# --- DNS ---
whmapi1 adddns domain=<d> ip=<ip>
whmapi1 dumpzone domain=<d>
whmapi1 editzonerecord domain=<d> line=<n> address=<value>
# --- PHP ---
whmapi1 php_get_installed_versions
whmapi1 php_set_vhost_versions version=ea-php82 vhost=<d>
# --- SSL ---
whmapi1 start_autossl_check_for_users user=<u>
uapi SSL install_ssl domain=<d> cert="${cert}" key="${key}" cabundle="${bundle}"
# --- Email / Exim ---
mailq ; exim -bpc ; exiqgrep -i
exim -Mvl <id> ; exim -Mrm <id>
# --- MySQL ---
uapi --user=<u> Mysql create_database name=<u>_<db>
uapi --user=<u> Mysql create_user name=<dbuser> password='<pass>'
uapi --user=<u> Mysql set_privileges_on_database user=<dbuser> database=<u>_<db> privileges=ALL
# --- Backups / migration ---
/scripts/pkgacct <u> /home/backups
/scripts/restorepkg /home/cpmove-<u>.tar.gz
# --- Disk / quotas ---
repquota -a ; du -sh /home/<u>/* | sort -rh | head
/scripts/fixquotasSummary
Day-to-day cPanel/WHM work comes down to a handful of repeating shapes: creating and suspending accounts under the right package, keeping DNS and SSL correct as domains and servers change, matching each client's PHP version to their actual application, and diagnosing the two tickets that never stop coming — "my site is down" (usually disk quota or PHP version) and "my email isn't arriving" (usually SPF/DKIM or IP reputation). Learn the whmapi1/uapi equivalents of every WHM screen and these tickets go from guesswork to a five-minute checklist.
Resources
- Official cPanel & WHM documentation —
docs.cpanel.net - cPanel API reference (whmapi1 / uapi) —
api.docs.cpanel.net - CloudLinux documentation (CageFS, LVE) —
docs.cloudlinux.com - Exim mail transfer agent documentation —
exim.org - MySQL reference manual —
dev.mysql.com