Automatic cPanel Backups

Many hosting services allow their customers to administer their web sites using a product called cPanel. One of the features of cPanel is the ability to backup your hosting data, including your databases, email setup and code. Of course, most hosting providers also perform backups for you so you might wonder why you should bother about doing your own as well. But what if the hosting company folds or what if you want to move your site to another hosting provider?

The cPanel backup facility lets you do this manually but it’s also possible to spoof the web form it uses and drive the cPanel engine using a PHP script. That allows you to automate the backup of multiple web sites to an FTP server somewhere and have it run automatically as part of a cron job on a regular basis. Windows devs can get the benefits of cron using Windows Task Scheduler or the excellent pycron by Gerhard Kalab.

The Code

Here’s the script I use to do this. It’s based on work initially done by Justin Cook back in 2006 but cPanel has changed a bit since then and I’ve had to tweak it a little to accommodate these changes. I’ve also dropped in a simple loop through an array to backup multiple sites.

<?php
 
// Automatic cPanel FTP backup
// This script contains passwords. Do not put it in a public folder.
 
// ********* THE FOLLOWING ITEMS NEED TO BE CONFIGURED *********

// First site details
$sites['0']['domaintobackup'] = 'mycompany.com';
$sites['0']['cpaneluser']     = 'user1';
$sites['0']['cpanelpass']     = 'pass1';
// This is found as part of your cPanel URL
// e.g. https://mycompany.com:2083/frontend/x3Bronze/index.html
$sites['0']['cpanelskin']     = 'x3Bronze';

//Second site details
$sites['1']['domaintobackup'] = 'example.com';
$sites['1']['cpaneluser']     = 'user2';
$sites['1']['cpanelpass']     = 'pass2';
$sites['1']['cpanelskin']     = 'x3Bronze';
 
// FTP host details
$ftpmode = 'ftp';               // 'ftp' for active,
                                // 'passiveftp' for passive,
                                // 'scp' for scp - most secure
$ftpuser = 'ftpuser';
$ftppass = 'ftppassword';
$ftphost = 'my.ftp.server.com'; // Full hostname or IP address for FTP host
$ftpport = '21';
$ftpfold = '/sitebackups';      // Destination folder for backup files
 
$notifyemail = 'backupwarnings@mycompany.com';
$secure = 0; // Set to 1 for SSL (requires SSL support)
$debug = 0;  // Set to 1 to have web page result appear in your cron log
 
// *********** NO CONFIGURATION ITEMS BELOW THIS LINE *********
 
foreach ($sites as $site)
{
	if ($secure)
	{
		$url = 'ssl://'.$site['domaintobackup'];
		$port = 2083;
	}
	else
	{
		$url = $site['domaintobackup'];
		$port = 2082;
	}

	$socket = fsockopen($url,$port);
	if (!$socket)
	{
		echo 'Failed to open socket connection… Bailing out!\n';
		exit;
	}

	$authstr = $site['cpaneluser'] . ':' . $site['cpanelpass'];
	$pass = base64_encode($authstr);

	$params = 'dest=$ftpmode&amp;amp;email_radio=1&amp;amp;email=$notifyemail'.
	          '&amp;amp;server=$ftphost&amp;amp;user=$ftpuser&amp;amp;pass=$ftppass&amp;amp;port=$ftpport'.
	          '&amp;amp;rdir=$ftpfold&amp;amp;submit=Generate Backup';

	fputs($socket,'POST /frontend/'.$site['cpanelskin'].
	              '/backup/dofullbackup.html?'.$params.' HTTP/1.0\r\n');
	fputs($socket,'Host: ' . $site['domaintobackup'] . '\r\n');
	fputs($socket,'Authorization: Basic $pass\r\n');
	fputs($socket,'Connection: Close\r\n');
	fputs($socket,'\r\n');

	while (!feof($socket))
	{
		$response = fgets($socket,4096);
		if ($debug)
		{
			echo $response . '\n';
		}
	}

	echo $site['domaintobackup'] . 'complete.\n';

	fclose($socket);
}
 
?>

Personally I call this using the PHP CLI in my mobile USB stick XAMPP installation from my crontab and it backs up to the FTP server on my USB stick. Having said that, there are plenty of ways you can use this script and picking the best one really does depend on how you work and what your general development setup is.

Pitfalls and Their Solutions

A few things are worth noting if you’re trying to set this up yourself. There are two top tips for diagnosing problems with this setup:

  • Set $debug=1 in the script so you can see what errors you’re getting if any.
  • Check the incoming connections log on your FTP server to make sure the FTP data is getting through.

More specifically, if you look at the FTP server log and don’t see the connections coming in from the script then make sure your firewall/router is letting the traffic through on the right ports. The ports for FTP are 20 and 21 for the FTP protocol traffic itself and various other ports used for the payload data. Those ports depend on how you have your FTP server setup (see the discussion of passive mode FTP below).

The other potential pitfall with completely missing FTP connections is that you might be running a NAT router and yet not have setup port forwarding for the inbound FTP traffic in order to route it to the IP address of the FTP server itself.

If you’re using passive mode FTP (you probably should be) and you’re seeing connections in the FTP server log but they’re failing after the protocol negotiation with errors like 425 Can't open data connection. then make sure you’ve allowed the incoming data ports through your firewall as well as just the FTP protocol ports of 20 and 21. Setting up the passive mode FTP server settings lets you do this as well as set up the correct external IP address. There’s a great article on how all this works in general at FileZilla.

Leave a Reply

Your email address will not be published. Required fields are marked *