Packages and feature lists are the two primitives cPanel gives you to differentiate plans. Get them right once and provisioning, upgrades, and renewals become declarative — change the package, every account on it inherits the new limits. Get them wrong and you end up patching individual accounts by hand for years.
This article covers the model, a tier layout that works for most shared and reseller hosts, and the rough edges that surprise people the first time they wire packages up to a billing platform.
What packages and feature lists actually do
A package is a quota and infrastructure profile — disk quota, bandwidth quota, addon
domain count, MySQL database count, FTP and email account counts, mailing list count,
dedicated IP toggle, shell access, CGI access, theme, language, locale, and (when
CloudLinux is installed) the LVE limits referenced by a package extension. WHM stores these
under /var/cpanel/packages/<name> as flat key=value files.
A feature list is the UI surface for that account in cPanel — which icons and links the
user sees. WHM stores these under /var/cpanel/features/<name>. Hiding a feature does not
disable the underlying service; a determined user can still hit the cPanel API directly.
Feature lists are for the cPanel UI only — security boundaries belong in the package
(quotas, shell access, CGI) or at the system level.
Packages and feature lists are independent. Multiple packages can reference the same
feature list (e.g., all shared tiers can share a shared-default feature list and differ
only in quotas), and you can override the feature list per account from WHM > Modify an
Account.
A tier layout that scales
Most shared hosts can model their entire catalogue with three packages and one feature list. Start there and only add more when a real product reason appears.
| Tier | Disk | Bandwidth | Add-on domains | MySQL DBs | LVE CPU | LVE EP | PMEM |
|---|---|---|---|---|---|---|---|
| Starter | 10 GB | 100 GB | 1 | 5 | 100% (1 core) | 20 | 1 GB |
| Pro | 50 GB | 500 GB | 10 | 25 | 200% | 40 | 2 GB |
| Business | 200 GB | unmetered | unlimited | unlimited | 400% | 80 | 4 GB |
A few notes on this layout:
- "Unlimited" in WHM means
0. Set the field to0and cPanel treats it as unmetered. Most billing platforms display "unlimited" to the customer but pass0over the wire. - LVE values are per-account, not per-cPanel user. A reseller's child accounts each get their own LVE; the reseller package itself does not need higher limits unless you sell reseller-tier hosting separately.
- Bandwidth quotas in WHM are advisory. cPanel will not block a site over quota; it
flags the account in WHM > List Accounts and the bandwidth usage report. If you need hard
cutoffs, write a WHM standardized hook on the
Whostmgr::Accounts::bwlimitevent.
For the LVE specifics see CloudLinux LVE tuning — the defaults above are conservative starting points for a 4-vCPU, 16 GB shared node, not target values.
Build the package once, version the file
Create the package from WHM > Packages > Add a Package, then dump it to disk and put it in git:
cat /var/cpanel/packages/starter
You should see a flat key=value file with QUOTA, BWLIMIT, MAXADDON, MAXSQL,
MAXPOP, MAXFTP, MAXSUB, MAXLST, MAXPARK, IP, CGI, HASSHELL, CPMOD, and so
on. Commit these to a repository on the server. Every package change goes through git →
cp file /var/cpanel/packages/<name> → whmapi1 verify_users_in_conf to validate. When
you onboard a new node, copy the directory across instead of clicking through WHM.
For LVE limits inside the package, edit the _PACKAGE_EXTENSIONS field to reference a
CloudLinux extension file. See CloudLinux reseller limits in WHM
for the syntax — the extension model is the only sane way to keep LVE in the package rather
than overriding per-account after creation.
Build the feature list
The default feature list (named default) enables almost everything. Clone it and disable
features you do not want exposed in the shared tier:
- File Manager > Java Upload — obsolete, dead weight
- Logs > Awstats — heavy on busy accounts, prefer the built-in dashboard
- Software > Perl Modules and PHP Pear Packages — confusing for shared users, often broken under CloudLinux's PHP Selector
- Email > Calendars and Contacts (CalDAV/CardDAV) — only enable if you actually run the CCS service
- Advanced > Cron Jobs — leave on, but pair with LVE cron throttling to stop runaway crons
- Preferences > Change Style / Change Language — harmless, leave on
Wire packages into Blesta or WHMCS
Both billing platforms model the cPanel package as a string field on the product. The
provisioning module passes that string to the WHM createacct API, which fails loudly if
the package does not exist on every server in the cluster. Two failure modes hit nearly
every host eventually:
- Package exists on the primary server but not on a failover node. Treat
/var/cpanel/packages/as configuration, not state. Rsync the directory across the cluster after every change, or run it from a systemd timer. - Package name changes between renewal cycles. A customer on
starter-2023will not auto-upgrade tostarter-2025just because you renamed the product in billing. Either keep the old package alive forever, or run awhmapi1 changepackagemigration in a maintenance window. See Blesta cPanel provisioning setup for the module-side mapping.
If you sell reseller hosting, the package's MAXSUB, MAXPOP, and other count fields cap
what the reseller can create — but you also need a separate ACL list controlling what WHM
features the reseller can use. Covered in WHM reseller accounts and ACLs.
Common pitfalls
- Editing the
defaultpackage. It is the fallback for any account created without an explicit package and for any account whose package is later deleted. Leave it at conservative defaults and never reference it from your billing platform. - Setting "Dedicated IP" in the package. This is a one-time allocation, not a renewable resource — when the account is created cPanel grabs an IP from the shared pool. Removing the flag later does not return the IP. Manage dedicated IPs as a billing add-on, not a package attribute.
- Mixing shell access into a shared tier. If even one shared tier has
HASSHELL=y, CageFS containment is materially weaker for that tier. Keep shell access in a separate package (typically the Business or Reseller tier) and usejailshellrather thanbash— see the cPanel shell access documentation for thechshflow. - Forgetting that new WHM versions add fields you didn't set. After an update, run
whmapi1 listpkgs --output=jsonpretty | jqand look for any package missing the keys present indefault. Backfill them explicitly so the next update doesn't introduce drift.
What's the difference between a cPanel package and a feature list?+
Can I change a package without affecting existing accounts on it?+
How do I export cPanel packages between servers?+
Does deleting a package break accounts assigned to it?+
Can I set CloudLinux LVE limits inside a cPanel package?+
What is 'unlimited' in WHM actually set to?+
Next steps
- WHM reseller accounts and ACLs — the ACL model that pairs with packages for reseller-tier hosting
- CloudLinux reseller limits in WHM — wiring LVE
into packages via
_PACKAGE_EXTENSIONS - Blesta cPanel provisioning setup — mapping packages to billing products and avoiding the rename-on-renewal trap
For volume cPanel licensing across multiple shared nodes, see cPanel license tiers explained or contact us. Activating a cPanel license takes about ten minutes end-to-end.