Git и репозитории. Часть 1 — «SSH и GPG» 🔐¶
Когда начинаешь нормально работать с репозиториями, довольно быстро упираешься в две вещи: SSH и GPG. Первая нужна, чтобы удобно и безопасно ходить в удалённые репозитории без вечного ввода логина и пароля. Вторая — чтобы подписывать коммиты и теги, подтверждая: да, это действительно вы, а не какой‑то рандомный Вася с соседнего подвала.
В этой статье спокойно и без лишнего пафоса настроим оба механизма: создадим SSH‑ключ для доступа к GitHub / Gitea / серверам, затем сделаем GPG‑ключ для подписи коммитов. Заодно разберёмся, что это вообще такое, как это использовать и почему приватные ключи нужно беречь как зеницу ока.
Поехали 😎
🔑 Что такое SSH и зачем он нужен¶
SSH (Secure Shell) — это защищённый протокол для удалённого подключения и аутентификации. Если по‑простому: он позволяет доказать удалённой стороне, что вы — это вы, без передачи пароля по сети каждый раз.
В контексте Git это особенно удобно. Вместо того чтобы вводить логин, пароль, токены и прочую тоску при каждом git clone, git pull или git push, вы один раз создаёте пару ключей:
- приватный ключ — хранится только у вас;
- публичный ключ — отдаётся на GitHub, Gitea, сервер или куда нужно.
Дальше сервер смотрит: «ага, публичный ключ знакомый» — и пускает. Красота.
Важно: приватный ключ никому не отдаём. Вообще. Никогда. Если публичный ключ можно показывать и копировать на сервер, то приватный — это ваш цифровой пропуск.
⚙️ Почему именно ed25519¶
Для SSH‑ключей сегодня нормальный дефолт — это ed25519.
Что это вообще такое? Это современный алгоритм на основе эллиптических кривых EdDSA over Curve25519. Звучит как заклинание из тёмного подвала криптографов, но нам важна практика: ed25519 даёт хороший уровень безопасности, работает быстро, использует компактные ключи и поддерживается всеми нормальными современными системами.
Почему он хорош:
- компактный;
- быстрый;
- безопасный;
- поддерживается почти везде.
Если у вас нет какой‑то древней инфраструктуры из музея, где всё держится на скотче и rsa, то ed25519 — лучший выбор.
🛠️ Создаём SSH‑ключ¶
Сгенерируем один обычный ключ для локальной системы:
ssh-keygen -t ed25519
Дальше система спросит:
- Куда сохранить ключ. Можно оставить путь по умолчанию.
- Парольную фразу на ключ. Я очень рекомендую её ставить.
Если вы оставите путь по умолчанию, получите два файла:
~/.ssh/id_ed25519— приватный ключ;~/.ssh/id_ed25519.pub— публичный ключ.
🧠 Добавляем SSH‑ключ в агент¶
Чтобы не вводить парольную фразу каждый раз, ключ можно загрузить в ssh-agent:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
Да, команду с eval удобнее выполнять в bash или совместимом шелле. Но вообще это спокойно адаптируется и под другие оболочки.
У меня логика обычно такая: после первого использования ключ попадает в агент и живёт там до перезапуска сессии терминала. Это удобно и без перегибов.
Если используете fish, имеет смысл добавить в ~/.config/fish/config.fish вот это:
# Start ssh-agent if no agent socket is available.
if not set -q SSH_AUTH_SOCK
eval (ssh-agent -c) > /dev/null
end
Тогда агент будет подниматься автоматически, если для текущей сессии ещё нет доступного сокета. Мелочь, а жить становится приятнее.
📄 Как получить публичный SSH‑ключ¶
Публичную часть ключа можно просто вывести в терминал:
cat ~/.ssh/id_ed25519.pub
Именно этот текст вы копируете:
- в GitHub →
Settings→SSH and GPG keys; - в Gitea → настройки SSH‑ключей;
- на удалённые сервера в
~/.ssh/authorized_keys.
Ещё раз: файл с
.pub— это публичный ключ, его и используем для прокидывания наружу.
🧩 Настраиваем SSH‑конфиг¶
Чтобы не писать каждый раз кучу параметров руками, правим ~/.ssh/config.
Пример:
Host *
ServerAliveInterval 30
ServerAliveCountMax 3
TCPKeepAlive yes
AddKeysToAgent yes
IdentitiesOnly yes
HashKnownHosts yes
StrictHostKeyChecking ask
IdentityAgent $SSH_AUTH_SOCK
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519
Host myvps
HostName your.server.domain_or_ip
User your_user
Port 22
IdentityFile ~/.ssh/id_ed25519
Что здесь полезно:
- AddKeysToAgent yes — ключ можно автоматически добавлять в агент;
- IdentitiesOnly yes — SSH не будет перебирать весь зоопарк ключей подряд;
- HashKnownHosts yes — список известных хостов будет храниться в зашифрованном виде;
- StrictHostKeyChecking ask — SSH спросит подтверждение при первом подключении.
После правки не забудьте защитить права:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/config
✅ Проверяем SSH на GitHub¶
Теперь можно проверить подключение:
ssh -T git@github.com
Если всё в порядке, GitHub ответит приветствием и сообщит, что аутентификация успешна. Шелл при этом он вам не даст — и это нормально.
🖥️ SSH для своего сервера¶
С GitHub всё довольно цивилизованно: вставили публичный ключ в настройки — и поехали. Со своим сервером всё чуть более руками, но логика та же.
1. Первый вход — по паролю¶
Чтобы впервые зайти на сервер, доступ по паролю должен быть включён. Обычно это настраивается в sshd_config примерно так:
PasswordAuthentication yes
KbdInteractiveAuthentication yes
UsePAM yes
PermitRootLogin no
Что здесь означает каждая строка:
- PasswordAuthentication yes — разрешает обычный вход по паролю;
- KbdInteractiveAuthentication yes — включает keyboard-interactive аутентификацию; на некоторых системах она используется вместе с обычным входом по паролю;
- UsePAM yes — разрешает PAM участвовать в аутентификации; во многих дистрибутивах это часть нормальной работы парольного входа;
- PermitRootLogin no — запрещает прямой вход под
rootпо SSH. И это правильно. Лезть снаружи сразу подroot— плохая привычка и обычно вообще не нужно.
Но тут есть важный нюанс: в системе могут быть дополнительные файлы конфигурации SSH, которые переопределят эти правила. Например, что‑то в духе sshd_config.d/*.conf. То есть вы вроде бы всё честно прописали, а сервер всё равно упрямо делает вид, что ничего не видел. Проверяйте не только основной конфиг, но и каталог с дополнительными включаемыми файлами.
2. Прокидываем ключ на сервер¶
После первого входа по паролю копируем публичный ключ на сервер:
ssh-copy-id your_user@your.server.domain_or_ip
Если у вас нестандартный порт, указывайте его явно:
ssh-copy-id -p 2222 your_user@your.server.domain_or_ip
Эта команда добавит ваш публичный ключ в ~/.ssh/authorized_keys на сервере.
3. Теперь вход по ключу доступен¶
После этого можно пробовать обычный вход:
ssh your_user@your.server.domain_or_ip
Если всё настроено правильно, сервер пустит вас уже по ключу. Пароль больше не нужен — и это именно то, чего мы добивались.
4. Отключаем вход по паролю¶
И вот это обязательно: после того как убедились, что вход по ключу работает, отключайте вход по паролю.
В конфиге сервера должно остаться примерно так:
PasswordAuthentication no
KbdInteractiveAuthentication no
UsePAM yes
PermitRootLogin no
После этого перезапускаете sshd и живёте спокойнее.
Да, это означает, что при подключении с нового устройства вы уже не сможете просто вбить пароль и зайти, как в старые добрые времена. Придётся:
- либо зайти со старого доверенного устройства;
- либо использовать веб‑консоль / VNC / панель хостера;
- временно снова включить вход по паролю;
- добавить новый ключ;
- и снова выключить парольный доступ.
Да, это чуть менее удобно. Но это безопасность. Сервер, на который можно войти по паролю снаружи, — это всегда дополнительная поверхность атаки. Лучше один раз сделать нормально, чем потом удивляться, откуда на VPS внезапно майнер и китайский цирк.
🔏 Что такое GPG и зачем он нужен¶
Теперь к GPG.
GPG (GNU Privacy Guard) — это инструмент для криптографии: шифрования, проверки подписи и работы с ключами. В контексте Git нас интересует не шифрование, а именно цифровая подпись.
Зачем нужна подпись коммитов:
- GitHub / Gitea могут показать, что коммит подписан и верифицирован;
- становится проще доказать, что коммит действительно сделан вами;
- это просто хороший тон, если вы ведёте публичные репозитории или серьёзные проекты.
Если SSH говорит: «я могу войти на сервер», то GPG говорит: «этот коммит подписал именно я».
🛠️ Создаём GPG‑ключ¶
Сгенерируем ключ в интерактивном режиме:
gpg --full-generate-key
Рекомендованные ответы:
- Тип ключа —
ECC (sign only)/ «только для подписи»; - Кривая —
Curve 25519; - Срок действия — любой на ваш вкус. Я обычно ставлю 1 год;
- дальше вводите имя, почту и парольную фразу.
Почему срок действия на год — нормальная идея:
- ключи полезно периодически ротировать;
- если ключ утёк или потерял актуальность, не придётся жить с ним вечно;
- при этом год — срок комфортный и не раздражает.
🔍 Смотрим созданный GPG‑ключ¶
После генерации посмотрим список секретных ключей:
gpg --list-secret-keys --keyid-format=long
Вывод будет примерно такой:
sec ed25519/AAAAAAAAAAAAAAAA 2026-03-09 [SC] [expires: 2027-03-09]
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
uid [ultimate] Your Name <your_email@example.com>
Здесь нас интересует ID ключа — в примере это AAAAAAAAAAAAAAAA.
Теперь экспортируем публичную часть:
gpg --armor --export AAAAAAAAAAAAAAAA
Её и нужно вставить:
- в GitHub →
Settings→SSH and GPG keys→New GPG key; - либо в аналогичный раздел Gitea, если он у вас поддерживает верификацию подписей.
🧷 Настраиваем gpg-agent¶
Чтобы ввод пароля был удобным, нужно настроить gpg-agent. Правим файл ~/.gnupg/gpg-agent.conf:
pinentry-program /usr/bin/pinentry-curses
default-cache-ttl 2147483647
max-cache-ttl 2147483647
Что это значит:
- pinentry-program — какая программа будет спрашивать пароль;
- default-cache-ttl и max-cache-ttl — как долго агент будет держать пароль в памяти.
Да, значения выглядят так, будто мы решили сломать математику. На практике это даёт очень долгий кэш. В реальности поведение часто сводится к тому, что пароль живёт до перезапуска терминальной сессии или агента.
Если вы работаете в терминале, pinentry-curses — хороший вариант. Если предпочитаете графику, можно использовать pinentry-gtk или pinentry-qt.
Если используете fish, добавьте в ~/.config/fish/config.fish ещё и это:
# Ensure GPG pinentry can access the correct TTY.
set -gx GPG_TTY (tty)
Без этой строки pinentry иногда начинает жить своей жизнью и делать вид, что терминал ему не указ. А нам такое счастье не нужно.
После изменения конфига перезапускаем агент:
gpgconf --kill gpg-agent
gpgconf --launch gpg-agent
И не забываем про права на директорию:
chmod 700 ~/.gnupg
⚙️ Привязываем GPG к Git¶
Теперь говорим Git, какой ключ использовать для подписи:
git config --global user.name "Ваше Имя"
git config --global user.email "your_email@example.com"
git config --global user.signingkey AAAAAAAAAAAAAAAA
git config --global commit.gpgsign true
git config --global tag.gpgsign true
git config --global gpg.program gpg
Что здесь происходит:
user.nameиuser.email— авторство коммитов;user.signingkey— какой именно GPG‑ключ использовать;commit.gpgsign true— подписывать все коммиты по умолчанию;tag.gpgsign true— подписывать теги;gpg.program gpg— какой бинарник использовать.
После этого Git начнёт подписывать коммиты автоматически.
✅ Проверяем подпись коммитов¶
Проще всего — создать тестовый коммит:
mkdir test-gpg && cd test-gpg
git init
echo "test" > README.md
git add README.md
git commit -m "test: проверка GPG подписи"
Если всё настроено правильно, Git попросит парольную фразу через pinentry, создаст коммит, а платформа покажет, что он подписан.
Посмотреть подпись локально можно так:
git log --show-signature -1
🧠 Как лучше хранить ключи¶
Здесь логика простая.
Для локальной системы вы создаёте один SSH‑ключ и один GPG‑ключ. Этого обычно достаточно. SSH‑ключ используете для GitHub, Gitea и при желании для своих серверов. GPG‑ключ — для подписи коммитов и тегов.
Главные правила:
- приватные ключи не копируем куда попало;
- не отправляем их в мессенджеры, облака и «временные заметки»;
- по возможности ставим парольную фразу;
- публичные ключи можно добавлять на разные серверы и в разные сервисы.
Если устройство потеряли или есть подозрение, что ключ утёк, всё просто:
- удаляем публичный ключ с GitHub / Gitea / серверов;
- создаём новую пару;
- обновляем привязки.
Без паники, но и без режима «да ладно, и так сойдёт».
🏁 Что в итоге получилось¶
Мы настроили два важных механизма:
- SSH — для безопасного доступа к GitHub / Gitea / серверам;
- GPG — для подписи коммитов и тегов.
Теперь у вас есть нормальная база для работы с репозиториями: без лишнего ввода паролей, с аккуратной аутентификацией и с верифицируемыми коммитами. Уже не просто «что‑то там пушится», а более‑менее взрослая инфраструктура 🙂
А дальше главное — не сливать приватники куда попало и не устраивать цифровой колхоз там, где можно один раз сделать нормально 🖤