Как мне скопировать файлы, которым нужен root-доступ, с помощью scp?

168

У меня есть сервер Ubuntu, к которому я подключаюсь по SSH.

Мне нужно загрузить файлы со своего компьютера /var/www/на сервер, файлы /var/www/принадлежат root.

Используя PuTTY, после того, как я войду в систему, я должен sudo suсначала ввести свой пароль, чтобы иметь возможность изменять файлы в /var/www/.

Но когда я копирую файлы с помощью WinSCP, я не могу создать / изменить файлы /var/www/, потому что у пользователя, к которому я подключаюсь, нет прав доступа к файлам, /var/www/и я не могу сказать, sudo suкак в случае сеанса ssh ,

Вы знаете, как я мог справиться с этим?

Если бы я работал на своей локальной машине, я бы позвонил, gksudo nautilusно в этом случае у меня есть только терминальный доступ к машине.

Димитрис Сапикас
источник
Это больше похоже на вопрос для вашего провайдера виртуального сервера, или для разработчиков putty или winscp.
Добей
7
@ Да, ты явно неправ, речь идет о привилегиях Ubuntu!
Димитрис Сапикас
7
Почему это закрыто? Это совершенно правильный вопрос о копировании файлов с помощью scp - каждый веб-разработчик знаком с этой ситуацией
Сергей
У меня похожая проблема. Я создаю файл (в данном случае HTML) на компьютере с Windows и пытаюсь скопировать его с помощью WinSCP в папку / var / www / html / website. И это говорит о том, что есть проблема с разрешением. Поскольку я могу скопировать в свою папку / home, я скопировал файл в два этапа, но это не очень удобно :-) Я попытался добавить своего пользователя в группу www-data, но это не помогло. Есть идеи, почему добавление пользователя в www-данные все еще не позволяет пользователю скопировать файл в папку, принадлежащую группе www-data?
ЯнезКраньски,

Ответы:

126

Ты прав, нет sudoпри работе с scp. Обходной путь - использовать scpдля загрузки файлов в каталог, где у вашего пользователя есть разрешения на создание файлов, затем войти в систему через ssh и использовать sudoдля перемещения / копирования файлов в их конечное место назначения.

scp -r folder/ user@server.tld:/some/folder/you/dont/need/sudo
ssh user@server.tld
 $ sudo mv /some/folder /some/folder/requiring/perms 
# YOU MAY NEED TO CHANGE THE OWNER like:
# sudo chown -R user:user folder

Другим решением будет изменение прав доступа / владельцев каталогов, в которые вы загружаете файлы, чтобы ваш непривилегированный пользователь мог писать в эти каталоги.

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

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

Сергей
источник
я не получил первое решение, не могли бы вы быть немного более конкретным?
Димитрис Сапикас
Когда я говорю свои собственные файлы, я имею в виду / var / www, я использую свой vps в качестве веб-сервера .... в моей собственной папке у меня полный доступ
Dimitris Sapikas
7
Число рейнольдса первое решение. 1. scp -R mysite dimitris@myserver.com:/home/dimitris/2. ssh dimitris@myserver.com3. sudo mv ~/mysite /var/www- это двухэтапный процесс, сначала вы scpотправляете файлы в домашнюю директорию, затем вы входите через ssh и копируете / перемещаете файлы туда, где они должны быть
Сергей
36

Другой способ - скопировать, используя tar + ssh вместо scp:

tar -c -C ./my/local/dir \
  | ssh dimitris@myserver.com "sudo tar -x --no-same-owner -C /var/www"
Вилли Уилер
источник
2
Это лучший способ сделать это.
mttdbrd
2
Я не могу заставить этот метод работать успешно. Как написано, я получаю sudo: sorry, you must have a tty to run sudo. Если я добавлю «-t» для выделения TTY, я получу Pseudo-terminal will not be allocated because stdin is not a terminal.. Я не вижу, чтобы это работало без sudo без пароля.
IBBoard
1
@IBBoard: попробуйте решение здесь, используя ssh -t:ssh -t dimitris@myserver.com "sudo tar -x --no-same-owner -C /var/www"
Александр Берд
2
@AlexanderBird Хотя это работает во многих случаях, я не уверен, что это работает здесь, потому что мы пытаемся передать тарбол через SSH-соединение. См. Serverfault.com/questions/14389/…
IBBoard
Это то, что, наконец, сработало для меня. У вас нет прав доступа к удаленному файлу, который вы хотите скопировать в локальный, сделать sudo tar, заархивировать его, изменить разрешения с помощью chmodи chown, а затем скопировать в локальный. Особенно, если это каталог.
форум
28

Быстрый способ

С сервера на локальную машину:

ssh user@server "sudo cat /etc/dir/file" > /home/user/file

С локального компьютера на сервер:

cat /home/user/file | ssh user@server "sudo tee -a /etc/dir/file"
Андерсон Лира
источник
5
Этот ответ недооценен. Он простой, чистый, читает или записывает корневой файл с помощью одной атомарной операции и не требует ничего, что еще не гарантировано, если вы используете scp. Основным недостатком является то, что он не копирует разрешения. Если вы хотите этого, смоляное решение лучше. Это мощная техника, особенно в сочетании с магией xargs / bash для прохождения путей ..
markgo2k
Я думаю, что вопрос был о загрузке файла с локального на удаленный, а не наоборот
Korayem
1
Красиво сделано. Это именно то, что я искал как вверх, так и вниз. Спасибо
Джереми
Заслуживает быть лучшим ответом, конечно.
Эндрю Уотсон
Можно ли это сделать для каталога, а не для файла?
lucidbrot
26

Вы также можете использовать ansibleдля этого.

Скопируйте на удаленный хост, используя модуль ansiblecopy :

ansible -i HOST, -b -m copy -a "src=SRC_FILEPATH dest=DEST_FILEPATH" all

Получить с удаленного хоста, используя модуль ansiblefetch :

ansible -i HOST, -b -m fetch -a "src=SRC_FILEPATH dest=DEST_FILEPATH flat=yes" all

НОТА:

  • Запятая в -i HOST,синтаксисе не является опечаткой. Это способ использовать ansible без необходимости в инвентаре.
  • -bзаставляет действия на сервере выполняться как root. -bрасширяется до --become, и по умолчанию --become-userиспользуется root, по умолчанию используется --become-methodsudo.
  • flat=yesкопирует только файл, не копирует весь удаленный путь, ведущий к файлу
  • Использование подстановочных знаков в путях к файлам не поддерживается этими модулями.
  • Копирование каталога является поддерживается copyмодулем, но не с помощью fetchмодуля.

Конкретный вызов для этого вопроса

Вот пример, который является конкретным и полностью определенным, если предположить, что каталог на вашем локальном хосте, содержащий файлы для распространения sourcedir, и что имя хоста удаленной цели hostname:

cd sourcedir && \
ansible \
   --inventory-file hostname, \ 
   --become \
   --become-method sudo \
   --become-user root \
   --module-name copy \
   --args "src=. dest=/var/www/" \
   all

С кратким призывом быть:

cd sourcedir && \
ansible -i hostname, -b -m copy -a "src=. dest=/var/www/" all

PS Я понимаю, что высказывание «просто установите этот невероятный инструмент» является своего рода глухим ответом. Но я обнаружил, что ansible очень полезен для администрирования удаленных серверов, поэтому его установка, несомненно, принесет вам другие преимущества, помимо развертывания файлов.

erik.weathers
источник
Мне нравится этот ответ, но я рекомендую направить его на заданный вопрос, в отличие от более обобщенного комментария, перед upvote. что-то вродеansible -i "hostname," all -u user --become -m copy -a ...
Майк Д
@MikeD: как выглядят вышеуказанные изменения?
erik.weathers
1
Будет ли что-то вроде -i 'host,'действительный синтаксис? Я думаю, что при чтении команды легко потерять пунктуацию. (Для читателя я имею в виду, если не оболочку.)
mwfearnley
1
@mwfearnley: конечно, оболочка будет обрабатываться так -i 'host,'же, как -i host,и -i "host,". В целом, я предпочитаю, чтобы эти вызовы были как можно более короткими, чтобы они не были пугающими, но вы должны не стесняться делать их настолько подробными и четкими, насколько вы считаете, что это необходимо для ясности.
erik.weathers
2
Способ мыслить нестандартно! Большое использование Ansible
Джонатан
12

При запуске sudo suлюбые файлы, которые вы создаете, будут принадлежать пользователю root, но по умолчанию невозможно напрямую войти в систему как root с помощью ssh или scp. Также невозможно использовать sudo с scp, поэтому файлы нельзя использовать. Исправьте это, заявив право собственности на ваши файлы:

Предполагая, что ваше имя пользователя было dimitri, вы можете использовать эту команду.

sudo chown -R dimitri:dimitri /home/dimitri

С этого момента, как уже упоминалось в других ответах, «Ubuntu» использует sudo, а не root-логины. Это полезная парадигма с большими преимуществами безопасности.

trognanders
источник
Я использую это решение любым способом, но что если я смогу получить полный доступ к своей собственной файловой системе, я не хочу печатать sudo chow ...для каждого отдельного каталога: S
Dimitris Sapikas
2
Смена владельца всех системных файлов для удобства пользователей крайне не рекомендуется. Это позволяет любой ошибке в пользовательском пространстве, с которой вы можете столкнуться, серьезно подрывает безопасность вашей системы. Гораздо лучше изменить владельца файлов, которые вам нужно изменить или обновить с помощью SCP, но оставить все остальное в собственности root (как и должно быть). Тем не менее, -Rin chownсообщает ему об изменении владельца этого каталога, а также всех дочерних файлов и каталогов рекурсивно ... так что вы можете делать все что угодно.
Trognanders
хм .... кажется, работает нормально, спасибо! извините, я не могу проголосовать (система не позволяет мне делать ...)
Димитрис Сапикас
11

Может быть, лучшим способом является использование rsync( Cygwin / cwRsync в Windows) поверх SSH?

Например, чтобы загрузить файлы с владельцем www-data:

rsync -a --rsync-path="sudo -u www-data rsync" path_to_local_data/ login@srv01.example.com:/var/www

В вашем случае, если вам нужны привилегии root, команда будет выглядеть так:

rsync -a --rsync-path="sudo rsync" path_to_local_data/ login@srv01.example.com:/var/www

Смотрите: scp на удаленный сервер с sudo .

Алексей Важнов
источник
5

Если вы используете инструменты OpenSSH вместо PuTTY, вы можете сделать это, инициировав scpпередачу файлов на сервер с помощью sudo. Убедитесь, что sshdна вашем локальном компьютере запущен демон. С ssh -Rего помощью вы можете дать серверу способ связаться с вашей машиной.

На вашей машине:

ssh -R 11111:localhost:22 REMOTE_USERNAME@SERVERNAME

В дополнение к входу в систему на сервере, он будет перенаправлять каждое соединение, выполненное на порту 11111 сервера, на порт 22 вашей машины: порт, который вы sshdпрослушиваете.

На сервере начните передачу файла следующим образом:

cd /var/www/
sudo scp -P 11111 -r LOCAL_USERNAME@localhost:FOLDERNAME .
bergoid
источник
1

Вы можете использовать сценарий, который я написал, вдохновленный этой темой:

touch /tmp/justtest && scpassudo /tmp/justtest remoteuser@ssh.superserver.com:/tmp/

но это требует некоторых сумасшедших вещей (что, кстати, автоматически делается по сценарию)

  1. сервер, на который отправляется файл, больше не будет запрашивать пароль при установке ssh-соединения с исходным компьютером
  2. из-за необходимости отсутствия приглашения sudo на сервере, sudo больше не будет запрашивать пароль на удаленной машине для пользователя

Вот сценарий:

interface=wlan0
if [[ $# -ge 3 ]]; then interface=$3; fi
thisIP=$(ifconfig | grep $interface -b1 | tail -n1 | egrep -o '[0-9.]{4,}' -m1 | head -n 1)
thisUser=$(whoami)
localFilePath=/tmp/justfortest
destIP=192.168.0.2
destUser=silesia
#dest 
#destFolderOnRemoteMachine=/opt/glassfish/glassfish/
#destFolderOnRemoteMachine=/tmp/

if [[ $# -eq 0 ]]; then 
echo -e "Send file to remote server to locatoin where root permision is needed.\n\tusage: $0 local_filename [username@](ip|host):(remote_folder/|remote_filename) [optionalInterface=wlan0]"
echo -e "Example: \n\ttouch /tmp/justtest &&\n\t $0 /tmp/justtest remoteuser@ssh.superserver.com:/tmp/ "
exit 1
fi

localFilePath=$1

test -e $localFilePath 

destString=$2
usernameAndHost=$(echo $destString | cut -f1 -d':')

if [[ "$usernameAndHost" == *"@"* ]]; then
destUser=$(echo $usernameAndHost | cut -f1 -d'@')
destIP=$(echo $usernameAndHost | cut -f2 -d'@')
else
destIP=$usernameAndHost
destUser=$thisUser
fi

destFolderOnRemoteMachine=$(echo $destString | cut -f2 -d':')

set -e #stop script if there is even single error

echo 'First step: we need to be able to execute scp without any user interaction'
echo 'generating public key on machine, which will receive file'
ssh $destUser@$destIP 'test -e ~/.ssh/id_rsa.pub -a -e ~/.ssh/id_rsa || ssh-keygen -t rsa'
echo 'Done'

echo 'Second step: download public key from remote machine to this machine so this machine allows remote machine (this one receiveing file) to login without asking for password'

key=$(ssh $destUser@$destIP 'cat ~/.ssh/id_rsa.pub')
if ! grep "$key" ~/.ssh/authorized_keys; then
echo $key >> ~/.ssh/authorized_keys
echo 'Added key to authorized hosts'
else
echo "Key already exists in authorized keys"
fi

echo "We will want to execute sudo command remotely, which means turning off asking for password"
echo 'This can be done by this tutorial http://stackoverflow.com/a/10310407/781312'
echo 'This you have to do manually: '
echo -e "execute in new terminal: \n\tssh $destUser:$destIP\nPress enter when ready"
read 
echo 'run there sudo visudo'
read
echo 'change '
echo '    %sudo   ALL=(ALL:ALL) ALL'
echo 'to'
echo '    %sudo   ALL=(ALL:ALL) NOPASSWD: ALL'
echo "After this step you will be done."
read

listOfFiles=$(ssh $destUser@$destIP "sudo ls -a")

if [[ "$listOfFiles" != "" ]]; then 
echo "Sending by executing command, in fact, receiving, file on remote machine"
echo 'Note that this command (due to " instead of '', see man bash | less -p''quotes'') is filled with values from local machine'
echo -e "Executing \n\t""identy=~/.ssh/id_rsa; sudo scp -i \$identy $(whoami)@$thisIP:$(readlink -f $localFilePath) $destFolderOnRemoteMachine"" \non remote machine"
ssh $destUser@$destIP "identy=~/.ssh/id_rsa; sudo scp -i \$identy $(whoami)@$thisIP:$(readlink -f $localFilePath) $destFolderOnRemoteMachine"
ssh $destUser@$destIP "ls ${destFolderOnRemoteMachine%\\\\n}/$(basename $localFilePath)"
if [[ ! "$?" -eq 0 ]]; then echo "errror in validating"; else echo -e "SUCCESS! Successfully sent\n\t$localFilePath \nto \n\t$destString\nFind more at http://arzoxadi.tk"; fi
else
echo "something went wrong with executing sudo on remote host, failure"

fi
ENDOFSCRIPT
) | sudo tee /usr/bin/scpassudo && chmod +x /usr/bin/scpassudo
test30
источник
@Braiam да, конечно, извините за ссылку, сценарий довольно длинный, и это было причиной :)
test30
1

Вы можете комбинировать ssh, sudo и, например, tar для передачи файлов между серверами, не имея возможности войти в систему как root и не имея разрешения на доступ к файлам с вашим пользователем. Это немного неудобно, поэтому я написал сценарий, чтобы помочь этому. Вы можете найти скрипт здесь: https://github.com/sigmunau/sudoscp

или здесь:

#! / Бен / Баш
разреш = 0
от = $ 1
к = $ 2
сдвиг
сдвиг
файлы = "$ @"
if test -z "$ из" -o -z "$ в" -o -z "$ files"
тогда
    echo "Использование: $ 0 (файл) *"
    echo "пример: $ 0 сервер1 сервер2 / usr / bin / myapp"
    выход 1
фи

прочитайте -s -p "Введите пароль:" sudopassword
эхо ""
TEMP1 = $ (Mktemp)
temp2 = $ (Mktemp)
(echo "$ sudopassword"; echo "$ sudopassword" | ssh $ из sudo -S tar c -P -C / $ files 2> $ temp1) | ssh $ в sudo -S tar x -v -P -C / 2 > $ temp2
sourceres = $ {PIPESTATUS [0]}
если [$? -ne 0 -o $ sourceres -ne 0]
тогда
    эхо "Неудача!" > & 2
    echo "$ from output:"> & 2
    cat $ temp1> & 2
    echo ""> & 2
    echo "$ to output:"> & 2
    cat $ temp2> & 2
    разреш = 1
фи

rm $ temp1 $ temp2
выход $ res
sigmunda
источник
Добро пожаловать в Спросите Ubuntu. Не могли бы вы включить сценарий в свой ответ? Я знаю, что это маловероятно, но если репозиторий GitHub когда-либо будет удален или URL-адрес будет изменен, то ответ будет недействительным. Лучше включить скрипт напрямую и оставить репозиторий github в качестве источника.
Майкл Линдман
0

Вот модифицированная версия ответа Вилли Уилера, которая передает файл (ы) через tar, но также поддерживает передачу пароля к sudo на удаленном хосте.

(stty -echo; read passwd; stty echo; echo $passwd; tar -cz foo.*) \
  | ssh remote_host "sudo -S bash -c \"tar -C /var/www/ -xz; echo\""

Немного дополнительной магии здесь - опция -S для sudo. Со страницы руководства sudo:

-S, --stdin Записать подсказку к стандартной ошибке и прочитать пароль из стандартного ввода вместо использования терминального устройства. За паролем должен следовать символ новой строки.

Теперь мы на самом деле хотим, чтобы вывод tar передавался в ssh, и это перенаправляет стандартный вывод ssh на стандартный вывод tar, удаляя любой способ передачи пароля в sudo с интерактивного терминала. (Мы могли бы использовать функцию sudo ASKPASS на удаленном конце, но это уже другая история.) Мы можем получить пароль в sudo, хотя, захватывая его заранее и добавляя его к выводу tar, выполняя эти операции в подоболочке и передавая выходные данные подоболочка в ssh. Это также имеет дополнительное преимущество - не оставлять переменную окружения, содержащую наш пароль, в нашей интерактивной оболочке.

Вы заметите, что я не выполнил 'read' с опцией -p, чтобы напечатать приглашение. Это потому, что запрос пароля от sudo удобно передается обратно в stderr нашей интерактивной оболочки через ssh. Вы можете задаться вопросом "как выполняется sudo, если он работает внутри ssh справа от нашего канала?" Когда мы выполняем несколько команд и перенаправляем вывод одной команды в другую, родительская оболочка (в данном случае интерактивная оболочка) выполняет каждую команду в последовательности сразу после выполнения предыдущей. При выполнении каждой команды за каналом родительская оболочка прикрепляет (перенаправляет) стандартный вывод левой стороны к стандартному выводу правой стороны. Выход становится входным по мере прохождения через процессы.

$ (stty -echo; read passwd; stty echo; echo $passwd; tar -cz foo.*) | ssh 
remote_host "sudo -S bash -c \"tar -C /var/www/ -xz; echo\""
[sudo] password for bruce: 
[1]+  Stopped                 ( stty -echo; read passwd; stty echo; echo 
$passwd; tar -cz foo.* ) | ssh remote_host "sudo -S bash -c \"tar -C 
/var/www/ -xz; echo\""

$ pstree -lap $$
bash,7168
  ├─bash,7969
  ├─pstree,7972 -lap 7168
  └─ssh,7970 remote_host sudo -S bash -c "tar -C /var/www/ -xz; echo"`

Наша интерактивная оболочка - PID 7168, наша подоболочка - PID 7969, а наш процесс ssh - PID 7970.

Единственным недостатком является то, что read примет ввод, прежде чем sudo успеет отослать ответ. На быстром соединении и быстром удаленном хосте вы не заметите этого, но можете сделать это медленно. Любая задержка не повлияет на возможность ввода приглашения; это может появиться только после того, как вы начали печатать.

Примечание. Я просто добавил запись файла хоста для "remote_Host" на мою локальную машину для демонстрации.

Брюс
источник