I have a shell script to set up the environment and install a relatively complex web application on a webserver, which has gradually evolved from a quick bad hack into a larger and slightly less bad hack.

Previously, my script had a built-in 'bootstrap' function to allow me to easily copy it from my development computer to the remote server for use, requesting root login to create a folder to place the script into and then to copy the script.

As this project has evolved, it now turns out that additional software that we will need to rely on expects a 'sudo' environment (rather than root login) for its own setup script, and so I'd like to switch the working of my setup script from expecting root to using sudo (especially as we may wish to share this with others, and for it to be able to work on servers where root is not available (eg, Ubuntu)).

At present, my bootstrap function does:

    SCRIPT=`basename $0`

    echo "Copying script '${SCRIPT}' onto server: '${RHOST}' into '${INSTALL_DIR}'"
    echo "(You need to login (as root) 2 times.)"
    ssh root@$RHOST "umask 027; mkdir -p $INSTALL_DIR"
    scp -p "$SCRIPT" root@$RHOST:/$INSTALL_DIR
    echo "Done. Now login to the server and run the script as root."

I am not sure how I can translate this to using sudo? scp expects me to login as the user who will be able to write to the folder where the file should go, which I won't be able to do if there is no root account?

Or perhaps I am making this too complicated? If the normal user on the remote server is essentially root-one-step-removed anyway, perhaps, rather than trying to create a 'tidy' place to store these admin scripts, I could just scp it somewhere into the user's own filespace, and the user could then in turn run the install part of the script from there using sudo. (I suppose the only issue that might then arise might be if a different administrator needed to run the script and couldn't access the other user's files..)


3 Answers 3


There are numerous ways to tackle this problem outside of SSH. In addition to that you are a bit ambiguous about the root account and the "sudo" environment. What I'm assuming is that you mean is that the root account does not allow shell access (which is the default on Ubuntu) and you have to give sudo access to users to be able to grant administrator permissions. The root account itself still exists (uid/gid 0).

Sticking with SSH and sudo

In the case of SSH, sudo, and securely copying files. You can can copy the file to a public location and then use sudo to copy or move it to the restricted location. This does have some security implications as the file is, at least, temporarily in a public location. There are also numerous approaches to mitigate the security factor of this issue.

Securely copy the file to a temporary location on the remote server.

scp -p xfer_file jschaeffer@aiur:/tmp

Now connect to the server using SSH and copy or move it to the permanent location.

ssh -t jschaeffer@aiur: sudo cp /tmp/xfer_file /perm

The key takeaway here is -t to ssh. From the man page.

 -t      Force pseudo-tty allocation.  This can be used to execute arbitrary screen-based programs on a
         remote machine, which can be very useful, e.g. when implementing menu services.  Multiple -t options
         force tty allocation, even if ssh has no local tty.

Don't prompt for a password at all

In addition to this you could define your sudo rule to not require a password and it wouldn't prompt the user.

Allowing password-less authentication to root for non-root users

Alternatives to this approach would be to use public keys. You can grant users access to another account through the use of public keys. This has its own security implications as well. You are giving users full root access to a box (a little tidbit about that below).

jschaeffer@defiler:~# ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/jschaeffer/.ssh/id_rsa):
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /jschaeffer/.ssh/id_rsa.
Your public key has been saved in /jschaeffer/.ssh/id_rsa.pub.

Then copy the public key to the remote server (make sure to copy the public key not the private). Because the entire discussion surrounds copying files to a server that doesn't allow direct root access I won't display the ssh-copy-id or scp commands that connects with the root account. Regardless, you have to find a way to transfer the key to ~root/.ssh/authorized_keys. Could use the strategy above or copy to a flash drive or some other method (rsync, ftp, etc)

The root account has to allow password-less authentication on the server. Make sure the settings are set correctly in /etc/ssh/sshd_config

# Authentication:
LoginGraceTime 120
PermitRootLogin without-password
StrictModes yes

Then just copy the file directly to the root account.

scp -p xfer_file root@aiur:/perm_location

You can restrict what users can actually do when they ssh by appending options to the authorized_keys file

Other options

Of course there are many other options which I will list but not go into detail:

  • Use Kerberos. Kerberos is an entire protocol designed around security in unsecure networks. This of course requires an entire environment, upkeep, hardware, etc, probably not what you are looking for. SSH integrates with Kerbero or you can use one of Kerberos's replacements of an unsecure transfer.
  • Copy the file to a temporary location on the server and have a cron job that is run as root on the remote server pick up files in that directory and transfer them to the permanent location
  • Rsync the file
  • Put the file in a public location (i.e. ftp, sftp, http) that both servers have access to.
  • Re-enable the root account.
  • Thanks for your detailed answer. I think that scp to a temporary location, followed by cp/mv (via ssh), might be the easiest adaptation for me to make.
    – dave559
    Mar 28, 2017 at 15:40

For rsync, there is a pattern people have used to implement this. Most Linux installs include rsync by default.

rsync -e "ssh -t" --rsync-path="sudo rsync" ...

-- https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Automated_Backup#Backup_with_rsync_and_sudo


Instead of pushing the data somewhere you can't easily write, how about pulling the data? Or pushing the data somewhere else that can be written to, followed by something on the remote system putting the data in place? --probably when the app gets bounced to pick up the new files?

Also be careful that some of the suggestions are weakening the security of your production system.

  • My reason for asking was that I wanted, if possible, to avoid a multi-step procedure for 'bootstrapping' the installation script onto the remote server if at all possible, but I agree that 'pulling' the file across might perhaps be easier, although involving more typing on my part!
    – dave559
    Mar 28, 2017 at 15:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .