我有一台要使用SSH连接到的Ubuntu服务器。

我需要将机器中的文件上传到服务器上的/var/www//var/www/中的文件归root所有。 />使用PuTTY,登录后,我必须先输入sudo su和密码才能修改/var/www/中的文件。

但是当我使用WinSCP复制文件时,我可以t在/var/www/中创建创建/修改文件,因为与我连接的用户没有对/var/www/中文件的权限,因此我无法像在ssh会话中一样说sudo su

你知道我该怎么处理吗?

如果我在本地计算机上工作,我会打gksudo nautilus,但在这种情况下,我只能通过终端访问该计算机。

评论

对于您的虚拟服务器提供商,腻子或winscp开发人员来说,这似乎更像是一个问题。

@dobey您显然是错误的,这与ubuntu特权有关!

为什么关闭?这是关于使用scp复制文件的完全正确的问题-每个Web开发人员都熟悉这种情况

在服务器之间在一行中复制受保护的文件?应该有所帮助。

我有一个类似的问题。我在Windows计算机上创建了一个文件(在这种情况下为HTML),并尝试使用WinSCP将其复制到/ var / www / html / website文件夹。它说存在权限问题。因为我可以复制到/ home文件夹,所以我分两个步骤复制了文件,但它不是很方便:-)我尝试将用户添加到www-data组,但没有帮助。为什么不向用户添加到www-data的任何想法仍然不允许用户将文件复制到www-data组拥有的文件夹中?

#1 楼

没错,使用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,但是由于某些原因,此功能被禁用,因此我强烈建议您不要这样做。 />

评论


我没有第一个解决方案,请您更具体一点吗?

– Dimitris Sapikas
2012年10月30日9:42

我说我自己的文件,我的意思是/ var / www,我将我的vps用作Web服务器....在我自己的文件夹中,我具有完全访问权限

– Dimitris Sapikas
2012年10月30日在9:44

回覆。第一个解决方案。 1. scp -R mysite dimitris@myserver.com:/ home / dimitris / 2. ssh dimitris@myserver.com 3. sudo mv〜/ mysite / var / www-这是一个两步过程,首先将文件scp您的主目录,然后通过ssh登录并将文件复制/移动到应放置的位置

–谢尔盖
2012年10月30日在21:58

您无法设置root帐户将scp用于root拥有的文件,这很荒谬。 sudo根本不起作用。谁拥有我的电脑我或Canonical?从这方面来说,它与Android和Google一样糟糕。恕我直言。我只想将文件从/ usr / local / bin从我拥有的一台计算机复制到我拥有的另一台计算机。

–WinEunuuchs2Unix
20年6月23日,下午2:21

@ WinEunuuchs2Unix:的确,您可以设置计算机,以便您可以以root用户身份进行SSH,只需要对配置进行一点更改即可。完成后,您可以根据需要以root用户身份将文件尽可能多地作为scp文件。

–谢尔盖
20 Jun 25'2:46

#2 楼

快速方法

从服务器到本地计算机:

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


从本地计算机到服务器:

cat /home/user/file | ssh user@server "sudo tee -a /etc/dir/file"


评论


这个答案被低估了。它简单,干净,只需一个原子操作即可读取或写入根文件,并且如果您使用的是scp,则不需要保证没有任何内容。主要缺点是它不复制权限。如果需要,tar解决方案更好。这是一项强大的技术,尤其是与xargs / bash魔术结合使用以遍历路径时。

– markgo2k
18年5月16日在18:12

做得漂亮。这正是我一直在寻找的东西。谢谢

–杰里米
19 Mar 28 '19 at 16:32

是否可以对目录而不是文件执行此操作?

–lucidbrot
19年8月11日在15:06

...但您需要将-t传递给ssh,除非{一些先决条件}。否则,它将以sudo出现错误:不存在tty并且未指定askpass程序。然后开球-a?问题是关于复制,而不是附加并同时回显到stdout。

– conny
19年8月21日在7:33



我将围绕sudo添加另一种方法:不存在tty且未指定askpass程序是指定“ sudo -S cat / etc / dir / file”,而不是仅“ sudo cat / etc / dir / file”

–rh16
20年7月21日在2:05

#3 楼

另一种方法是使用tar + ssh而不是scp复制:

tar -c -C ./my/local/dir \
  | ssh dimitris@myserver.com "sudo tar -x --no-same-owner -C /var/www"


评论


这是最好的方法。

– mttdbrd
15年3月30日在20:31

我无法使这种方法成功工作。按照我写的sudo:抱歉,您必须有一个tty才能运行sudo。如果我添加“ -t”来分配TTY,那么我将不会分配伪终端,因为stdin不是终端。.如果没有无密码的sudo,我将看不到它的工作。

– IBBoard
15年10月26日在16:35

@IBBoard:使用ssh -t在这里尝试解决方案:ssh -t dimitris@myserver.com“ sudo tar -x --no-same-owner -C / var / www”

–亚历山大·伯德(Alexander Bird)
16年8月18日在15:21



@AlexanderBird虽然在很多情况下都可以使用,但我不确定它在这里是否可以使用,因为我们正在尝试通过SSH连接传递压缩包。参见serverfault.com/questions/14389/…

– IBBoard
16年8月19日在19:36

这终于对我有用。您无权复制要复制到本地的远程文件,执行sudo tar,对其进行存档,使用chmod和chown更改权限,然后将其复制到本地。特别是在目录下。

–计算器
18年8月9日在9:07

#4 楼

您还可以使用ansible完成此操作。
使用ansible的copy模块复制到远程主机:
ansible -i HOST, -b -m copy -a "src=SRC_FILEPATH dest=DEST_FILEPATH" all

使用ansible的fetch模块从远程主机获取:
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仅复制文件,不复制导致文件的整个远程路径
使用通配符这些ansible模块不支持文件路径中的

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对于管理远程服务器非常有用,因此安装它肯定会为您带来除部署文件之外的其他好处。

评论


我喜欢这个答案,但我建议您将其直接针对所提出的问题,而不是更普遍的评论。类似于ansible -i“主机名”,所有-u用户--become -m复制-a ...

– Mike D
16年2月16日在19:30

@MikeD:以上更改看起来如何?

–erik.weathers
16-2-19的3:08

像-i'host'这样的语法会有效吗?我认为在阅读命令时很容易丢失标点符号。 (对于读者,我的意思是,如果不是外壳的话。)

–mwfearnley
16年6月10日在15:37

@mwfearnley:可以肯定的是,shell将-i'host'与-i host或-i“ host”相同。总的来说,我宁愿使这些调用尽可能短,以免使它们望而生畏,但是您应该随心所欲地使它变得冗长而明确,因为您认为它们很清楚。

–erik.weathers
16年6月15日在3:00

在框外思考的方式!大量使用Ansible

– jonatan
18年9月16日在9:19

#5 楼

也许最好的方法是通过SSH使用rsync(在Windows中为Cygwin / cwRsync)?例如,上传所有者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


请参阅:使用sudo的scp到远程服务器。

#6 楼

当您运行sudo su时,您创建的任何文件都将由root拥有,但是默认情况下不可能直接使用ssh或scp作为root登录。也无法将sudo与scp一起使用,因此这些文件不可用。通过声明对文件的所有权来解决此问题:

假设您的用户名是dimitri,则可以使用此命令。

sudo chown -R dimitri:dimitri /home/dimitri


,如其他答案中所述,“ Ubuntu”方法是使用sudo,而不是root登录。这是一个有用的范例,具有很大的安全优势。

评论


我正在以任何方式使用此解决方案,但是如果我可以完全访问自己的文件系统该怎么办,我不想为每个目录输入sudo chow ...:

– Dimitris Sapikas
2012年10月30日9:47

不建议将所有系统文件的所有权更改给用户以方便传递。它使您可能遇到的任何用户空间错误都会严重损害系统的安全性。最好更改您需要由SCP更改或更新的文件的所有权,而让其他所有内容都由root拥有(如理应如此)。就是说,chown中的-R告诉它更改该目录的所有权以及所有子文件和目录的递归...因此您可以执行任何您喜欢的事情。

– gn
2012年10月30日17:48

嗯..看起来很好,谢谢!抱歉,我无法投票(系统不允许我执行...)

– Dimitris Sapikas
2012年10月30日19:05

#7 楼

如果使用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 .


#8 楼

这是Willie Wheeler答案的修改版本,它可以通过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\""


额外的魔力是sudo的-S选项。在sudo手册页中:


-S,--stdin
将提示写入标准错误,并从标准输入中读取密码,而不使用终端设备。密码后必须带有换行符。


现在,我们实际上希望将tar的输出通过管道传递到ssh,并将ssh的stdin重定向到tar的stdout,删除任何从交互式终端将密码传递到sudo的方法。 (我们可以在远端使用sudo的ASKPASS功能,但这是另一回事。)我们可以通过预先捕获密码并将其放在tar输出中(通过在子shell中执行这些操作并将其输出管道化)来将密码输入sudo中。将subshel​​l放入ssh。这还具有一个额外的优点,即不会在交互外壳中保留包含悬空密码的环境变量。

您会注意到我没有使用-p选项执行“读取”来显示提示。这是因为来自sudo的密码提示已通过ssh方便地传递回了交互式shell的stderr。您可能想知道“鉴于sudo在管道右侧的ssh中运行,该如何执行?”当我们执行多个命令并将一个命令的输出传递到另一个命令时,父外壳程序(在本例中为交互式外壳程序)在执行前一个命令后立即按顺序执行每个命令。在执行管道后面的每个命令时,父外壳程序会将左侧的stdout附加(重定向)到右侧的stdin。然后,在通过过程时,输出变为输入。我们可以通过执行整个命令并在输入密码之前使进程组(Ctrl-z)后台运行,然后查看进程树来查看此操作。

$ (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进程是PID7970。

唯一的缺点是在sudo有时间将其提示发送回之前,read将接受输入。在快速连接和快速远程主机上,您不会注意到这一点,但如果两者都很慢,则可能会发现这一点。任何延迟都不会影响输入提示的能力;

注意,我只是将用于“ remote_Host”的主机文件条目添加到了用于演示的本地计算机。

评论


如果使用bash,则可以使用read -s passwd而不是stty -echo和stty echo。

–丹尼尔·哈丁(Daniel Harding)
20-04-14在13:33

#9 楼

您可能会使用受此主题启发而编写的脚本:

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


但这需要一些疯狂的东西(顺便说一句,由脚本自动完成) >

与源计算机建立ssh连接时,正在发送文件的服务器将不再询问密码
由于服务器上缺少sudo提示的必要性,sudo将不再询问用于远程计算机上的密码,用于用户

以下脚本:

interface=wlan0
if [[ $# -ge 3 ]]; then interface=; 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: q4312078q local_filename [username@](ip|host):(remote_folder/|remote_filename) [optionalInterface=wlan0]"
echo -e "Example: \n\ttouch /tmp/justtest &&\n\t q4312078q /tmp/justtest remoteuser@ssh.superserver.com:/tmp/ "
exit 1
fi

localFilePath=

test -e $localFilePath 

destString=
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
13年11月22日在1:42

#10 楼

您可以将ssh,sudo和例如tar结合使用,以在服务器之间传输文件,而无需以root用户身份登录并且没有与用户一起访问文件的权限。这有点奇怪,所以我写了一个脚本来帮助这个。您可以在以下位置找到脚本:https://github.com/sigmunau/sudoscp

或此处:

#! /bin/bash
res=0
from=
to=
shift
shift
files="$@"
if test -z "$from" -o -z "$to" -o -z "$files"
then
    echo "Usage: q4312078q    (file)*"
    echo "example: q4312078q server1 server2 /usr/bin/myapp"
    exit 1
fi

read -s -p "Enter Password: " sudopassword
echo ""
temp1=$(mktemp)
temp2=$(mktemp)
(echo "$sudopassword";echo "$sudopassword"|ssh $from sudo -S tar c -P -C / $files 2>$temp1)|ssh $to sudo -S tar x -v -P -C / 2>$temp2
sourceres=${PIPESTATUS[0]}
if [ $? -ne 0 -o $sourceres -ne 0 ]
then
    echo "Failure!" >&2
    echo "$from output:" >&2
    cat $temp1 >&2
    echo "" >&2
    echo "$to output:" >&2
    cat $temp2 >&2
    res=1
fi

rm $temp1 $temp2
exit $res


评论


欢迎来到Ask Ubuntu。您能否在回答中包含脚本?我知道这不太可能,但是如果github仓库被删除或URL被更改,那么答案将是无效的。最好直接包含该脚本,并保留github repo作为源。

–迈克尔·林德曼(Michael Lindman)
15年7月1日在15:25



#11 楼

我知道这是一个比较老的问题,但是时代在变化,一些技巧也在变化。万一有人仍在寻找简化的方法来完成此任务。

假设


您在服务器上的用户是个傻瓜。
您正在运行Windows10。
/var/www中的文件应该属于用户:组www-data:www-data


概念

概念是通过ssh组合远程命令和scp文件传输器,而不依赖于诸如PuTTyWinSCP之类的GUI。这些命令可以从Command PromptPowerShell运行。要执行的五个主要任务是:


环境设置
将文件传输到服务器
设置远程文件权限
在远程文件夹之间传输
清理

任务3-5可以一步完成。如果您计划经常执行此操作,则离开环境设置将使您可以忽略任务1和5。

环境设置

您可能已经或可能没有文件夹可以用作传输的临时存储库。如果不是,则可以运行:

ssh user@server.tld "mkdir ~/wwwtemp"


根据服务器的设置,可能会或可能不会提示您输入user的密码/口令来验证ssh会话。

一旦会话通过身份验证,将执行mkdir ~/wwwtemp命令,然后ssh会话将终止,并且您将在提示符下返回(Command PromptPowerShell)。

传输文件到服务器

下一步是使用scp将文件从本地Windows计算机传输到Ubuntu服务器,如下所示:

scp -R local\path user@server.tld:~/wwwtemp/


根据服务器的身份验证方法,您可能需要输入密码/密码。

文件的权限和最终目标

文件传输完成后,您可以可以像这样在ssh上运行一系列命令:

ssh -t user@server.tld "sudo chown -R www-data:www-data ~/wwwtemp  && sudo mv -R ~/wwwtemp/* /var/www/ && sudo rmdir ~/wwwtemp"


同样,根据服务器的身份验证方法,可能会提示您是否提示您输入password/passphrase。无论采用哪种身份验证方法,sudo都会提示您输入user的密码。除非,当然,除非在user运行chownmv时禁用了密码要求。请参阅此问题以获取有关如何执行此操作的指导。

此步骤涵盖任务3-5:




rmdir递归设置所需的文件权限在刚上传的文件上。

sudo chown -R www-data:www-data ~/wwwtemp将临时存储库的内容递归移动到其最终目的地。

sudo mv -R ~/wwwtemp/* /var/www/删除临时存储库。由于我们在任务3中更改了目录所有者,因此必须在此处使用sudo rmdir ~/wwwtemp。当然,sudo会分隔每个命令。这些命令将按顺序执行。如果计划保留存储库&&,则可以按顺序省略最终命令。

注意事项

可以在最终wwwtemp命令字符串末尾省略&& sudo rmdir ~/wwwtemp。您希望以后继续使用临时存储库。这样做还意味着每次希望以这种方式将文件传输到服务器时,都可以省略第一个ssh命令。