cPanel has a “full backup” feature that can store the backup on a remote FTP server or can use Secure Copy (SCP) to push the files to a remote location. Normally you would want to automate this process via a cron job using a script or a php file. A full description can be found here and I am not going to cover this use case: Howto: Automatic cPanel Backups
cPanel backup with remote credentials
My concern was that the backup script will contain credentials to the cpanel and the remote connection (FTP or SCP) in plan text. Besides the credentials being exposed on the remote server you need to run a FTP server that increases the risk of compromise (outdated package, misconfiguration, you name it).
code snippet from the backup script
$auth = base64_encode("username:password"); $domain = "https://example.com:2083"; $theme = "paper_lantern"; $ftp = false; $ftp_server = "fortress.com"; $ftp_username = "strong_user"; $ftp_password = "super_secret"; $ftp_port = "21"; $ftp_directory = "/";
cPanel backup with without remote credentials
If you want to avoid exposing your remote server to vulnerabilities and potentially leaking credentials in transit (ie FTP sends the password in clear text) there is a nice trick I have implemented.
The idea is to generate the backup file on the remote server that will be stored in the root folder. We don’t let cPanel push the backup remotely, but we’ll fetch the file directly from the remote server.
In this instance the backup script resides on the remote server (our fortress) and holds just the credentials to the cPanel instance. You can even obfuscate the password in different ways to make it even harder for anyone to retrieve the password if they manage to get gain access to the content of the file itself.
$pass = exec("id -nu | md5sum | awk -F- '{ print \$1 }'");
Generating and downloading the backup
- To generate the backup we’ll need to hit the
/backup/dofullbackup.html
first. This will start generating the full backup in the background. - In the second stage the script will check for all available backups
/backup/fullbackup.html
generated previously and will try to get the file/download?file=
. - The final stage is to delete the old backup from the remote server using the json api endpoint
/json-api/cpanel
<?php $login = 'cpanel_user'; $pass = exec("id -nu | md5sum | awk -F- '{ print \$1 }'"); $auth = base64_encode("$login:$pass"); $domain = "https://example.com:2083"; $theme = "paper_lantern"; // Do not change below $url = $domain . "/frontend/" . $theme . "/backup/dofullbackup.html"; $data = array(); $options = array( 'http' => array( 'header' => "Content-type: application/x-www-form-urlencoded\r\nAuthorization: Basic $auth\r\n", 'method' => 'POST', 'content' => http_build_query($data) ), 'ssl' => array( 'verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true ) ); # execute backup generation $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $url = $domain . "/frontend/" . $theme . "/backup/fullbackup.html"; $options = array( 'http' => array( 'header' => "Content-type: application/x-www-form-urlencoded\r\nAuthorization: Basic $auth\r\n", 'method' => 'GET' ), 'ssl' => array( 'verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true ) ); $context = stream_context_create($options); $result = file_get_contents($url, false, $context); # get downloadable files preg_match_all("|/download\?file=(.*?)\"|", $result, $matches); foreach ($matches[1] as $match) { $auth = $login . ':' . $pass; // due to memory contrains we will do the download with curl $url = $domain . "/download?file=" . $match; exec("curl -s -u " . escapeshellarg($auth) . ' ' . escapeshellarg($url) . " -o " . escapeshellarg("/home/backup/hosting_backup/" . $match)); // now delete them $url = $domain . "/json-api/cpanel"; exec("curl -s -u " . escapeshellarg($auth) . ' ' . escapeshellarg($url) . " --data " . escapeshellarg("cpanel_jsonapi_module=Fileman&cpanel_jsonapi_func=fileop&cpanel_jsonapi_apiversion=2&filelist=1&multiform=1&doubledecode=0&op=unlink&metadata=[object Object]&sourcefiles=%2fhome%2fpmcnet%2f" . $match)); } if ($result === FALSE) { exit("Error backing up server."); }
You can download the source code by visiting the GitHub repo.
References
Howto: Automatic cPanel Backups
cPanel Auto Backup Script Generator
Howto: Automatic cPanel Backups
cPanel Automated Backup Script
How do I Generate a cPanel Backup using an Automated Script?
cPanel Automated Backup Script Using PHP, Cron Jobs and FTP