Коротко: ssh-copy-id -i ~/.ssh/id_ed25519.pub USER@SERVER_IP копирует ваш открытый SSH-ключ в ~/.ssh/authorized_keys на сервере, и дальше вы входите по ключу, а не по паролю. Для этого утилите нужно хотя бы раз войти на сервер, обычно по паролю; ключи, которые уже установлены, она пропускает. В Windows ssh-copy-id нет; строка PowerShell, которая делает то же самое, — ниже.
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 на своём компьютере — никогда не на сервере:
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@laptopid_ed25519 — закрытый ключ, он остаётся на вашем компьютере. id_ed25519.pub — одна строка, которая начинается с ssh-ed25519, и на серверы отправляется только этот файл. В Windows оба файла лежат в C:\Users\имя\.ssh. OpenSSH свои сообщения не переводит, поэтому вывод выше одинаков в любой локали.
Шаг 2: скопируйте ключ с помощью ssh-copy-id
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 | Использовать другой файл конфигурации ssh | ssh-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 для учётных записей, которым разрешён только SFTP | ssh-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:
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), скопируйте строку и выполните на сервере, войдя под тем пользователем, для которого ключ:
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: проверьте ключ, прежде чем отключать пароли
Войдите только по ключу, чтобы вас не обманул тихий откат на пароль:
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 или домашний каталог доступны на запись кому-то, кроме владельца. В логе об этом сказано прямо:
sudo journalctl -u ssh --since "10 minutes ago" | grep -i -E 'refused|bad ownership'Authentication refused: bad ownership or modes for directory /home/aliceИсправьте права, войдя под тем пользователем, для которого ключ:
chmod go-w ~
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keysЕсли ls -la ~/.ssh показывает, что файлы принадлежат root (обычно потому, что их создали через sudo), пользователь сам их поменять не сможет. Передайте их ему из-под root, подставив имя пользователя вместо USERNAME:
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.