Permission denied (publickey) при git push — как починить
Делаешь git push, а в ответ:
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.Сообщение конкретное: SSH-сервер не принял твой ключ. Не пароль, не сам репозиторий, не сетевую связность — именно публичный ключ. Дальше нужно понять, на каком из шагов цепочка ломается.
Алгоритм, по которому я разбираю
Шаг 1: видит ли SSH сервер вообще
Проверяю, доходит ли запрос до GitHub:
ssh -T git@github.comНа GitLab — git@gitlab.com, на Bitbucket — git@bitbucket.org.
Если ответ — что-то вроде «Hi username! You've successfully authenticated» — связь и ключ в порядке, проблема в другом (доступ к конкретному репозиторию). Если Permission denied — пошли разбираться с ключами.
Шаг 2: какой ключ ssh пытается использовать
ssh -vT git@github.com 2>&1 | grep -E 'Offering|identity|debug1: send'В выводе видишь, какие ключи клиент предлагает серверу. Если там нет твоего id_ed25519, или нужного ключа от рабочего аккаунта — проблема в конфигурации.
Шаг 3: загружен ли ключ в ssh-agent
ssh-add -lЕсли ответ The agent has no identities — добавляешь:
ssh-add ~/.ssh/id_ed25519Если файла нет, его нужно создать.
Создание ключа с нуля
ssh-keygen -t ed25519 -C "me@example.com"Жмёшь Enter на путь, придумываешь passphrase (можно пустую, но лучше поставить).
Копируешь публичный ключ:
cat ~/.ssh/id_ed25519.pubНа macOS — pbcopy < ~/.ssh/id_ed25519.pub, на Linux с xclip — xclip -sel clip < ~/.ssh/id_ed25519.pub.
Идёшь в настройки GitHub: Settings → SSH and GPG keys → New SSH key. Вставляешь содержимое .pub-файла. Никогда — не приватный ~/.ssh/id_ed25519!
Несколько аккаунтов: рабочий и личный
Самый частый сценарий, в котором всё ломается. У тебя личный ключ id_ed25519 и рабочий id_ed25519_work. Ты делаешь git push в рабочий репозиторий, а ssh по умолчанию предлагает личный, и сервер не пускает.
Решение — конфиг ~/.ssh/config:
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_work
IdentitiesOnly yesДальше для рабочего репозитория используешь хост github-work:
git remote set-url origin git@github-work:my-org/secret-app.gitSSH прочитает конфиг, поймёт, что для github-work нужен id_ed25519_work, и пушнёт от рабочего аккаунта.
Опция IdentitiesOnly yes важна. Без неё ssh всё равно перебирает все ключи из агента и может предложить личный первым, спалив тем самым твой коммит на рабочий аккаунт.
Шаг 4: права на файлы
SSH очень строгий по правам. Если на ~/.ssh или приватном ключе слишком открытые права, ssh откажется его использовать и не скажет внятно почему.
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/configЕсли ключ лежит в шаренной папке или вытащен из чужого архива — права обычно слетают. Лечится одной строкой выше.
Шаг 5: ключ типа RSA и SHA-1
GitHub в 2022-м перестал принимать RSA-ключи, подписанные только SHA-1. Если у тебя старый id_rsa, может прилетать как раз Permission denied (publickey).
Проверка типа:
ssh-keygen -lf ~/.ssh/id_rsa.pubЕсли RSA и сомневаешься в свежести — генерируй ed25519. Это короче, безопаснее и точно поддерживается.
Особый случай: использование HTTPS вместо SSH
Иногда проще не воевать с ключами, а ходить по HTTPS с личным токеном. Особенно на корпоративных машинах, где SSH-исходящие закрыты фаерволом.
git remote set-url origin https://github.com/user/repo.gitПри первом push потребует логин — указываешь имя пользователя и Personal Access Token вместо пароля. Можно положить в credential helper, чтобы каждый раз не спрашивал.
Я обычно использую gh auth login, чтобы не возиться с токенами руками — он сам ставит правильный credential helper.
Дебаг последней инстанции
GIT_SSH_COMMAND="ssh -vvv" git push 2>&1 | head -100Тройной -vvv заставит ssh подробно логировать всё: какие ключи он пробует, какие сервер отвечает, на каком этапе обрывается. По этому выводу всегда видно, в чём загвоздка — ключа нет в агенте, права не те, конфиг не подцепил, ключ просто не загружен в GitHub.
Чек-лист
ssh -T git@github.com— связь и identity сервера в порядке.ssh-add -l— ключ в агенте.- Публичный ключ загружен в настройки GitHub/GitLab/Bitbucket.
- Права на
~/.sshи приватный ключ —700/600. - Если несколько аккаунтов — конфиг с
IdentitiesOnly yes. - RSA на старом ключе — генерируй ed25519.
Permission denied (publickey) — это не загадка. Это конкретный мессадж: «я не понял, кто ты». Каждый из шагов выше отвечает на один вопрос — где именно ssh потерял твою личность. Расставляешь чек-марки по списку — и пуш проходит.