mysurik.ru

Безопасность домашнего сервера: личный опыт

У меня был момент прозрения. Сижу я ночью, проверяю почту — а там письмо от Hetzner. «Ваш сервер скомпрометирован». Я сначала подумал — да ну, бред. Зашёл по SSH, а там… майнер. Кто-то запустил Monero на моём VPS, и он жрал CPU на 100% уже сутки.

Я даже не заметил.

Вот тогда я сел и пересмотрел своё отношение к безопасности. Раньше думал: «домашний сервер, кому я нужен». Скажу сразу — это самое опасное заблуждение. Умные люди давно автоматизировали взлом, и твой сервер ищут не по имени, а по портам. Сканеры прочёсывают интернет 24/7. Если у тебя открыт SSH на стандартном порту — ты уже в зоне риска.

Первое, что я сделал — поменял порт SSH. 22-й порт атакуют постоянно. В логах fail2ban у меня были тысячи попыток входа в сутки. Просто перенёс на 2222 — и количество атак упало на 90%. Не панацея, но первый шаг очевидный.

Дальше — ключи вместо пароля. Парольная аутентификация — зло. Я сгенерировал ed25519-ключ, скопировал на сервер, и отключил `PasswordAuthentication no` в sshd_config. После этого даже если кто-то угадает пароль — не зайдёт. А ключ без файла-пароля (passphrase) не имеет смысла — я добавил и его.

Кстати про fail2ban. Это must have. Я настроил его не только для SSH, но и для nginx, и для WordPress (через лог wp-login). После того как поставил — количество брутфорс-атак в логах упало с тысяч до нуля. Ну, до бана этих тысяч. Конфиг простой:

[sshd]
enabled = true
port = 2222
maxretry = 3
bantime = 86400

Сутки бана. Три попытки. Жёстко, но работает.

Теперь про то, что я упустил в самом начале. Обновления. Долгое время у меня была схема «работает — не трогай». И это нормально, пока не выходит уязвимость в OpenSSL или в той же nginx. Теперь у меня стоит `unattended-upgrades` для критических патчей, и раз в неделю я захожу и вручную обновляю пакеты. Да, это скучно. Да, я тоже ленюсь. Но майнер на сервере — ещё более скучно.

Раз уж заговорили про веб — ставьте заглушку на неиспользуемые домены. Я на своём nginx настроил default server, который возвращает 444 (закрыть соединение без ответа) для всех запросов, которые не подходят ни под один server_name. Потому что сканеры тупо долбятся по IP, а ты даже не знаешь. А у тебя там может phpMyAdmin висеть с дефолтным паролем.

Да, кстати, удалите phpMyAdmin. Или хотя бы повесьте на него HTTP Basic Auth и ограничьте доступ по IP. Я свой удалил и пользуюсь командной строкой — удобнее, быстрее и без дыр.

Firewall. Я долго откладывал настройку, потому что «и так всё норм». Потом сел и настроил ufw. Разрешил только SSH, HTTP, HTTPS и WireGuard. И порт моего игрового сервера. Всё остальное — дроп. Раз — и список атак в fail2ban сократился ещё вдвое. Потому что если порт закрыт — в него даже не ломятся.

WireGuard — отдельная песня. Я сделал VPN-доступ к админским интерфейсам. Теперь phpMyAdmin (я его не удалил, а перенёс), Grafana, Portainer — всё доступно только через WireGuard. Снаружи эти порты даже не открыты. Хочешь зайти в админку — сначала подними VPN. Спокойно? Спокойно.

Ещё я перестал использовать root для повседневной работы. Создал отдельного пользователя `deploy`, дал ему sudo на конкретные команды. Root login через SSH вообще отключил в sshd_config — `PermitRootLogin no`. Если кто-то подберёт пароль от рута (а его нет, я его даже не знаю) — не зайдёт.

Логи. Я их не смотрел годами, пока не случился майнер. Теперь у меня всё стекается в Grafana через Loki — watching. Docker-логи, nginx, auth.log, syslog — всё в одной панели. Но хотя бы раз в неделю глазами пробегаться по `/var/log/auth.log` — святое. Там сразу видно, ломятся к тебе или нет.

И последнее — бекапы. Безопасность — это не только про взлом. Диск тоже может сдохнуть. Или ты сам что-то сломаешь обновлением. У меня бекапы на отдельный диск, ежедневно, с хранением за неделю. Восстановление проверял — работает.

Сейчас мой сервер стоит в интернете уже полгода. За это время было несколько попыток брутфорса (fail2ban отбил), один сканер нашёл старый тестовый поддомен (я его удалил), и ничего не сломалось. Я сплю спокойно не потому что думаю «кому я нужен», а потому что знаю — доступ к серверу есть только у меня, через ключ и VPN, а всё остальное закрыто.

Сделай хотя бы половину из этого — и будешь в порядке. Серьёзно, майнер на сервере — это не смешно.

Расскажу ещё то, чему научился уже после той ночи с майнером. В первой части я описал базу, но есть вещи, которые стоит знать, чтобы не наступать на те же грабли, что и я.

Про двухфакторку для SSH. Ключи — это хорошо, но если на твоём ноутбуке похитят приватный ключ — всё, вход открыт. Поэтому я добавил TOTP на SSH через libpam-google-authenticator. Теперь вход по ключу требует ещё и одноразовый код из приложения на телефоне. Это чуть замедляет подключение, зато даже украденный ключ бесполезен без кода. Один раз этот механизм меня реально спас: на работе дали ноутбук с историей, и я успел отозвать доступы до того, как ими кто-то воспользовался.

Про мониторинг подозрительной активности. Fail2ban банит, но он не расскажет, что происходит внутри, если взлом всё же случился. Поэтому я поставил несколько простых, но действенных вещей. Во-первых, алерт на вход в систему по SSH — если кто-то залогинился, мне приходит уведомление. Во-вторых, алерт на новые пользователи и новые crontab-записи — майнеры любят прописываться в cron. В-третьих, алерт на подозрительные процессы с высоким CPU. Именно такой алерт помог бы мне заметить майнер за часы, а не через сутки.

Про анализ логов. Не обязательно разворачивать Loki и Grafana сразу — можно начать с простого. Я написал скрипт, который раз в час проверяет auth.log на неудачные попытки и необычные входы, и шлёт результат в ntfy. Плюс grep по auth.log раз в неделю глазами. Со временем я понял, что вижу «нормальный» фон атак и сразу замечаю, когда что-то выбивается из обычной картины. Это как знать свои логи как свои пять пальцев.

Про изоляцию сервисов. Один из главных уроков майнера — не держать всё под одним пользователем. Сейчас каждый мой сервис живёт в своём контейнере или как минимум под своим пользователем с ограниченными правами. Если один сервис скомпрометируют — он не получит доступ к остальным. Раньше у меня всё крутилось под root, и это была пороховая бочка.

Про сетевые срезы. Я разделил сервер на логические зоны: публичные сервисы (сайт, почта), внутренние (Grafana, Portainer, базы) и совсем приватные (тестовые поддомены). Публичная зона — наружу, внутренние — только через VPN, приватные — вообще изолированы в своей сети Docker без выхода в интернет. Если что-то из приватной зоны попробует стучаться наружу — это сразу видно и это повод насторожиться.

Про то, что безопасность — это процесс, а не разовая настройка. После той ночи я понял главное: нельзя один раз настроить всё и забыть. Угрозы меняются, выходят новые уязвимости, появляются новые инструменты у атакующих. У меня заведён ежемесячный ритуал: обновить всё, пробежаться по логам, проверить открытые порты (ss -tulpn), посмотреть, нет ли новых пользователей и необычных процессов. Двадцать минут в месяц — и спокойствие.

Ещё про безопасность домашнего сервера есть специфика: ты не под защитой облачного провайдера, который следит за инфраструктурой. За всё отвечаешь ты. Поэтому я бы советовал начать с малого: смена порта SSH, ключи вместо паролей, fail2ban, ufw, обновления. Это уже отсекает 95% автоматизированных атак. Дальше — двухфакторка, изоляция сервисов, мониторинг. Не обязательно делать всё сразу — но сделать базовый минимум нужно обязательно.

И последнее, но важное: регулярно проверяй, что твоя защита реально работает. Попробуй сам зайти со стороны: открыт ли ненужный порт, отвечает ли nginx на запросы по IP, работает ли fail2ban на тестовой попытке входа. У меня один раз выяснилось, что фаервол не применился после перезагрузки — и я думал, что защищён, а по факту все порты были открыты. Проверяй — и будешь спать спокойно.

В итоге: безопасность — это не про паранойю, а про базовые привычки. Майнер на сервере — наглядный тому пример. Двадцать минут на базовую настройку и ежемесячная проверка избавят тебя от ночи, когда почта сообщает, что «ваш сервер скомпрометирован». Поверь мне, я знаю, о чём говорю — я через это прошёл.

Ещё расскажу про резервные копии и восстановление, потому что это неотделимо от безопасности. У меня бекапы лежат на отдельном диске, а снаружи — ещё одна копия в облаке. Ключевое — я проверяю восстановление, а не просто делаю дампы. Однажды я обнаружил, что полгода «бэкапил» пустую базу, потому что скрипт молча падал. С тех пор раз в месяц я разворачиваю бэкап на тестовой машине и убеждаюсь, что всё работает. Скучно, но именно это спасает в момент, когда диск реально умирает.

И про то, как я перестал бояться. После той ночи с майнером я первое время каждый день проверял логи и порты. Потом успокоился: когда базовая защита настроена, а мониторинг алертит о подозрительном — паранойя уходит. Ты знаешь, что если что-то случится, ты узнаешь об этом в первые минуты, а не через сутки. Вот это ощущение контроля — главное, что дала мне эта история.

И если уж говорить про автоматизацию — я настроил, чтобы раз в день приходил короткий отчёт: сколько попыток входа было, какие порты открыты, свободное место на дисках. На это уходит секунда на чтение, а картина держится в голове постоянно. Для домашнего сервера этого более чем достаточно, чтобы чувствовать себя уверенно.

Если вкратце — порядок действий для новичка: смени порт SSH, заведи ключи, включи fail2ban и ufw, настрой обновления, сделай двухфакторку. Затем изолируй сервисы и добавь мониторинг. В конце — проверь бекапы. Полдня работы, а потом годы спокойной жизни.

Ваш комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *