opscape

Networking and remote

ssh-copy-id

Install your public SSH key in a remote account's authorized_keys so you can log in without a password.

ssh-copy-id [-i [KEY.pub]] [-p PORT] [-n] [-f] [-t TARGET] [USER@]HOST

6 of 6 examples run in Debian 13.7 on 2026-10-31 · openssh-client 1:10.0p1-7+deb13u4 · manual: ssh-copy-id(1)

ssh-copy-id host logs in to host (with a password, the last time you will need it) and appends your public key to ~/.ssh/authorized_keys there, creating the directory and file with the right permissions if needed. After that, ssh, scp and rsync log in with the key.

It first tries to log in with each candidate key, and skips keys that already work, so running it twice does not add duplicates. -i picks a specific key; without it, ssh-copy-id uses the keys in your ssh agent, or else your newest ~/.ssh/id_*.pub.

It is a shell script that only needs a working ssh login, so it works against any server. When you cannot use it, the manual equivalent is cat key.pub | ssh host 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys' plus fixing permissions (chmod 700 ~/.ssh; chmod 600 ~/.ssh/authorized_keys). In the sandbox, server is the machine itself and the default key is already installed.

Examples

Running it when the key is already installed

ssh-copy-id server
explain
output
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/dev/.ssh/id_ed25519.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed

/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.
		(if you think this is a mistake, you may want to use -f option)

ssh-copy-id found the default key, logged in with it successfully, and therefore installed nothing. The warning is informational and the exit status is 0, so it is safe to run repeatedly from provisioning scripts.

Preview which keys would be installed

Setup run before this example
ssh-keygen -q -t ed25519 -C deploy@ci -f ./deploy_key -N ''
ssh-copy-id -n -i deploy_key.pub server
explain
output
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "deploy_key.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
=-=-=-=-=-=-=-=
Would have added the following key(s):

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIvmoKuS6vOgqonogcrZS270fnRbj9i3y0K+WO24eVtZ deploy@ci
=-=-=-=-=-=-=-=

-n does everything except the copy: it checks that the new key does not already work, then prints the exact line it would add.

Install a new key and log in with it

Setup run before this example
ssh-keygen -q -t ed25519 -C deploy@ci -f ./deploy_key -N ''
ssh-copy-id -i deploy_key.pub server
ssh -i deploy_key -o IdentitiesOnly=yes server 'tail -n 1 ~/.ssh/authorized_keys'
output
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "deploy_key.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys

Number of key(s) added: 1

Now try logging into the machine, with: "ssh -i ./deploy_key 'server'"
and check to make sure that only the key(s) you wanted were added.

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL5oue4QVJ4VoWzKWyIbF+HUMNfZsXrHLOK36PyBQ3di deploy@ci

ssh-copy-id reports one key added and suggests a test login. The second command does that test: IdentitiesOnly=yes makes ssh offer only deploy_key, and the last line of authorized_keys on the server is the new key.

A server on another port

ssh-copy-id -p 2222 server
explain
outputexit 1
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/dev/.ssh/id_ed25519.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed

/usr/bin/ssh-copy-id: ERROR: ssh: connect to host server port 2222: Connection refused

ssh-copy-id passes -p to ssh. Nothing listens on 2222 here, so ssh cannot connect and ssh-copy-id fails with exit status 1. With a Port line in ~/.ssh/config you can leave -p out.

Write to a different authorized_keys file

Setup run before this example
ssh-keygen -q -t ed25519 -C backup@nas -f ./backup_key -N ''
ssh-copy-id -f -i backup_key.pub -t /home/dev/demo/authorized_keys.test server
cat authorized_keys.test
output
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "backup_key.pub"

Number of key(s) added: 1

Now try logging into the machine, with: "ssh -i 'server'"
and check to make sure that only the key(s) you wanted were added.

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIDV74ZbGT0gH2eiToKZAziGmYokL0tJD7AynXcxbbz0 backup@nas

-t PATH (in recent OpenSSH releases) installs the key into another file on the server, for setups where sshd reads keys from a central location. -f skips the trial login with the new key, which could not succeed here anyway since sshd does not read that file. In this mode the suggested test command even leaves out the key name; ignore it.

The manual equivalent without ssh-copy-id

Setup run before this example
ssh-keygen -q -t ed25519 -C deploy@ci -f ./deploy_key -N ''
ssh server 'umask 077; mkdir -p keys-test && cat >> keys-test/authorized_keys' < deploy_key.pub
ssh server 'ls -l keys-test/authorized_keys'
output
-rw------- 1 dev dev 91 Oct 31 20:21 keys-test/authorized_keys

This is essentially what ssh-copy-id does: append the public key over ssh, with a umask that makes the directory 700 and the file 600. On a real server the path is ~/.ssh/authorized_keys; the example writes to a test directory instead.

Common pitfalls

  • If key login still asks for a password after ssh-copy-id, check permissions on the server: ~ must not be group- or world-writable, ~/.ssh should be 700 and authorized_keys 600, or sshd ignores the file.

  • ssh-copy-id -i ~/.ssh/id_ed25519 (without .pub) still installs the public key; it adds .pub itself. Never copy the private file anywhere.

  • -f skips the "already installed" check and can add duplicate lines.

GNU vs BSD and macOS

The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).

  • ssh-copy-id ships with OpenSSH on Linux and recent macOS. Old macOS releases lacked it; the manual cat key.pub | ssh host ... pipeline works everywhere.

Options worth knowing

A selection, described in our own words. For the full list, see ssh-copy-id(1) or ssh-copy-id --help.

OptionWhat it does
-i FILEInstall this key (the .pub is used even if you name the private file).
-p PORTConnect to PORT on the remote host.
-nDry run: show the keys that would be installed.
-fForce: install without checking whether the key already works.
-sUse SFTP instead of running commands on the remote side.
-t PATHInstall into PATH on the remote host instead of ~/.ssh/authorized_keys.
-F FILEUse FILE as the ssh configuration.
-o OPTIONPass an option to ssh.
-xTrace the script for debugging.

Related