Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

So I have the following setup:

  • Server A (webserver)
  • Server B (Xen Dom0 - with logical volumes)
  • Server C (backup server)

I want to create backups from server B to server C all automatically and securely. I can create a PHP file on server B which upon accessing will create a backup. However it would need to have PHP being ran on the server.

Now I could also use ssh2_connect from PHP, which I could use to only run PHP on server B and execute commands, but those commands require root access. So anyone hacking the webserver or other way get access to the files would have immediate root access.

I have a database on my webserver with the "commands" to do. Like backup VM server 1, then restore VM server 8 etc. That's why I need to send "commands" from server A to server B. My question is, what is the best solution to do this safely? I obviously don't want anyone getting access to server B except me.

share|improve this question
add comment

3 Answers 3

up vote 1 down vote accepted

Instead of having Server A run the commands remotely on Server B, why not have Server B just ask Server A which commands to run?

Schedule a cron job, something along these lines:

10 01 * * * /usr/local/bin/do_backups

Where do_backups looks something like this:

#!/usr/bin/env php
<?php

$conn = pg_connect('host=servera dbname=backup');
pg_prepare($conn, 'get_commands', 'SELECT command FROM backup_commands');
$result = pg_execute($conn, 'get_commands', array());
$commands = pg_fetch_result($result);

foreach($commands as $cmd) {
    system(escapeshellcmd($cmd));
}
?>

Obviously, this is kind of pseudocode since I don't know what your database looks like, so if it isn't clear what it is doing, let me know. Just remember to escape your command if it takes arguments that may be untrusted. Also, it's been a while since I've written in PHP, so there may be mistakes in my code ;)

share|improve this answer
add comment

What you want to do is to create a cron job on server B that makes the backup for you regularly. If you have php_cli installed on the server, this could even be a PHP script if you know this best.

Create your backup script in any form you like and then, as root, add this to the crontab with crontab -e. Example:

0 1 * * * /root/mybackupscript.sh 

would run the script mybackupscript.sh in root's home folder every night at 01:00 o'clock.

For more info, see man cron and man crontab.


Following your edit, some other suggestions:

  • Have your backup script poll the web server for the job information. It still can run as root. A simple script on the web server can generate job commands for this poll.
  • Connect to Server B with SSH and run the jobs this way. Difficult to get running non-interactively in a secure fashion.
  • Allow a user on Server B (likely the web server's user) to sudo your backup script without a password. Make sure only root can modify this script and it can't be fooled with malicious parameters.
share|improve this answer
    
Yes, however doing this with a cron wouldn't work, as I have a database on my webserver with the "commands" to do. Like backup VM server 1, then restore VM server 8 etc. That's why I need to send "commands" from server A to server B. –  Devator Mar 9 '12 at 9:23
    
Better update your question to include this info. I was wondering why your mentioned Server A in the first place. Also, tell us how server A should control this. –  SvW Mar 9 '12 at 9:26
    
I've edited my original post. –  Devator Mar 9 '12 at 9:31
add comment

WRT Devator's answer, you can use phpseclib, a pure PHP SSH implementation, to do SSH interactively. Here's an example from the phpseclib docs regarding sudo, which normally provides an interactive prompt for a password:

<?php
include('Net/SSH2.php');

$sftp = new Net_SSH2('www.domain.tld');
$sftp->login('username', 'password');

echo $sftp->read('username@username:~$');
$sftp->write("sudo ls -la\n");
$output = $sftp->read('#Password:|username@username:~\$#', NET_SSH2_READ_REGEX);
echo $output;
if (preg_match('#Password:#', $lines)) {
    $ssh->write("password\n");
    echo $sftp->read('username@username:~$');
}
?>

You can also make use of $ssh->setTimeout(xx) to accommodate commands that never return what you're looking for even with regular expression matching.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.