1. Какие угрозы реальны
После выдачи публичного IP ваш VPS попадает в поле зрения автоматических сканеров в течение нескольких минут. Посмотрите в /var/log/auth.log — на любом незащищённом сервере там тысячи попыток входа по SSH за сутки.
grep "Failed password" /var/log/auth.log | tail -20Злоумышленники перебирают логины (root, admin, ubuntu) и популярные пароли. Если VPS доступен по паролю — это вопрос времени.
Частые угрозы
- — Брутфорс SSH (подбор пароля)
- — Компрометация через слабый пароль root
- — Уязвимости в устаревших пакетах
- — Открытые лишние порты (БД, Redis без пароля)
Защита (этот гайд)
- — SSH-ключи вместо паролей
- — Отключение root-логина
- — UFW: разрешён только нужный трафик
- — Fail2Ban: бан после нескольких ошибок
2. Шаг 0: создать нового пользователя
Работать под root — плохая практика. Создайте обычного пользователя с правами sudo. После этого root-логин можно будет полностью отключить.
# Создать пользователя (замените "san" на своё имя)
adduser san
# Добавить в группу sudo
usermod -aG sudo san
# Проверить
groups sansu - san
sudo whoami
# Должно вывести: rootВсе дальнейшие команды можно выполнять от этого пользователя через sudo.
3. Шаг 1: SSH-ключи
SSH-ключи — основа безопасности. Вместо пароля используется криптографическая пара: приватный ключ хранится у вас, публичный — на сервере. Без приватного ключа войти невозможно, даже зная пароль.
Генерация ключа (на вашем компьютере)
Ed25519 — современный стандарт 2026 года: короче RSA и надёжнее.
ssh-keygen -t ed25519 -C "my-vps-key"
# Файлы появятся в ~/.ssh/
# ~/.ssh/id_ed25519 — приватный (никому не давать!)
# ~/.ssh/id_ed25519.pub — публичный (копируем на сервер)Passphrase — ставить или нет?
Рекомендуется. Даже если кто-то украдёт файл приватного ключа — без passphrase он бесполезен. На macOS/Windows ключи с passphrase запоминаются в системном keychain, и вводить её каждый раз не нужно.
Скопировать ключ на сервер
# Автоматически (если SSH работает по паролю)
ssh-copy-id -i ~/.ssh/id_ed25519.pub san@ВАШ_IP
# Вручную (если ssh-copy-id недоступен)
cat ~/.ssh/id_ed25519.pub | ssh san@ВАШ_IP "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keysПроверить вход по ключу
ssh -i ~/.ssh/id_ed25519 san@ВАШ_IP
# Если вошли без пароля — ключ работает
# Только после этого отключаем парольный входСовет: ~/.ssh/config
Добавьте на вашем компьютере в ~/.ssh/config: Host myvps, HostName ВАШ_IP, User san, IdentityFile ~/.ssh/id_ed25519. После этого подключаться можно просто командой ssh myvps.
4. Шаг 2: Hardening sshd_config
После того как вход по SSH-ключу работает, отключаем парольную аутентификацию и root-логин. Это закрывает большинство векторов атаки на SSH.
Редактируем конфиг
sudo nano /etc/ssh/sshd_configНайдите и измените (или добавьте в конец) следующие параметры:
# Отключить вход под root
PermitRootLogin no
# Отключить парольную аутентификацию (только ключи)
PasswordAuthentication no
# Включить аутентификацию по ключам (по умолчанию yes, проверить)
PubkeyAuthentication yes
# Ограничить число попыток входа
MaxAuthTries 3
# Сократить время ожидания логина (секунды)
LoginGraceTime 30
# Отключить X11 (графический проброс — не нужен на сервере)
X11Forwarding no
# Опционально: разрешить вход только конкретному пользователю
# AllowUsers san
# Опционально: сменить порт (например на 2222)
# Port 2222Если меняете порт SSH
Сначала откройте новый порт в UFW: sudo ufw allow 2222/tcp, затем перезапустите sshd, потом удалите правило для порта 22: sudo ufw delete allow 22/tcp. Иначе рискуете заблокировать себя.
Проверить и перезапустить
sudo sshd -tsudo systemctl restart ssh
# Проверить статус
sudo systemctl status sshПроверьте новое подключение!
Откройте новый терминал и убедитесь, что SSH-вход по ключу работает. Только после этого закрывайте текущую сессию. Если что-то пошло не так — в текущей сессии ещё можно исправить конфиг.
5. Шаг 3: UFW — файрвол
UFW (Uncomplicated Firewall) — удобная обёртка над iptables, встроенная в Ubuntu. По умолчанию закрывает все входящие соединения, кроме явно разрешённых. Это защищает от случайно открытых портов (Redis, PostgreSQL и другие сервисы часто слушают на всех интерфейсах).
Установка и базовая настройка
sudo apt install -y ufw# Разрешить SSH (критично — иначе потеряете доступ!)
sudo ufw allow 22/tcp
# Если вы сменили порт SSH на 2222:
# sudo ufw allow 2222/tcp
# Разрешить HTTP и HTTPS (если есть веб-сервер)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Включить файрвол
sudo ufw enable
# Введите "y" для подтвержденияПроверить статус
sudo ufw status verboseВывод должен показать: Status: active, Default: deny (incoming), allow (outgoing).
Полезные команды UFW
# Разрешить порт (например, для PostgreSQL — только с конкретного IP)
sudo ufw allow from 192.168.1.100 to any port 5432
# Запретить порт
sudo ufw deny 3306
# Удалить правило
sudo ufw delete allow 80/tcp
# Посмотреть правила с номерами (для удаления по номеру)
sudo ufw status numbered
# Перезагрузить правила
sudo ufw reload
# Отключить UFW (если что-то пошло не так)
sudo ufw disableПринцип минимальных прав
Открывайте только те порты, которые реально нужны. PostgreSQL, Redis, MongoDB не должны быть доступны с интернета — только с localhost или конкретного IP. Проверьте какие порты слушают: sudo ss -tlnp
6. Шаг 4: Fail2Ban
Fail2Ban анализирует лог-файлы и автоматически блокирует IP-адреса, с которых идут повторные неудачные попытки входа. После нескольких ошибок IP попадает в бан через iptables на заданное время.
Установка
sudo apt update
sudo apt install -y fail2ban
# Запустить и добавить в автозапуск
sudo systemctl enable --now fail2ban
# Проверить статус
sudo fail2ban-client statusНастройка через jail.local
Никогда не редактируйте jail.conf напрямую — он перезапишется при обновлении. Создайте jail.local:
sudo nano /etc/fail2ban/jail.local[DEFAULT]
# Бан на 1 час
bantime = 3600
# Считать попытки за последние 10 минут
findtime = 600
# Бан после 5 неудачных попыток
maxretry = 5
# Игнорировать локальные адреса и ваш IP (замените на свой!)
ignoreip = 127.0.0.1/8 ::1
[sshd]
enabled = true
port = ssh
# Если сменили порт SSH:
# port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600ignoreip — обязательно добавьте свой IP
Если у вас статический IP — добавьте его в ignoreip, чтобы случайно не забанить себя. Узнать свой IP: curl ifconfig.me
sudo systemctl restart fail2banМониторинг и управление
# Общий статус всех jail
sudo fail2ban-client status
# Статус SSH jail — видно число и список забаненных IP
sudo fail2ban-client status sshd
# Разбанить конкретный IP вручную
sudo fail2ban-client set sshd unbanip 1.2.3.4
# Смотреть лог в реальном времени
sudo tail -f /var/log/fail2ban.logЧерез несколько часов после включения запустите sudo fail2ban-client status sshd — увидите, как Fail2Ban уже заблокировал первых сканеров.
7. Шаг 5: Автоматические обновления
Большинство успешных взломов происходит через известные уязвимостис уже выпущенными патчами, которые просто не установили. Пакет unattended-upgrades автоматически устанавливает security-обновления в фоне — без перезагрузки (кроме обновлений ядра).
sudo apt install -y unattended-upgrades
# Настроить через диалог (выберите "Yes")
sudo dpkg-reconfigure -plow unattended-upgradescat /etc/apt/apt.conf.d/20auto-upgrades
# Должно быть:
# APT::Periodic::Update-Package-Lists "1";
# APT::Periodic::Unattended-Upgrade "1";По умолчанию обновляются только пакеты из -security репозитория — это безопасно. Полный apt upgrade лучше делать вручную раз в 1–2 недели.
8. Итоговая проверка
Пройдитесь по чеклисту — убедитесь, что всё настроено корректно:
SSH-ключ работает
ssh san@ВАШ_IP — вход без пароля
Root-логин отключён
ssh root@ВАШ_IP → Permission denied
Парольный вход закрыт
ssh -o PubkeyAuthentication=no san@ВАШ_IP → Permission denied
UFW активен
sudo ufw status → Status: active
Fail2Ban работает
sudo fail2ban-client status → sshd в списке
Автообновления включены
sudo systemctl is-active unattended-upgrades → active
# Статус SSH
sudo systemctl status ssh
# Активные правила UFW
sudo ufw status verbose
# Fail2Ban — сколько IP забанено
sudo fail2ban-client status sshd
# Открытые порты на сервере
sudo ss -tlnp
# Автообновления
sudo systemctl is-active unattended-upgradesИтого: что сделали