Синхронизируйте локальные и удаленные папки с помощью 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 для входа без пароля между серверами.
Это то, что я должен потратьте еще немного времени. Если кто-нибудь знает, как это сделать, пожалуйста, это было бы очень полезно.
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, просто не имел бы доступа к ключу.
Я надеюсь, что это поможет.
Когда вы позволяете веб-серверу выполнить команду, он запускает ее от имени своего пользователя ("никто" или "apache" или аналогичный) и ищет закрытый ключ в домашнем каталоге этого пользователя/.ssh, в то время как закрытый ключ, который вы настраиваете для своего пользователя, находится в "/home/you/.ssh/файл ключей", или как бы вы его ни назвали.
Заставьте ssh использовать этот конкретный ключ с параметром -i
:
ssh -i /home/you/.ssh/keyfile
И это должно сработать
Простое, но прямое решение этой проблемы здесь, которое я использую.
НЕ запускайте rsync напрямую с php, у него есть проблемы, а также это может быть угрозой безопасности. Скорее всего, просто подготовьте два сценария. В php-скрипте вам просто нужно изменить значение одной переменной в файловой системе с 0 на 1.
Теперь, с другой стороны, создайте сценарий rsync, который будет работать вечно и будет иметь следующую логику. "" Если в файле 0, то не запускайте rsync, если он равен 1, затем запустите rsync, затем измените его значение обратно на 0 после успешного запуска rsync; ""
Я тоже это делаю.