JetBackup 5 is a backup plugin for cPanel & WHM. It backs up every account incrementally to a remote destination, and lets both you and your customers restore files, databases and email from cPanel. This guide installs it on a cPanel server and sends the backups to an SSH backup account on a remote server, the way we did it on production servers, including the mistakes worth avoiding.
Quick answer
-
Check the server meets the requirements (AVX CPU, AlmaLinux/CloudLinux/Rocky 8–10, cPanel 88+,
maxmem2048+). -
Buy a JetBackup 5 licence for the server's IP.
-
As root, run:
bash <(curl -LSs https://repo.jetlicense.com/static/install) jetapps --install jetbackup5-cpanel release jetbackup5 --license -
Open WHM › Plugins › JetBackup 5, pick New Installation, and save the JetRecovery Encryption Key.
-
Add an SSH (Legacy) destination with key login to your backup account, create a job with Backup Structure set to Incremental, and schedule it before its first run.
What you need:
- A cPanel & WHM server with root SSH access.
- A JetBackup 5 licence (from JetApps or the cPanel Store) for the server's public IP.
- A backup server you can reach over SSH, with
rsyncinstalled and room for the backups. Any Linux server or VPS will do.
Step 1: Check the requirements
grep -o -m1 -w avx /proc/cpuinfo
cat /etc/redhat-release
/usr/local/cpanel/cpanel -V
grep maxmem /var/cpanel/cpanel.config
df -h / /home
| Check | Needed |
|---|---|
| CPU | prints avx (on a VM, the host can hide it) |
| OS | AlmaLinux, CloudLinux or Rocky Linux 8, 9 or 10 |
| cPanel | version 88 or later |
maxmem |
2048 or more; raise it in WHM › Tweak Settings › Max cPanel process memory |
| Disk | free space for JetBackup and its database |
Tip: without -w, grep -o -m1 avx prints avx many times on newer CPUs, because it also matches avx2 and the AVX-512 flags. Any avx output is a pass; no output is a fail.
Step 2: Install JetBackup 5
Run as root:
bash <(curl -LSs https://repo.jetlicense.com/static/install)
Installing jetapps repo package...DONE
Cleaning installed repos....DONE
Installing jetapps cli package...Importing GPG key 0x544FA811:
Userid : "JetApps LLC (JetApps Official Signing Key) <security@jetapps.com>"
DONE
The installer imports JetApps' signing key by itself. Then install the plugin from the release tier:
jetapps --install jetbackup5-cpanel release
Installing jetbackup5-cpanel version 5.4.1.4-203...Completed
Use release, not stable. Some older guides, including cPanel's own knowledge base, say stable. That tier is not in JetApps' current list (release, rc, edge, alpha), and there is no downgrade from a newer tier.
Step 3: Activate the licence
jetbackup5 --license
License is set to IP based.
License fetched successfully.
License is Active
An IP licence needs no key: JetBackup fetches it for the server's IP. It is checked again every 48 hours.
Step 4: First open in WHM
Open WHM › Plugins › JetBackup 5. The first time, it shows the JetRecovery Wizard:
- New Installation: start with the default configuration. Pick this on a new server.
- JetRecovery Mode: restore JetBackup's settings from a backup, for disaster recovery or a server move. Picking it with another server's config would copy that server's jobs and destinations.
Next, JetBackup shows the JetRecovery Encryption Key. Save it now, off the server (a password manager is ideal). It is the only way to decrypt JetBackup's own config backup if the server is lost. Without it you can still restore accounts, but you would rebuild every job and setting by hand. Each server has its own key.
Step 5: Review the important settings
The settings page opens after the wizard. The defaults are mostly fine; we changed these:
| Setting | Default | Recommended | Why |
|---|---|---|---|
| Downloads TTL | Don't delete | 3 days | downloads are written to the server's own disk |
| Manual Backups TTL | Don't delete | 7 days | otherwise manual and customer on-demand backups pile up forever |
| Concurrent System Tasks | 5 | 1 | stops the integrity check running beside a backup, which overloaded the backup server and got the server's IP refused |
| Delete orphan backups older than | 180 days | keep | backups of terminated accounts stay 6 months |
Step 6: Prepare the SSH backup account
On the backup server, as root, give each cPanel server its own user and folder, so one server cannot see or delete another's backups:
useradd -m <backup-user>
mkdir /home/<backup-user>/backups
chown <backup-user>: /home/<backup-user>/backups
command -v rsync
The last command must print a path. If it prints nothing, install rsync (dnf install rsync or apt install rsync): JetBackup's SSH destination copies files with rsync, so login alone is not enough. The user needs write access, because JetBackup deletes old backups itself.
On the cPanel server, create a key just for backups and copy it to the account:
ssh-keygen -t ed25519 -N '' -f /root/.ssh/jetbackup_backup
ssh-copy-id -i /root/.ssh/jetbackup_backup.pub -p <ssh-port> <backup-user>@<backup-host>
ssh-copy-id asks for the account's password once. If the backup server allows key login only, add the .pub key to /home/<backup-user>/.ssh/authorized_keys there by hand instead.
Open the firewall (CSF)
CSF allows outgoing port 22 by default. If the backup server uses another SSH port, allow it to that server's IP only, and check the port before and after the change:
timeout 5 bash -c '</dev/tcp/<backup-ip>/<ssh-port>' && echo open || echo blocked
cp /etc/csf/csf.allow /etc/csf/csf.allow.bak
echo 'tcp|out|d=<ssh-port>|d=<backup-ip> # Backup server, JetBackup' >> /etc/csf/csf.allow
csf -r
timeout 5 bash -c '</dev/tcp/<backup-ip>/<ssh-port>' && echo open || echo blocked
This rule allows only outgoing traffic, only on that port, only to the backup server. To undo it, copy the .bak file back and run csf -r.
Test the key login. A listing with no password prompt means it works:
ssh -4 -p <ssh-port> -i /root/.ssh/jetbackup_backup <backup-user>@<backup-host> ls -la /home/<backup-user>/backups
Step 7: Add the destination
In JetBackup, open Destinations › Create New Destination, set Destination For Backup, and choose SSH (Legacy). The first time, it shows an Install Now button instead of the fields: the SSH type is a separate plugin. Install it, and the form appears. Two defaults need changing:
| Field | Default | Use |
|---|---|---|
| Destination Name | empty | a neutral name like Cloud Storage (customers see it in cPanel) |
| Backup Directory | / |
an absolute path, for example /home/<backup-user>/backups (a relative ./backups/ failed) |
| Remote Host | empty | <backup-host> |
| Port | 22 | your backup server's SSH port |
| Remote Username | empty | <backup-user> |
| Authentication Type | Password | Private Key, /root/.ssh/jetbackup_backup |
| Rsync Prefer IPv4/IPv6 | Default Route | IPv4, if your firewall rule allows only the IPv4 address |
Turn on Export JB Config so JetBackup's own settings are backed up too. When you save, JetBackup fills in Disk Info and runs a speed test. That means it logged in successfully. Disk Info shows the free space of the whole disk the folder is on, not a per-user quota.
Turning on Export JB Config also creates a JetBackup Config job by itself, which runs daily. You don't need to create it.
Step 8: Create the backup job
First, create clearly named schedules (Daily, Weekly, Monthly) under Backup Jobs › Manage Schedules. Schedules are shared between jobs, and retention is counted per schedule, so swapping a schedule later can leave old backups outside the rotation.
Then open Backup Jobs › Create New Backup Job:
| Field | Default | Use |
|---|---|---|
| Backup Type | Accounts | keep |
| Backup Structure | Deduplication | Incremental |
| Destinations | none | your destination |
| Retry failed items | No | Yes |
| Directories and Files to exclude | empty | logs, caches and temp folders (Insert Multiple) |
| Schedules | none | Daily retain 7, Weekly (Sunday) retain 4, Monthly (1st) retain 3 |
Set Backup Structure to Incremental before adding the destination. Deduplication isn't supported on SSH (Legacy), so with the default the destination shows as "Backup structure not supported".
Check the retention after saving. On two servers, Monthly saved as retain 2 instead of the 3 we typed. Open the job again and fix it if needed.
Step 9: Start the first run the right way
Never start the first full backup with "Run Now". Manual and scheduled runs keep separate backup sets, each with its own full backup, and manual backups are kept until their TTL. A "Run Now" first run means uploading everything twice.
Instead, set the job's Schedule Time a few minutes ahead. The first run is then a scheduled run that starts the daily set. After it finishes, move the Schedule Time to its real night slot (a running job can't be edited).
Pick the night slot after WHM's own backup. Check when it really ends: the local backup logs in /usr/local/cpanel/logs/cpbackup/ show the start, but if WHM also sends backups to a remote destination, check the transporter log too:
grep cpbackup_transporter /usr/local/cpanel/logs/cpbackup_transporter.log | tail
On our server the local backup finished in 15 minutes, but the remote transfer ran almost an hour. We started JetBackup an hour after that.
How long the first run takes
Look for one big account before you start. It sets the time, not the total size:
repquota -a | awk '$1!="root" && $3 ~ /^[0-9]+$/ {printf "%8.1f GB %s\n", $3/1024/1024, $1}' | sort -rn | head
JetBackup backs up several accounts in parallel, but one account goes through a single rsync stream. On one server, a single account held three quarters of the data. Its first run of about 355 GB across 25 accounts took 6 hours 51 minutes, about three times faster than the destination speed test suggested, because the test measures one stream.
JetBackup reports the result when it finishes:
The backup job "daily" completed successfully in 6 Hours and 51 Minutes. Total Completed: 25 Total Partial: 0 Total Failed: 0 Total Aborted: 0
Step 10: Set the cleanup time
Open Settings › Performance and set Backup Cleanup & Integrity Check to every 1 day at 12:00 AM, and keep Concurrent System Tasks at 1 (see step 5). With "No Preference", cleanup ran while a backup was uploading. Recheck it after later saves: on one server it changed to 2 days by itself.
Step 11: Test a restore
Test on a throwaway account with fake data, never on a real customer: a restore overwrites the live account. Start with a Download restore, which changes nothing, then restore the test account.
Troubleshooting
"Backup structure not supported". The job is set to Deduplication. Change Backup Structure to Incremental.
Destination test fails. Check the SSH port, the key path, an absolute Backup Directory the user can write to, that rsync is installed on the backup server, and the CSF rule. The ssh test from step 6 should work first.
Some accounts end up Partial. Usually the account is over its quota. Check both space and inodes with quota -vs <user>; an account can be at its inode limit while its space looks fine.
The plugin isn't licensed. Run jetbackup5 --license and check the licence is bound to the server's current public IP.