Журнал Tenku

Безопасность VPS: минимум, без которого сервер нельзя считать своим

В интернет смотрят тысячи ботов. Они не «выбрали вас». Они перебирают 22 порт у всех IP подряд. Пароль Root123 на свежем VPS живёт часы, иногда минуты. Это не повод для паранойи и не повод ставить десять панелей «антихак». Это повод закрыть очевидное в первый день и не открывать базу в мир.

Базовый контур входа — в первом SSH. Здесь — зачем каждая мера, что ещё сделать перед продом, и как понять, что уже поздно и нужно переустанавливать, а не «чистить антивирусом».

Модель угроз, которая вам реально нужна

Вам почти наверняка не нужен сценарий «иностранная разведка». Вам нужны:

  • словари по SSH и панелям;
  • дырявые плагины WordPress;
  • залитый webshell в uploads;
  • случайно открытый Redis/MySQL/Mongo;
  • утечка .env из веб-корня;
  • майнер после одной уязвимости PHP.

Закрытие этого списка даёт 90% результата. Остальное — обновления CMS и мозг при установке плагинов.

Сеть: закрыто всё, что не служит клиенту

UFW:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status numbered

Если сайта нет — 80/443 не открывайте «на будущее». Каждый открытый порт — сканер в логе.

Никогда в incoming:

  • 3306 MySQL
  • 5432 Postgres
  • 6379 Redis
  • 27017 Mongo
  • 9200 Elasticsearch
  • 2375 Docker без TLS (и вообще Docker socket в сеть)

Админские GUI на 8069/8080/9090 — только после базовой авторизации и лучше вообще через SSH-туннель:

ssh -L 3306:127.0.0.1:3306 deploy@IP

С ноутбука база на 127.0.0.1:3306. Для интернета её не существует.

Проверка с LTE: nc -vz IP 3306 должен не открываться. С localhost на сервере — должен.

SSH: пароль — временный, ключ — постоянный

Пока есть PasswordAuthentication yes, вас будут долбить. Ключ Ed25519, отдельный пользователь, PermitRootLogin prohibit-password или no. Подробные команды — в гайде первого входа, не дублируем ради объёма: сделайте его до продакшена.

Полезно дополнительно:

  • AllowUsers deploy в sshd_config, если root по SSH больше не нужен.
  • Fail2ban на sshd.
  • Не хранить ключ прод-сервера на общем ноутбуке без фразы и без диска BitLocker/FileVault.

Смена порта 22 → 2222 снижает шум, не целевую атаку. Если меняете — сначала UFW allow 2222, потом sshd, потом проверка, потом deny 22. Иначе вырежете себя. В тикете Tenku укажите новый порт, если просите зайти с консоли.

Обновления — это безопасность, не «оптимизация»

sudo apt update && sudo apt -y full-upgrade
sudo systemctl enable unattended-upgrades

Ядро иногда требует reboot. Кабинет Tenku переживёт. Сайт с persistent redis и php-fpm — тоже, если вы не держите сессии только в памяти без sticky и без внешнего стора.

Не отключайте обновления «чтобы ничего не сломалось». Сломается иначе: известный CVE в php-fpm, который уже в сканерах.

CMS и плагины обновляйте отдельно и сознательно. unattended-upgrades не патчит WordPress.

PHP и веб-корень

Документ-рут Laravel — public/. Документ-рут не должен включать .git, .env, vendor как статику. Nginx не отдаёт скрытые файлы (location ~ /\.).

Загрузки пользователей не должны исполняться как PHP:

location /wp-content/uploads/ {
    location ~ \.php$ { deny all; }
}

Это закрывает классический webshell «фото.jpg.php». Права 644, владелец www-data. 777 на uploads — приглашение.

display_errors в проде Off. Ошибки — в лог, не на экран клиенту с путями.

Секреты

Пароли БД, ключи касс, SMTP — в .env вне веб-корня или в wp-config вне git. Репозиторий без секретов. Скриншот .env в тикет поддержки стороннего подрядчика — смена всех ключей, не «ну он свой».

После увольнения человека уберите его строку из authorized_keys в тот же день. Не через месяц.

Fail2ban и лимиты входа в CMS

SSH fail2ban не защищает /wp-login.php. Нужен либо плагин лимита, либо jail по access-логу Nginx на POST /wp-login.php. Без фанатизма: не забаньте себя с динамического IP офиса на сутки. Белый список своего постоянного IP — нормально.

Капча на логин — для публичных WP. Для закрытой админки на отдельном домене ещё лучше, но это уже архитектура.

Что смотреть раз в неделю, не раз в год

  • sudo unattended-upgrades --dry-run или просто факт, что пакеты не 200 дней давности: apt list --upgradable
  • df -h и df -i
  • sudo journalctl -p err -u ssh --since today
  • sudo fail2ban-client status sshd
  • список слушающих портов: ss -tulpn

Лишний python -c в crontab www-data, которого вы не ставили — инцидент.

Если кажется, что уже взломали

Признаки: неизвестные пользователи в /etc/passwd, authorized_keys с чужим ключом, CPU 100% на процессе kdevtmpfsi/xmrig, исходящий спам, сайт рисует чужую виагру.

Не «лечите антивирусом Linux». Считайте машину грязной.

  1. Сделайте снимок того, что ещё можно: логи, список процессов, crontab, authorized_keys — на другой компьютер.
  2. Смените пароли касс, DNS-регистратора, админок, токенов API — не на этой же машине, с безопасного ПК.
  3. Поднимите чистый VPS, перенесите код из git и данные из известного чистого бэкапа, не «скопируем /var/www как есть вместе с shell».
  4. Старый сервер выключите. Не оставляйте «пока разберёмся» в сети.

Tenku переустановит VPS по тарифу, но секреты, которые утекли, сами не отзовутся. Отзыв ключей — ваша работа.

Чего не делать ради «безопасности»

  • Не ставить десяток сканеров, которые сами дырявые.
  • Не закрывать ICMP «от пинга» — вы усложните себе диагностику сети, атакующим нет.
  • Не отключать IPv6 криво: лучше корректный AAAA или его отсутствие, чем half-open.
  • Не верить, что «скрытая панель на порту 8090» невидима. Она в ss и в сканере.

Дисциплина скучная: ключ, файрвол, обновления, закрытая база, неисполняемые uploads. На этом фоне нормальный бэкап важнее ещё одного «модуля защиты». Когда контур стоит — занимайтесь сайтом. Если после укрепления всё тормозит, это уже не fail2ban, а ресурсы и запросы.

Нужен сервер под задачу?

Выберите тариф и локацию — VPS появится в кабинете.

Смотреть тарифы