Синхронизируйте локальные и удаленные папки с помощью rsync из php-скрипта без ввода пароля


Как я могу синхронизировать локальные и удаленные папки с помощью rsync из php-скрипта без запроса на ввод пароля?

Я уже настроил открытый ключ для автоматизации входа на удаленный сервер для моего пользователя.

Таким образом, это работает без каких-либо проблем с cli:

rsync -r -a -v -e "ssh -l user" --delete ~/local/file 111.111.11.111:~/remote/;

Но, когда я пытаюсь запустить то же самое из PHP-скрипта (на веб-странице на моем локальном сервере):

$c='rsync -r -a -v -e "ssh -l user" --delete ~/local/file 111.111.11.111:~/remote/';
//exec($c,$data);
passthru($c,$data);
print_r($data);

Вот что я получаю:

255

И ни один файл не загружается с локального на удаленный сервер.

В поисках в сети я нашел эту подсказку:

"Вы могли бы использовать комбинацию BASh и ожидать здесь кода оболочки, но это было бы не очень безопасно, потому что это автоматизировало бы вход в систему root. Создайте ключи для nobody или apache (независимо от пользователя, от имени которого выполняется Apache). В качестве альтернативы, установите phpSuExec, Suhosin или suPHP, чтобы сценарии запускались от имени пользователя, для которого они были вызваны"

.

Ну, я не знаю, как "автоматизировать вход в систему root" для PHP, который работает как "apache". Может быть, лучше запустить скрипт от имени реального пользователя, я не знаю... Спасибо!

ОБНОВЛЕНИЕ: - Поскольку это прекрасно работает:

passthru('ssh [email protected] | ls',$data);

Возвращая список домашнего фодера, я могу быть уверен, что с автоматическим входом в систему проблем нет. Это может быть что-то с rsync, запущенным из PHP-скрипта.

  • У меня также есть chmod-R 0777 в локальной и удаленной папках на всякий случай. Но я этого не понял пока.

ОБНОВЛЕНИЕ:

Вся проблема связана с тем фактом, что "при запуске в командной строке ssh использует файлы ключей на $HOME/.ssh/, но в PHP он запускается с использованием пользователя Apache, поэтому у него может не быть $HOME; тем более $HOME/.ssh/id_dsa. Итак, либо вы специально указываете ему, какой файл ключей использовать, либо вручную создаете этот каталог и его содержимое"

.

Хотя я не могу получить rsync, вот как я должен перенести файл с локального на удаленный:

if($con=ssh2_connect('111.111.11.111',22)) echo 'ok!';
if(ssh2_auth_password($con,'apache','xxxxxx')) echo ' ok!';
if(ssh2_scp_send($con,'localfile','/remotefolder',0755)) echo ' ok!';

Требуется локальный файл: 0644 Потребности в удаленной папке: 0775

Я думаю, если бы решение не заключалось в том, чтобы запускать php с тем же пользователем, что и bash...

@Yzmir Рамирес дал такое предложение: "Я не думаю, что вы хотите "скопировать ключ куда-нибудь, где apache сможет до него добраться" - это нарушение безопасности. Лучше изменить сценарий для запуска от имени защищенного пользователя, а затем настроить ключи .ssh для входа без пароля между серверами.

Это то, что я должен потратьте еще немного времени. Если кто-нибудь знает, как это сделать, пожалуйста, это было бы очень полезно.

Author: Roger, 2011-01-23

3 answers

Когда я установил то же самое в нашем приложении, я также столкнулся с 255 ошибками и обнаружил, что они могут означать разные вещи; это не особенно полезный код ошибки. На самом деле, даже сейчас, после того, как решение работает бесперебойно уже более года, я все еще вижу, что в журналах иногда появляется 255.

Я также скажу, что заставить его работать может быть немного сложно, так как здесь задействовано несколько переменных. Одна вещь, которую я нашел чрезвычайно полезной, заключалась в том, чтобы построить команду rsync в переменной, а затем запишите ее в журнал. Таким образом, я могу взять точную используемую команду rsync и попытаться запустить ее вручную. Вы даже можете обратиться к пользователю apache и запустить его из того же каталога, что и ваш скрипт (или независимо от того, что ваш скрипт устанавливает в качестве cwd), что заставит его действовать так же, как при программном запуске; это значительно упрощает отладку команды rsync, так как вам не нужно иметь дело с веб-сервером. Кроме того, когда вы запускаете его вручную, если он не работает по какой-то причине неустановленная причина, добавьте флаги детализации, чтобы увеличить вывод ошибок.

Ниже приведен код, который мы используем, слегка отредактированный для безопасности. Обратите внимание, что наш код фактически поддерживает синхронизацию как с локальными, так и с удаленными серверами, поскольку назначение полностью настраивается для обеспечения простой тестовой установки.

try {
    if ('' != $config['publishSsh']['to']['remote']):
    //we're syncing with a remote server
        $rsyncToRemote = escapeshellarg($config['publishSsh']['to']['remote']) . ':';
        $rsyncTo = $rsyncToRemote . escapeshellarg($config['publishThemes']['to']['path']);
        $keyFile = $config['publishSsh']['to']['keyfile'];
        $rsyncSshCommand = "-e \"ssh -o 'BatchMode yes' -o 'StrictHostKeyChecking no' -q -i '$keyFile' -c arcfour\"";
    else:
    //we're syncing with the local machine
        $rsyncTo = escapeshellarg($config['publishThemes']['to']['path']);
        $rsyncSshCommand = '';
    endif;

    $log->Message("Apache running as user: " . trim(`whoami`), GLCLogger::level_debug);
    $deployCommand = "
        cd /my/themes/folder/; \
        rsync \
        --verbose \
        --delete \
        --recursive \
        --exclude '.DS_Store' \
        --exclude '.svn/' \
        --log-format='Action: %o %n' \
        --stats \
        $rsyncSshCommand \
        ./ \
        $rsyncTo \
         2>&1
    "; //deployCommand
    $log->Message("Deploying with command: \n" . $deployCommand, GLCLogger::level_debug);
    exec($deployCommand, $rsyncOutputLines, $returnValue);
    $log->Message("rsync status code: $returnValue", GLCLogger::level_debug);
    $log->Message("rsync output: \n" . implode("\n", $rsyncOutputLines), GLCLogger::level_debug);
    if (0 != $returnValue):
        $log->Message("Encountered error while publishing themes: <<<$returnValue>>>");
        throw new Exception('rsync error');
    endif;

    /* ... process output ... */
} catch (Exception $e) {
    /* ... handle errors ... */
}

Несколько вещей, которые следует отметить в коде:

  • Я использую exec(), чтобы я мог записывать выходные данные в переменную. Затем я анализирую его, чтобы войти в систему и сообщить результаты с точки зрения того, сколько файлов было добавлено, изменено и удалено.

  • Я объединяю стандартный вывод rsync и стандартные потоки ошибок и возвращаю оба. Я также записываю и проверяю код возвращаемого результата.

  • Я регистрирую все, когда нахожусь в режиме отладки, включая пользователя, от имени которого запущен Apache, саму команду rsync и вывод команды rsync. Таким образом, тривиально легко выполнить ту же команду, что и тот же пользователь, просто быстро копирование и вставка, как я уже упоминал выше.

  • Если у вас возникли проблемы с командой rsync, вы можете настроить ее детализацию без каких-либо последствий и просмотреть выходные данные в журнале.

В моем случае я смог просто указать на соответствующий файл ключей и не слишком беспокоиться о безопасности. Тем не менее, некоторые мысли о том, как с этим справиться:

  • Предоставление Apache доступа к файлу не означает, что он должен находиться в веб-каталоге; вы можете поместить файл в любом месте, доступном пользователю Apache, даже на другом сетевом компьютере. В зависимости от других ваших уровней безопасности это может быть или не быть приемлемым компромиссом.

  • В зависимости от данных, которые вы копируете, вы можете сильно заблокировать разрешения пользователя ssh на другой машине, чтобы, если кому-то недобросовестному удалось проникнуть туда, у них была бы минимальная возможность нанести ущерб.

  • Вы можете использовать suEXEC для запуска сценария от имени пользователя другой чем пользователь Apache, что позволяет вам заблокировать доступ к вашему ключу для этого другого пользователя. Таким образом, кто-то, компрометирующий пользователя Apache, просто не имел бы доступа к ключу.

Я надеюсь, что это поможет.

 5
Author: mr. w, 2011-01-26 17:04:15

Когда вы позволяете веб-серверу выполнить команду, он запускает ее от имени своего пользователя ("никто" или "apache" или аналогичный) и ищет закрытый ключ в домашнем каталоге этого пользователя/.ssh, в то время как закрытый ключ, который вы настраиваете для своего пользователя, находится в "/home/you/.ssh/файл ключей", или как бы вы его ни назвали.

Заставьте ssh использовать этот конкретный ключ с параметром -i:

ssh -i /home/you/.ssh/keyfile

И это должно сработать

 0
Author: Fanis, 2011-01-23 17:58:51

Простое, но прямое решение этой проблемы здесь, которое я использую.

НЕ запускайте rsync напрямую с php, у него есть проблемы, а также это может быть угрозой безопасности. Скорее всего, просто подготовьте два сценария. В php-скрипте вам просто нужно изменить значение одной переменной в файловой системе с 0 на 1.

Теперь, с другой стороны, создайте сценарий rsync, который будет работать вечно и будет иметь следующую логику. "" Если в файле 0, то не запускайте rsync, если он равен 1, затем запустите rsync, затем измените его значение обратно на 0 после успешного запуска rsync; ""

Я тоже это делаю.

 0
Author: Farhan, 2012-04-08 12:21:22