27.2 ssh-copy-id: Deploying Public Keys to Remote Hosts
Right, so you’ve generated your SSH key pair. You’ve got this lovely little id_ed25519.pub file sitting there, full of promise. It’s like a high-tech key you just cut. But a key is useless unless you actually put it in the lock on the other side. That’s where ssh-copy-id comes in. It’s the part of the process where you stop admiring your own cleverness and actually get to log in without a password.
Think of it as your automated, hyper-competent courier. You tell it the address of the remote server (user@hostname) and it handles the incredibly tedious job of:
- Logging in via SSH (yes, it needs your password this one last time, so have it ready).
- Appending the contents of your public key file to the remote user’s
~/.ssh/authorized_keysfile. - Setting the correct, draconian file permissions on that remote
~/.sshdirectory and theauthorized_keysfile itself, because SSH will utterly refuse to work if they’re even slightly wrong. It’s security software; it’s allowed to be paranoid and fussy.
The beauty is its simplicity. The most common incantation is stupidly straightforward:
ssh-copy-id user@remote.host.com
This command assumes you’re using the default key file (~/.ssh/id_rsa.pub or ~/.ssh/id_ed25519.pub). It will find it, read it, and ship it off. It’ll then prompt you for the password for that remote user account. Go on, type it in. This is the last time you’ll have to do this for this user on this host, I promise.
What If My Key Isn’t Named id_anything.pub?
You’re a special snowflake who used the -f flag to give your key a unique, memorable name like my_awesome_key. I respect that. But now ssh-copy-id can’t find it on its own. No problem. You just have to point the courier directly to the package it needs to deliver using the -i flag.
ssh-copy-id -i ~/.ssh/my_awesome_key.pub user@remote.host.com
Crucially, you point it at the public key (the one ending in .pub). The command is smart enough to know you’d never, ever be dumb enough to try to send your private key over the network. Right? Right? (Don’t do that.)
The Black Magic It Performs (And How To Do It Manually)
So what is this courier actually doing that’s so great? Let’s pull back the curtain. If you had to do this by hand, the steps would be:
# Step 1: SSH in with your password (one last time)
ssh user@remote.host.com
# Step 2: On the remote host, ensure the .ssh directory exists with correct permissions
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# Step 3: Append your LOCAL public key to the remote authorized_keys file
# This is the clever one-liner that does the magic from your local machine:
cat ~/.ssh/id_ed25519.pub | ssh user@remote.host.com 'cat >> ~/.ssh/authorized_keys'
# Step 4: On the remote host, lock down the authorized_keys file permissions
chmod 600 ~/.ssh/authorized_keys
ssh-copy-id does all of this, perfectly, every time. It’s a fantastic little script that saves you from a world of permission-related headaches and typos. The fact that this isn’t built into the core ssh client is a bit of a mystery, but I’m just glad it exists.
When The Automatic Courier Breaks Down
It’s not foolproof. Sometimes you’ll run ssh-copy-id, type in the correct password, and get a connection closed message. Infuriating. The two most common culprits are:
- The remote
~/.sshdirectory already exists with wrong permissions. If it’s world-readable (e.g.,755), the SSH daemon loses its mind. The courier can’t fix this from the outside. You’ll have to log in the old-fashioned way and runchmod 700 ~/.ssh. - Password authentication is completely disabled on the remote host. This is a great, secure practice, but it makes deploying your first key a classic chicken-and-egg problem. Your only way in is through some other means, like a cloud provider’s web-based console. Once you’re in, you can manually create the
authorized_keysfile as shown above.
The Grand Finale: Testing It Worked
Never just assume. After you run ssh-copy-id, the final, glorious step is to test it.
ssh user@remote.host.com
If you’re greeted by a shell prompt without a password prompt, you’ve achieved nirvana. Go ahead and do it a few more times just for the thrill. It never gets old. Now go set up a config file for that host so you don’t have to type user@hostname ever again. But that’s a topic for another section.