Руководства

ssh-copy-id: как скопировать SSH-ключ на сервер и что делать в Windows

ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host дописывает открытый SSH-ключ в authorized_keys. Как создать ключ, все параметры, замена для Windows и ошибки.

Опубликовано ~10 мин чтения

Коротко: ssh-copy-id -i ~/.ssh/id_ed25519.pub USER@SERVER_IP копирует ваш открытый SSH-ключ в ~/.ssh/authorized_keys на сервере, и дальше вы входите по ключу, а не по паролю. Для этого утилите нужно хотя бы раз войти на сервер, обычно по паролю; ключи, которые уже установлены, она пропускает. В Windows ssh-copy-id нет; строка PowerShell, которая делает то же самое, — ниже.

Linux · macOS
ssh-copy-id -i ~/.ssh/id_ed25519.pub USER@SERVER_IP

Вместо USER подставьте учётную запись, под которой хотите входить (на новом VPS это часто root), а вместо SERVER_IP — адрес сервера. ssh-copy-id входит в клиент OpenSSH в Linux и поставляется с macOS. Всё, что описано ниже, проверено по самому скрипту в OpenSSH 9.2 (Debian 12) и по man-странице более новых версий.

Шаг 1: создайте ключ, если его ещё нет

Сначала поищите готовый ключ: ls ~/.ssh/*.pub. Если в списке есть id_ed25519.pub, переходите к шагу 2. Иначе создайте ключ Ed25519 на своём компьютере — никогда не на сервере:

Linux · macOS · Windows PowerShell
ssh-keygen -t ed25519 -C "you@laptop"

-C задаёт только комментарий в конце открытого ключа, чтобы потом различать ключи в authorized_keys; подойдёт любая метка. Нажмите Enter, чтобы принять имя файла по умолчанию, затем задайте парольную фразу. -t ed25519 пишите явно: OpenSSH сделал Ed25519 типом по умолчанию в версии 9.5, а более старые, включая 9.2 из Debian 12, без этого флага по-прежнему создают ключи RSA.

Пример вывода
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/you/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/you/.ssh/id_ed25519
Your public key has been saved in /home/you/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:nzRUX6Jlgiu7/hcjnTQRyqk+qs3nGDVZ/mIZS1pw4OM you@laptop

id_ed25519 — закрытый ключ, он остаётся на вашем компьютере. id_ed25519.pub — одна строка, которая начинается с ssh-ed25519, и на серверы отправляется только этот файл. В Windows оба файла лежат в C:\Users\имя\.ssh. OpenSSH свои сообщения не переводит, поэтому вывод выше одинаков в любой локали.

Шаг 2: скопируйте ключ с помощью ssh-copy-id

Linux · macOS
ssh-copy-id -i ~/.ssh/id_ed25519.pub USER@SERVER_IP
Пример вывода
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/you/.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: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
alice@203.0.113.10's password:

Number of key(s) added: 1

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

Так выглядит вывод OpenSSH 9.2; в новых версиях последние строки сформулированы немного иначе. При первом подключении к серверу ssh ещё до этого попросит подтвердить его ключ хоста; отвечайте yes, только если это действительно нужный сервер. За этим выводом скрипт делает три вещи:

  • Выбирает ключи. С -i — только указанный файл; к имени без .pub расширение дописывается. Без -i он устанавливает все ключи, которые держит ваш ssh-agent (всё, что выводит ssh-add -L), и только если агент пуст, берёт самый новый ~/.ssh/id*.pub. Поэтому -i стоит писать каждый раз.
  • Фильтрует. Пробует войти с каждым ключом, только по ключу, и отбрасывает те, что уже работают. С -i скрипт для этого шага требует, чтобы закрытый ключ лежал рядом с файлом .pub; -f отменяет и проверку, и это требование.
  • Устанавливает. Входит ещё раз — отсюда запрос пароля, — переходит в домашний каталог и выполняет umask 077 и mkdir -p .ssh, добавляет перевод строки, если его нет в конце последней строки authorized_keys, дописывает ключ и, если установлены утилиты SELinux, выполняет restorecon для обоих путей.

Из-за umask 077 созданный им каталог .ssh получает права 700, а новый authorized_keys — 600. Но каталог или файл, которые уже существуют с неправильными правами или владельцем, он не исправляет; это самая частая причина, по которой ключ установлен, но игнорируется (см. ниже).

Параметры ssh-copy-id

ПараметрЧто делаетПример
-i FILEУстановить только ключи из FILE; .pub дописывается, если его нетssh-copy-id -i ~/.ssh/id_ed25519.pub USER@SERVER_IP
-p PORTПорт SSH, строчная буква, как в ssh (у scp — -P)ssh-copy-id -p 2222 -i ~/.ssh/id_ed25519.pub USER@SERVER_IP
-o OPTIONЛюбой параметр ssh -o, передаётся как естьssh-copy-id -i ~/.ssh/id_ed25519.pub -o PubkeyAuthentication=no USER@SERVER_IP
-F FILEИспользовать другой файл конфигурации sshssh-copy-id -F ./ssh_config myvps
-nПробный прогон: выводит ключи, которые добавил бы. Для проверки всё равно входит на серверssh-copy-id -n -i ~/.ssh/id_ed25519.pub USER@SERVER_IP
-fПринудительно: без проверки и без закрытого ключа; возможны дубликатыssh-copy-id -f -i ./colleague.pub USER@SERVER_IP
-sРежим SFTP для учётных записей, которым разрешён только SFTPssh-copy-id -s -i ~/.ssh/id_ed25519.pub USER@SERVER_IP
-t FILEПисать в FILE вместо .ssh/authorized_keys; только OpenSSH 9.4+ (Ubuntu 24.04, Debian 13)ssh-copy-id -t .ssh/authorized_keys2 -i ~/.ssh/id_ed25519.pub USER@SERVER_IP
-xТрассировка команд скрипта; только OpenSSH 9.4+ssh-copy-id -x -i ~/.ssh/id_ed25519.pub USER@SERVER_IP

-f нужен и для того, чтобы установить чужой открытый ключ: у вас есть файл .pub коллеги, но не его закрытый ключ, так что шаг фильтрации выполнить нельзя. Ставьте -f перед -i. Скрипт ищет парный закрытый ключ в тот момент, когда читает -i, поэтому ssh-copy-id -i ./colleague.pub -f остановится с ошибкой ERROR: failed to open ID file './colleague'.

ssh-copy-id с нестандартным портом

ssh-copy-id передаёт -p прямо в ssh, поэтому буква строчная: ssh-copy-id -p 2222 -i ~/.ssh/id_ed25519.pub USER@SERVER_IP. Работает и псевдоним хоста из ~/.ssh/config, вместе с портом и пользователем: ssh-copy-id -i ~/.ssh/id_ed25519.pub myvps. Если не уверены, какой порт у сервера, в статье SSH-порт 22 показано, как проверить это с обеих сторон. Как перенести SSH на другой порт и не потерять доступ, описано в статье как безопасно сменить порт SSH (англ.).

ssh-copy-id в Windows

Клиент OpenSSH, встроенный в Windows (англ.), включает ssh, scp, sftp, ssh-keygen, ssh-agent, ssh-add и ssh-keyscan, но не ssh-copy-id: это shell-скрипт. Для Linux-сервера ту же работу сделает такая строка PowerShell:

PowerShell (Windows PowerShell 5.1 или PowerShell 7)
Get-Content "$env:USERPROFILE\.ssh\id_ed25519.pub" | ssh USER@SERVER_IP "umask 077; mkdir -p .ssh && { tail -c1 .ssh/authorized_keys 2>/dev/null | grep -q . && echo; tr -d '\r'; } >> .ssh/authorized_keys"

Введите пароль сервера, когда его спросят. Часть в двойных кавычках выполняется на сервере и повторяет то, что делает ssh-copy-id: umask 077, чтобы новые файлы получили 700 и 600, и перевод строки перед ключом, если в последней строке файла его нет. tr -d '\r' убирает возврат каретки, который Windows может добавить в конец переданной строки. В строке нет ни $, ни вложенных двойных кавычек, поэтому Windows PowerShell 5.1 и PowerShell 7 передают её в ssh без изменений. Мы прогнали серверную часть в bash и dash на отсутствующем каталоге .ssh, на файле с завершающим переводом строки и на файле без него; каждый раз получался чистый файл с правильными правами.

Если ключ называется иначе, поменяйте путь в Get-Content. Ключи, созданные ssh-keygen в Windows, лежат в $env:USERPROFILE\.ssh; ключ из PuTTYgen должен быть в формате OpenSSH — это текст из поля «Public key for pasting into OpenSSH authorized_keys file».

Скопировать ключ вручную

Если передать ключ через конвейер не получается, например на компьютере с жёсткими ограничениями, выведите открытый ключ (cat ~/.ssh/id_ed25519.pub или Get-Content в Windows), скопируйте строку и выполните на сервере, войдя под тем пользователем, для которого ключ:

на сервере · Debian · Ubuntu
mkdir -p ~/.ssh && chmod 700 ~/.ssh
touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys
[ -z "$(tail -c1 ~/.ssh/authorized_keys)" ] || echo >> ~/.ssh/authorized_keys
echo 'PUBLIC_KEY_LINE' >> ~/.ssh/authorized_keys

Замените PUBLIC_KEY_LINE всей строкой из файла .pub, начиная с ssh-ed25519. Одинарные кавычки оставьте. Третья строка — та же проверка, что делает ssh-copy-id: если в последней строке файла нет перевода строки, она его добавляет, чтобы новый ключ не приклеился к концу старого и не сломал оба. Для проверки выполните ssh-keygen -l -f ~/.ssh/authorized_keys на сервере и ssh-keygen -l -f ~/.ssh/id_ed25519.pub на своём компьютере: отпечатки должны совпасть. Строка, которая сломалась при вставке, молча пропускается — её просто не будет в списке.

На Ubuntu VPS или Debian VPS от VMHeaven всё это можно пропустить: вставьте открытый ключ при заказе, и он будет установлен при создании сервера, а вход по паролю останется запасным вариантом.

Шаг 3: проверьте ключ, прежде чем отключать пароли

Войдите только по ключу, чтобы вас не обманул тихий откат на пароль:

Linux · macOS · Windows PowerShell
ssh -o PreferredAuthentications=publickey -i ~/.ssh/id_ed25519 USER@SERVER_IP

Если вы попали в shell и пароль учётной записи не спрашивался (парольная фраза самого ключа не в счёт), ключ работает. С -v в выводе будет строка Authenticated to SERVER_IP ([SERVER_IP]:22) using "publickey". Если вместо этого Permission denied (publickey), сначала разберитесь с этим.

ssh-copy-id: Permission denied и другие ошибки

Permission denied (publickey) при запуске ssh-copy-id

Пример вывода
/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
alice@203.0.113.10: Permission denied (publickey).

Запроса пароля не было, значит, сервер не принимает пароли для этой учётной записи. Возможно, вход по паролю уже выключен (на сервере действующее значение, с учётом файлов в /etc/ssh/sshd_config.d/, покажет sudo sshd -T | grep -i passwordauthentication), или у учётной записи вообще нет пароля. ssh-copy-id нужен хотя бы один работающий способ входа. Либо запустите его с компьютера, чей ключ сервер уже принимает, либо добавьте ключ вручную из консоли сервера. В личном кабинете VMHeaven у VNC-консоли есть поле, которое отправляет вставленный текст, так что длинную строку ключа набирать руками не придётся.

Если запрос пароля появляется, но заведомо верный пароль не подходит, посмотрите на пользователя. Для root в sshd по умолчанию действует PermitRootLogin prohibit-password, то есть вход только по ключу, и Debian или Ubuntu, установленные самостоятельно, это значение сохраняют. Скопируйте ключ обычному пользователю с правами sudo или добавьте его в /root/.ssh/authorized_keys из консоли.

Ключ установлен, а ssh всё равно спрашивает пароль

sshd игнорирует authorized_keys, если сам файл, каталог .ssh или домашний каталог доступны на запись кому-то, кроме владельца. В логе об этом сказано прямо:

на сервере · Debian · Ubuntu
sudo journalctl -u ssh --since "10 minutes ago" | grep -i -E 'refused|bad ownership'
Пример вывода
Authentication refused: bad ownership or modes for directory /home/alice

Исправьте права, войдя под тем пользователем, для которого ключ:

на сервере · Debian · Ubuntu
chmod go-w ~
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

Если ls -la ~/.ssh показывает, что файлы принадлежат root (обычно потому, что их создали через sudo), пользователь сам их поменять не сможет. Передайте их ему из-под root, подставив имя пользователя вместо USERNAME:

на сервере · Debian · Ubuntu
sudo chown -R USERNAME: /home/USERNAME/.ssh

В Rocky Linux и AlmaLinux юнит называется sshd, а не ssh. Если права в порядке, а вход всё равно не работает, проверьте другие частые причины:

  • Не тот пользователь. Ключ в /root/.ssh/authorized_keys ничего не даёт для ssh deploy@SERVER_IP. Запускайте ssh-copy-id с тем пользователем, под которым входите.
  • Ключи читаются из другого места. sudo sshd -T | grep -i authorizedkeysfile покажет, где их ищет sshd. По умолчанию это .ssh/authorized_keys .ssh/authorized_keys2; ssh-copy-id всегда пишет в первый, если не указать -t (OpenSSH 9.4 и новее).
  • Вход под root ограничен. PermitRootLogin no не пускает root даже с правильным ключом.

Если числа 700 и 600 вам ни о чём не говорят, наш Chmod calculator (англ.) переведёт их в биты чтения, записи и выполнения для владельца, группы и остальных.

Полный список проверок, включая разбор вывода ssh -v на стороне клиента, — в статье Permission denied (publickey).

WARNING: All keys were skipped because they already exist

На шаге фильтрации вход с ключом удался, и ssh-copy-id считает, что ключ уже установлен. Обычно так и есть. Но так бывает и тогда, когда во время проверки был предложен другой, уже работающий ключ — например, заданный через IdentityFile для этого хоста в ~/.ssh/config. Добавьте -f, чтобы установить ключ без проверки.

ERROR: No identities found

В агенте нет ключей, и файла ~/.ssh/id*.pub тоже нет. Создайте ключ, как в шаге 1, или укажите нужный файл через -i.

Too many authentication failures

В вашем ssh-agent столько ключей, что сервер сдаётся раньше, чем дело дойдёт до пароля. Добавьте -o PubkeyAuthentication=no, чтобы вход для установки сразу шёл на пароль; почему так происходит, объяснено в статье Too many authentication failures (англ.).

Частые вопросы

Как скопировать SSH-ключ на сервер из Windows, если там нет ssh-copy-id?

Встроенный в Windows клиент OpenSSH умеет ssh, scp и ssh-keygen, но ssh-copy-id в нём нет. В PowerShell передайте открытый ключ через ssh и допишите его в ~/.ssh/authorized_keys на сервере с umask 077 (готовая строка есть в статье) или вставьте ключ в этот файл вручную из консоли сервера.

Где лежит SSH-ключ и какой из двух файлов отправлять на сервер?

ssh-keygen по умолчанию кладёт пару в ~/.ssh, в Windows это C:\Users\имя\.ssh. id_ed25519 — закрытый ключ, он никогда не покидает ваш компьютер. На сервер отправляется только id_ed25519.pub: одна строка, которая начинается с ssh-ed25519. Посмотреть её можно командой cat ~/.ssh/id_ed25519.pub.

Как указать в ssh-copy-id другой порт SSH?

Строчным -p, как в ssh: ssh-copy-id -p 2222 -i ~/.ssh/id_ed25519.pub user@host. Заглавный -P нужен только scp. Можно и через псевдоним из ~/.ssh/config, где уже прописаны порт и пользователь: ssh-copy-id -i ~/.ssh/id_ed25519.pub myvps.

Читайте также

Все статьи раздела