В интернет смотрят тысячи ботов. Они не «выбрали вас». Они перебирают 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 --upgradabledf -hиdf -isudo journalctl -p err -u ssh --since todaysudo fail2ban-client status sshd- список слушающих портов:
ss -tulpn
Лишний python -c в crontab www-data, которого вы не ставили — инцидент.
Если кажется, что уже взломали
Признаки: неизвестные пользователи в /etc/passwd, authorized_keys с чужим ключом, CPU 100% на процессе kdevtmpfsi/xmrig, исходящий спам, сайт рисует чужую виагру.
Не «лечите антивирусом Linux». Считайте машину грязной.
- Сделайте снимок того, что ещё можно: логи, список процессов, crontab,
authorized_keys— на другой компьютер. - Смените пароли касс, DNS-регистратора, админок, токенов API — не на этой же машине, с безопасного ПК.
- Поднимите чистый VPS, перенесите код из git и данные из известного чистого бэкапа, не «скопируем /var/www как есть вместе с shell».
- Старый сервер выключите. Не оставляйте «пока разберёмся» в сети.
Tenku переустановит VPS по тарифу, но секреты, которые утекли, сами не отзовутся. Отзыв ключей — ваша работа.
Чего не делать ради «безопасности»
- Не ставить десяток сканеров, которые сами дырявые.
- Не закрывать ICMP «от пинга» — вы усложните себе диагностику сети, атакующим нет.
- Не отключать IPv6 криво: лучше корректный AAAA или его отсутствие, чем half-open.
- Не верить, что «скрытая панель на порту 8090» невидима. Она в
ssи в сканере.
Дисциплина скучная: ключ, файрвол, обновления, закрытая база, неисполняемые uploads. На этом фоне нормальный бэкап важнее ещё одного «модуля защиты». Когда контур стоит — занимайтесь сайтом. Если после укрепления всё тормозит, это уже не fail2ban, а ресурсы и запросы.