60

Here is what I have tried, and I got an error:

$ cat /home/tim/.ssh/id_rsa.pub | ssh tim@just.some.other.server 'cat >> .ssh/authorized_keys'
Password: 
cat: >>: No such file or directory
cat: .ssh/authorized_keys: No such file or directory
Anthon
  • 79,293
Tim
  • 101,790

7 Answers7

111

OpenSSH comes with a command to do this, ssh-copy-id. You just give it the remote address and it adds your public key to the authorized_keys file on the remote machine:

$ ssh-copy-id tim@just.some.other.server

You may need to use the -i flag to locate your public key on your local machine:

$ ssh-copy-id -i ~/.ssh/id_rsa.pub tim@just.some.other.server
Michael Mrozek
  • 93,103
  • 40
  • 240
  • 233
  • 1
    Thanks! Why my command doesn't work? – Tim Jan 18 '12 at 20:18
  • @Tim This answer explained it; >> is handled by your shell, and you're running the command through SSH instead of through a shell. His fix of having SSH run a shell, which then runs your command, should work – Michael Mrozek Jan 18 '12 at 20:22
  • Thanks! (1) ssh-copy-id doesn't work either. I manually copy the file to the remote and append its content, then it works. I wonder why is this? I found that my default shell on the server is some script, which I update to my original post, and might be the reason. Please have a look. (2) I wonder if ssh-copy-id is just copy the public key to the remote, it doesn't create the private and public key, does it? – Tim Jan 18 '12 at 20:37
  • Okay, I crated a new post for my default shell problem – Tim Jan 18 '12 at 21:19
  • Ah, ok. It turns out SSH does run commands through the default shell (so the method from the question would work on most machines), but your default shell is some bizarre wrapper script that doesn't handle it properly – Michael Mrozek Jan 18 '12 at 23:42
  • 1
    Let's assume the SSH server is configured in such a way that it only accepts public key authentication as a authentication mechanism. In that case, using ssh-copy-id won't work, right? – Abdull Jun 07 '16 at 15:24
  • 1
    @Abdull Not unless you already have some other key on that machine to connect with. It's just connecting over SSH – Michael Mrozek Jun 07 '16 at 15:31
46

You could always do something like this:

scp ~/.ssh/id_rsa.pub user@remote.example.com:/tmp/id_rsa.pub
ssh user@remote.example.com 
cat /tmp/id_rsa.pub >> ~/.ssh/authorized_keys

I am not sure if you can cat from a local machine into an ssh session. Just move it to /tmp as suggested.

Edit: This is exactly what ssh-copy-id does. Just like Michael said.

  • Thanks! I wonder if ssh-copy-id is just copy the public key to the remote. It doesn't create the private and public key, does it? – Tim Jan 18 '12 at 20:51
  • No it doesn't create it. Just adds it. – Mr. Monkey Jan 18 '12 at 21:22
  • @Mr.Monkey Yes, you can pipe data into an ssh session (from cat or otherwise). What you're describing is the old-fashioned way; ssh-copy-id is recommended because there's less risk of typos or giving files wrong permissions. – Gilles 'SO- stop being evil' Jan 18 '12 at 23:19
  • @Gilles , You not always have access to the server to the client, especially when you're preparing a computer for its operation, so this method is much better than using ssh-cpy-id because you do not need to take the equipment or connect to the network before setting. – e-info128 Oct 26 '16 at 19:13
  • 1
    Or you can just pipe directly to the destination: cat ~/.ssh/id_rsa.pub | ssh <user>@<hostname> 'cat >> ~/.ssh/authorized_keys'. – Pablo A Jan 28 '18 at 02:12
10

This answer describes how to make the intended way shown in the question working.

You can execute a shell on the remote computer to interpret the special meaning of the >> redirection operator:

ssh tim@just.some.other.server sh -c "'cat >> .ssh/authorized_keys'" < /home/tim/.ssh/id_rsa.pub

The redirection operator >> is normally interpreted by a shell.

When you execute ssh host 'command >> file' then it is not guaranteed that command >> file will be interpreted by a shell. In your case command >> file is executed instead of the shell without special interpretation and >> was given to the command as an argument -- the same way as running command '>>' file in a shell.

Some versions of SSH (OpenSSH_5.9) will automatically invoke shell on the remote server and pass the command(s) to it when they detect tokens to be interpreted by a shell like ; > >> etc.

  • ssh tim@just.some.other.server 'cat >> .ssh/authorized_keys' < /home/tim/.ssh/id_rsa.pub also work, leaving sh -c – Timo Mar 13 '21 at 10:14
  • 1
    @Timo Yes, I tested this between current versions of Ubuntu (OpenSSH_8.2p1) and Debian (OpenSSH_7.9p1) and it works. ...but there is some trickery: in some cases the command is run directly on the server: command in other cases it is run using shell: bash -c command. I was not able to find in the OpenSSH documentation about how it is decided which way will OpenSSH use. It seems to be decided on the server side. --- To wrap it up: your shorter code might or might not work. --- I tried to explain this in my answer. – pabouk - Ukraine stay strong Mar 13 '21 at 12:27
5

Avoiding ssh-copy-id

Taken from the answers/comment to the Original Poster(OP)'s question:

1. with redirection (ssh at beginning)

ssh <user>@<host> 'cat >> ~/.ssh/authorized_keys' < ~/.ssh/id_rsa.pub

2. with pipe (ssh not at beginning)

cat ~/.ssh/id_rsa.pub | ssh <user>@<host> 'cat >> ~/.ssh/authorized_keys'
Timo
  • 338
3

openssh does provide ssh-copy-id. The sequence would be:

  • Generate a decent 4k key

    ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa4k
    
  • Start your ssh-agent up and suck in information like SSH_AGENT_PID, etc.

    ssh-agent -s > ~/mysshagent
    source ~/mysshagent
    rm ~/mysshagent
    
  • Now start loading keys into your SSH Agent

    ssh-add ~/.ssh/id_rsa4k
    
  • Check that it is loaded

    ssh-add -l
    ssh-add -L
    

    This will show you what you have in the ssh-agent

  • Now actually SSH to a remote system

    ssh username@remotehost.network
    
  • Now you can run ssh-copy-id with no arguments:

    ssh-copy-id
    

    This creates ~/.ssh/authorized_keys and fills in the basic info required from ssh-agent.

Michael Mrozek
  • 93,103
  • 40
  • 240
  • 233
  • BTW, I created a small script at https://github.com/centic9/generate-and-send-ssh-key which runs most of these steps in one go and additionally ensures file/directory permissions which usually always caused me headaches... – centic Oct 07 '15 at 11:24
  • This is a great method to use when password login is disabled. It allows adding a new key while authenticating with a prior key. – MountainX Feb 19 '18 at 22:45
1

I had troubles with ssh-copy-id when choosing another port than 22... so here is my oneliner with a different ssh-port (e.g. 7572):

ssh yourServer.dom -p7572 "mkdir .ssh; chmod 700 .ssh; umask 177; sh -c 'cat >> .ssh/authorized_keys'" < .ssh/id_rsa.pub
1

Indeed the the ssh-copy-id command does exactly this (from the openssh-client package):

ssh-copy-id user@host

Note:
host means IP address or domain.


I would like also to add some additional information to this

1) We can specify a different port for SSH on destination server:

ssh-copy-id "-p 8127 user@host"

Note:
The port must be in front of the user@host or it will not resolve.

Source

2) We can specify a file with a public key:

ssh-copy-id -i ~/.ssh/id_rsa.pub user@host

Note:
The -i option allows us to indicate the appropriate location of the name with the file that contains the public key.

Sometimes it can come in handy, especially if we store it in a non-standard location or we have more than one public key on our computer and we want to point to a specific one.