Як скопіювати файли, яким потрібен кореневий доступ із scp?


167

У мене є сервер Ubuntu, до якого я підключаюсь за допомогою SSH.

Мені потрібно завантажувати файли з моєї машини /var/www/на сервер, причому ці файли /var/www/належать root.

Використовуючи PuTTY, після входу в систему я повинен sudo suспершу ввести та свій пароль, щоб мати змогу змінювати файли в /var/www/.

Але коли я копіюю файли за допомогою WinSCP, я не можу створювати / редагувати файли в /var/www/, тому що користувач, з яким я підключаюся, не має дозволів на файли в, /var/www/і я не можу сказати, sudo suяк це роблю у випадку сеансу ssh. .

Ви знаєте, як я міг би з цим впоратися?

Якби я працював на своїй локальній машині, я б зателефонував, gksudo nautilusале в цьому випадку у мене є тільки термінальний доступ до машини.


Це більше схоже на питання для вашого постачальника віртуальних серверів, або для розробників шпаклівки або wincp.
добі

7
@dobey ви невірно помиляєтесь, мова йде про привілеї ubuntu!
Димитріс Сапікас

7
Чому це закрито? Це ідеально правильне питання щодо копіювання файлів за допомогою scp - кожен веб-розробник знайомий з цією ситуацією
Сергій


У мене схожа проблема. Я створюю файл (HTML в цьому випадку) на комп'ютері Windows і намагаюся скопіювати його з WinSCP в папку / var / www / html / website. І це говорить про те, що є проблема з дозволом. Оскільки я можу скопіювати в свою / домашню папку, я скопіював файл у два кроки, але це не дуже зручно :-) Я спробував додати свого користувача до групи даних www, але це не допомогло. Будь-яка ідея, чому додавання користувачеві до даних www все ще не дозволяє користувачеві копіювати файл у папку, яка належить групі даних www?
JanezKranjski

Відповіді:


125

Ви маєте рацію, 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
Re. перше рішення. 1. scp -R mysite dimitris@myserver.com:/home/dimitris/2. ssh dimitris@myserver.com3. sudo mv ~/mysite /var/www- це двоетапний процес, спочатку ви scpнадсилаєте файли до свого домашнього dir, потім ви входите через 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, а потім скопіюйте їх у локальний. Особливо, якщо це каталог.
форумчатор

27

Швидкий шлях

Від сервера до локальної машини:

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

Я думаю, питання полягало у завантаженні файлу з локального на віддалений, а не навпаки
Кораєм

1
Красиво зроблено. Це саме те, що я шукав і вгору, і вниз. Дякую
Джеремі

Заслуговує на найкращу відповідь.
Ендрю Уотсон

Чи можна це зробити і для каталогу, а не для файлу?
lucidbrot

26

Ви також можете використовувати ansibleдля цього.

Скопіюйте на віддалений хост за допомогою модуля ansiblecopy :

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

Витягнутиfetch з віддаленого хоста за допомогою модуля ansible :

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-method- sudo.
  • 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 -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
jonatan

12

Під час запуску sudo suбудь-які створені вами файли матимуть корінь, однак за замовчуванням неможливо безпосередньо увійти як root за допомогою ssh або scp. Також не можна використовувати sudo з scp, тому файли не можна використовувати. Виправте це, заявляючи право власності на свої файли:

Якщо припустити, що ваше ім’я користувача було dimitri, ви можете використовувати цю команду.

sudo chown -R dimitri:dimitri /home/dimitri

З цього моменту, як згадується в інших відповідях, способом "Ubuntu" є використання sudo, а не кореневі логіни. Це корисна парадигма, що має великі переваги безпеки.


Я використовую це рішення будь-яким способом, але що робити, якщо я можу отримати повний доступ до власної файлової системи, я не хочу вводити sudo chow ...для кожного каталогу: S
Димитріс Сапікас

2
Зміна власності на всі системні файли користувачеві для зручності передачі вкрай не рекомендується. Це дозволяє будь-якій помилку в просторі користувачів, з якою ви зіткнетеся, серйозно поставити під загрозу безпеку вашої системи. Набагато краще змінити право власності на файли, які потрібно змінити або оновити SCP, але залишити все інше, що належить root (як і належить). Тим не менше , -Rв chownговорить це , щоб змінити власника каталогу, і всі діти файли і каталоги рекурсивно ... так що ви можете зробити все , що завгодно.
трогнандри

хм .... це, здається, працює добре, дякую! вибачте, що не можу підняти пропозицію (система не дозволяє мені це робити ...)
Димитріс Сапікас

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 .

1

Ви можете використовувати сценарій, про який я написав, натхненний цією темою:

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

але для цього потрібні деякі шалені речі (які BTW. автоматично робиться сценарієм)

  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

@Braiam так, звичайно, вибачте за посилання, сценарій досить довгий і це було причиною :)
test30

1

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

або тут:

#! / бін / баш
res = 0
від = 1 дол
до = 2 дол
зрушення
зрушення
files = "$ @"
якщо тест -z "$ з" -o -z "$ до" -o -z "файли $"
тоді
    відлуння "Використання: $ 0 (файл) *"
    echo "приклад: $ 0 server1 server2 / usr / bin / myapp"
    вихід 1
фі

read -s -p "Введіть пароль:" sudopassword
відлуння ""
temp1 = $ (mktemp)
temp2 = $ (mktemp)
(echo "$ sudopassword"; echo "$ sudopassword" | ssh $ від sudo -S tar c -P -C / $ файли 2> $ temp1) | ssh $ to 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
    відлуння ""> & 2
    echo "$ to output:"> & 2
    cat $ temp2> & 2
    res = 1
фі

rm $ temp1 $ temp2
вихід $ res

Ласкаво просимо до Ask Ubuntu. Чи можете ви включити у відповідь сценарій? Я знаю, що це малоймовірно, але якщо коли-небудь видалити github repo або змінити URL, то відповідь буде недійсною. Краще включити сценарій безпосередньо і залишити github repo як джерело.
Майкл Ліндман

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:

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

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

Ви помітите, що я не виконував "читати" за допомогою параметра -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.

Єдиним недоліком є ​​те, що читання прийме вхід до того, як судо встигне повернути його підказки. При швидкому з'єднанні та швидкому віддаленому хості ви цього не помітите, але, можливо, якщо це буде повільно. Будь-яка затримка не вплине на можливість ввести підказку; це може з’явитися після того, як ви почали вводити текст.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.