Защита сервера: полный чек-лист
Шаг за шагом, с командами: от свежего VPS до сервера, которому можно доверять в продакшене.
За 30 секунд
Свежий сервер в интернете начинают сканировать в течение нескольких минут. Защита (hardening) означает сократить то, до чего может дотянуться атакующий, и ограничить то, что он сможет сделать, если проникнет внутрь: SSH только по ключам, файрвол с запретом по умолчанию, автоматические обновления безопасности, отдельные пользователи для приложений, приватные базы данных, HTTPS везде, WAF впереди и бэкапы, из которых вы реально восстанавливались. Ни одного шага по отдельности недостаточно; вместе они делают даже небольшой сервер по-настоящему трудным для взлома.
Почему я это использую
- Я применяю письменный базовый набор безопасности к каждому серверу, который веду, потому что последовательность важнее героизма: одни и те же восемь проверок везде.
- Большинство реальных взломов, о которых я слышу, — это не хитрые эксплойты, а открытый порт базы, вход по паролю или забытое обновление.
- К собственным инструментам я подхожу с той же меркой: когда я работаю с серверами вместе с AI-агентом, по умолчанию он работает только на чтение, и каждое изменение требует моего одобрения.
- Защищённый и задокументированный сервер проще передать, проверить и восстановить — а именно за это платят клиенты.
Как это работает
01Мышление: слои и минимальные привилегии
Защита сервера строится на двух принципах. Эшелонированная защита: исходите из того, что любой отдельный слой может отказать, и складывайте несколько (WAF на краю, файрвол, политика SSH, права приложений, бэкапы). Минимальные привилегии: каждый пользователь, процесс и ключ получает только тот доступ, который ему нужен, чтобы компрометация оставалась небольшой. Действуйте в безопасном порядке, потому что классическая авария при защите сервера — запереть самого себя. Сначала создайте своего пользователя и ключ, убедитесь во втором терминале, что можете войти с ними, и только потом отключайте root и пароли. Разрешите SSH в файрволе до его включения. Держите веб-консоль провайдера как запасной выход. Записывайте каждый шаг в короткий runbook или скрипт, чтобы следующий сервер получил ровно такую же обработку и вы могли показать клиенту, что было сделано.
- Сокращайте поверхность атаки: меньше открытых портов, сервисов и пакетов.
- Ограничивайте радиус поражения: отдельные пользователи, частные сети, учётные данные с узкими правами.
- Исходите из того, что взлом возможен: бэкапы вне площадки, логи и алерты, которые вы действительно будете читать.
021. Пользователи и SSH: только ключи, без root
Создайте личного администратора с sudo и установите свой публичный ключ (ключ Ed25519 — современный стандарт). Затем отключите вход под root и аутентификацию по паролю через отдельный файл в /etc/ssh/sshd_config.d/, который переживает обновления пакетов лучше, чем правка основного файла. В Ubuntu сервис называется ssh. Проверьте конфиг через sshd -t перед reload и держите текущую сессию открытой, пока тестируете новый вход в другом терминале. Смена порта SSH лишь уменьшает шум в логах; это не мера безопасности, так что делайте это, только если хотите более тихие логи. В командах дайте каждому человеку собственного пользователя и ключ, чтобы доступ можно было отзывать индивидуально, и удаляйте ключи ушедших людей.
# On the server, as root (one time)
adduser your_user
usermod -aG sudo your_user
# From your laptop
ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]
# /etc/ssh/sshd_config.d/99-hardening.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
AllowUsers your_user
# Validate, then reload (keep the current session open!)
sudo sshd -t && sudo systemctl reload ssh
032. Файрвол, обновления и fail2ban
По умолчанию запретите весь входящий трафик и откройте только то, что обслуживает сервер: SSH, HTTP и HTTPS. Продублируйте те же правила в файрволе облачного провайдера, чтобы трафик фильтровался ещё до того, как дойдёт до машины. Одна важная ловушка: Docker публикует порты контейнеров, записывая собственные правила iptables, которые обходят ufw. В файлах Compose привязывайте опубликованные порты к 127.0.0.1, если им действительно не нужно быть публичными. Далее включите unattended-upgrades для патчей безопасности; большинство обновлений ядра всё равно требует перезагрузки, так что запланируйте окно обслуживания или разрешите автоматические перезагрузки в тихий час. Установите fail2ban, чтобы банить источники brute force. Наконец, удалите сервисы, которыми не пользуетесь: каждый слушающий демон — это ещё одна вещь, которую нужно патчить.
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 verbose
sudo apt update && sudo apt install -y unattended-upgrades fail2ban
sudo dpkg-reconfigure -plow unattended-upgrades
# Optional: /etc/apt/apt.conf.d/50unattended-upgrades
# Unattended-Upgrade::Automatic-Reboot "true";
# Unattended-Upgrade::Automatic-Reboot-Time "04:00";
sudo ss -tulpn # everything listening; nothing unexpected on 0.0.0.0
043. Приложения: отдельные пользователи, права, приватные базы, секреты
Запускайте каждый сайт или приложение под собственным системным пользователем со своим пулом PHP-FPM или записью в менеджере процессов. Если одно приложение взломают, оно не сможет прочитать код, загрузки или env-файл другого. Код должен принадлежать пользователю deploy и быть недоступным для записи веб-процессу; доступны для записи только папки, которые должны меняться во время работы (storage и bootstrap/cache в Laravel, папки загрузок). Env-файлы доступны для чтения только пользователю приложения. Базы данных и Redis слушают localhost или частную сеть, и у каждого приложения свой пользователь БД с минимальными правами. Секреты живут в env-файлах на сервере или в менеджере секретов, никогда в Git, и ротируются, когда кто-то уходит или есть подозрение на утечку. Прогоняйте по репозиторию сканер секретов, потому что утёкшие ключи в старых коммитах — частый источник взломов.
# One system user per app, no login shell
sudo adduser --system --group --home /var/www/shop --shell /usr/sbin/nologin shop
# Code: owned by the deploy user, readable by the app group
sudo chown -R deploy:shop /var/www/shop
sudo find /var/www/shop -type d -exec chmod 750 {} +
sudo find /var/www/shop -type f -exec chmod 640 {} +
# Only runtime folders are writable by the app
sudo chmod -R 770 /var/www/shop/storage /var/www/shop/bootstrap/cache
# Secrets: readable by the app only
sudo chown deploy:shop /var/www/shop/.env && sudo chmod 640 /var/www/shop/.env
054. HTTPS везде и WAF впереди
Каждый сайт получает сертификат, обычно от Let's Encrypt через certbot, с автоматическим продлением (certbot устанавливает таймер systemd; проверьте его через dry run). Перенаправляйте HTTP на HTTPS, используйте только TLS 1.2 и 1.3 и добавьте HSTS, когда убедитесь, что каждый поддомен работает по HTTPS. Cloudflare или похожий CDN/WAF впереди скрывает IP origin-сервера, поглощает базовый DDoS-трафик и позволяет блокировать плохих ботов и применять rate limits на краю. Используйте режим SSL Full (strict), чтобы соединение от Cloudflare до вашего сервера было зашифровано, а сертификат проверялся; Flexible отправляет трафик на origin незашифрованным. Для дополнительной защиты разрешите 80 и 443 только с диапазонов IP Cloudflare или используйте туннель, чтобы атакующие не могли обойти край, обращаясь к IP origin напрямую.
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
sudo certbot renew --dry-run
systemctl list-timers | grep certbot
# nginx: modern TLS and HSTS (add HSTS only when all subdomains use HTTPS)
ssl_protocols TLSv1.2 TLSv1.3;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
server_tokens off;
065. Бэкапы, мониторинг и аудит
Защита сервера — это ещё и умение пережить то, что не удалось предотвратить. Делайте снапшоты у провайдера и, отдельно, бэкапы баз данных и загрузок на уровне приложения, скопированные в другой аккаунт или к другому провайдеру. Проверяйте восстановление по расписанию: непроверенный бэкап — это надежда, а не план. Мониторьте то, что обычно убивает небольшие серверы: заполненные диски, исчерпание памяти, истёкшие сертификаты и упавший сайт. Внешний мониторинг доступности (Uptime Kuma или алерты провайдера) плюс алерты по диску и нагрузке покрывают большую часть. Храните логи достаточно долго, чтобы расследовать инцидент. Затем проводите аудит: Lynis сканирует систему и выдаёт конкретные рекомендации по защите с оценкой — хороший способ поймать то, что пропустил чек-лист. Повторяйте его после изменений и сохраняйте отчёт.
# Audit the system and read the suggestions
sudo apt install -y lynis
sudo lynis audit system
sudo less /var/log/lynis-report.dat
# Quick health checks
df -h # disk usage
free -h # memory
sudo last -n 20 # recent logins
sudo journalctl -p err -b # errors since boot
sudo fail2ban-client status sshd
Когда применять
- На каждом новом сервере, до деплоя первого приложения.
- Когда вы унаследовали сервер: сначала аудит, затем пошаговое применение чек-листа.
- После любого инцидента или «почти инцидента» — как разбор того, какой слой отказал.
- Периодически (например, ежеквартально), потому что серверы «дрейфуют», пока люди делают быстрые правки.
Когда не стоит
- Не применяйте агрессивные изменения ядра или SSH на продакшен-сервере без второй сессии и запасного доступа через консоль.
- Не гонитесь за идеальной оценкой аудита в ущерб работающей и поддерживаемой системе; расставляйте приоритеты по реальным рискам.
Альтернативы
- Управляемые платформы (PaaS)
Провайдер защищает и патчит ОС; вы защищаете приложение и его конфигурацию.
- Ansible или cloud-init
Автоматизируйте тот же чек-лист, чтобы каждый сервер защищался одинаково и воспроизводимо.
- CIS Benchmarks
Подробные формальные стандарты защиты; полезны для соответствия требованиям, но тяжелее, чем нужно большинству небольших команд.
- Cloudflare Tunnel или VPN
Полностью убирают публичные порты на origin; доступ идёт через аутентифицированный туннель.
Лучшие практики
- SSH только по ключам, без входа под root, персональные учётки для каждого администратора.
- Файрвол с запретом по умолчанию на хосте и у провайдера; открыты только 22, 80 и 443.
- Автоматические обновления безопасности и регулярное окно для перезагрузок.
- Один системный пользователь на приложение, минимальные права на файлы и пользователи БД.
- Базы данных и Redis только на localhost или в частной сети.
- HTTPS везде с автопродлением, Cloudflare Full (strict) и правила WAF на краю.
- Бэкапы вне площадки, плановые тесты восстановления, алерты по доступности и диску и периодический аудит Lynis.
Частые ошибки
- Отключают вход по паролю, не убедившись, что вход по ключу работает, и потом заходят обратно через консоль провайдера.
- Доверяют ufw, пока Docker публикует порты базы данных на весь интернет.
- Запускают все сайты от www-data, так что один уязвимый плагин открывает все сайты на сервере.
- Используют Cloudflare Flexible SSL, оставляя соединение с origin незашифрованным.
- Хранят бэкапы только на том же сервере, где шифровальщик или удалённый дроплет заберут их вместе с ним.
Глубже
07SSH изнутри в современной Ubuntu: socket activation и криптография
Начиная с Ubuntu 24.04, SSH использует socket activation в systemd: ssh.socket слушает порт и запускает ssh.service при первом подключении. Генератор systemd читает Port и ListenAddress из sshd_config, чтобы собрать сокет, поэтому смена порта требует daemon-reload плюс перезапуска ssh.socket, а не просто reload сервиса. Многие заблокировали себе доступ: поменяли Port, перезагрузили ssh и закрыли сессию, а сокет всё ещё слушал 22, тогда как файрвол разрешал только новый порт. Что касается криптографии, текущие настройки OpenSSH по умолчанию хороши: свежие релизы автоматически согласуют гибридный постквантовый обмен ключами, а ключи Ed25519 — стандарт. Не копируйте старые списки шифров из блогов — они часто ослабляют современные настройки. sshd -T выводит действующую конфигурацию после всех drop-in, а инструмент ssh-audit сообщает о слабых алгоритмах. Для максимальной надёжности используйте аппаратные ключи (ed25519-sk) на security key, чтобы украденный с ноутбука файл был бесполезен.
# /etc/ssh/sshd_config.d/99-hardening.conf
Port 2222
# Open the new port first, then rebuild the socket
sudo ufw allow 2222/tcp
sudo sshd -t
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
sudo ss -tlnp | grep -E ':22 |:2222 '
# Effective settings after all drop-ins
sudo sshd -T | grep -E 'permitrootlogin|passwordauthentication|port'
08Песочница для сервисов с помощью systemd
Отдельный Unix-пользователь ограничивает, какие файлы может прочитать скомпрометированное приложение, но процесс всё равно видит большую часть файловой системы, может писать в /tmp, запускать произвольные бинарники и открывать любые сетевые сокеты. systemd может ограничить каждый сервис гораздо сильнее несколькими строками в drop-in: доступ к ОС только на чтение, никакого доступа к домашним каталогам, приватный /tmp, запрет повышения привилегий через setuid-бинарники и только нужные семейства адресов. systemd-analyze security оценивает каждый юнит от 0 (хорошо защищён) до 10 (открыт) и перечисляет недостающие опции, что делает защиту измеримой. Применяйте опции постепенно и тестируйте, потому что слишком тесная песочница проявляется ошибками доступа во время работы. MemoryMax и CPUQuota к тому же не дают одному вышедшему из-под контроля процессу положить весь сервер. Те же идеи есть и для контейнеров: запуск не от root, корневая файловая система только для чтения, урезанные capabilities.
# /etc/systemd/system/web.service.d/hardening.conf
[Service]
User=web
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ReadWritePaths=/var/www/web/shared
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
CapabilityBoundingSet=
MemoryMax=1G
# Then: sudo systemctl daemon-reload && systemd-analyze security web.service
09Настройки ядра и сети
Настройки sysctl управляют поведением ядра. Ubuntu уже поставляет разумные значения по умолчанию в /etc/sysctl.d/10-*.conf: SYN cookies, защищённые symlink и hardlink, ограниченные указатели ядра, а начиная с 24.04 — ограничения AppArmor на непривилегированные user namespaces. Небольшой дополнительный файл ещё сильнее укрепляет сетевой стек: игнорировать ICMP redirect и пакеты с source routing, которые могут перенаправить трафик, не отправлять redirect, раз сервер не маршрутизатор, и логировать пакеты с невозможными адресами источника. Два предостережения. Docker, Kubernetes и VPN-серверам нужен net.ipv4.ip_forward = 1, поэтому никогда не отключайте forwarding вслепую на таких хостах. А строгая проверка обратного пути (rp_filter = 1) может сломать серверы с несколькими интерфейсами и асимметричной маршрутизацией; поэтому Ubuntu по умолчанию использует мягкий режим (2). Применяйте через sysctl --system и перед раскаткой проверьте, что сеть и контейнеры по-прежнему работают.
# /etc/sysctl.d/99-hardening.conf
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.tcp_syncookies = 1
kernel.dmesg_restrict = 1
kernel.kptr_restrict = 2
# Apply and check one value
sudo sysctl --system
sysctl net.ipv4.conf.all.accept_redirects
10Обнаружение: как узнать, что слой защиты не сработал
Предотвращение рано или поздно даёт сбой, поэтому заранее планируйте, как это заметить. Отправляйте логи за пределы сервера (пересылка journald, Loki или облачный сервис), потому что атакующий с root первым делом правит локальные логи. auditd записывает значимые для безопасности события, например изменения /etc/passwd, sudoers или SSH-ключей. Проверка целостности файлов вроде AIDE строит базу хэшей системных файлов и сообщает об изменениях; запускайте её по таймеру и храните эталонную базу вне хоста. У патчинга тоже есть сторона обнаружения. unattended-upgrades устанавливает исправления, но работающие процессы держат старые библиотеки в памяти до перезапуска: needrestart их показывает, а /var/run/reboot-required сообщает, что новое ядро ждёт перезагрузки. Ubuntu Pro, бесплатная для небольшого числа личных машин, добавляет Livepatch для исправлений ядра без перезагрузки и Ubuntu Security Guide для автоматических профилей CIS или DISA-STIG. Ставьте алерты на новых sudo-пользователей, новые записи в authorized_keys и неожиданные слушающие порты.
# Watch changes to identity and SSH files
sudo apt install -y auditd
sudo auditctl -w /etc/passwd -p wa -k identity
sudo auditctl -w /etc/sudoers.d -p wa -k sudoers
sudo auditctl -w /home/your_user/.ssh/authorized_keys -p wa -k sshkeys
sudo ausearch -k sshkeys --start today
# Services still running old libraries, and pending reboot
sudo needrestart -r l
[ -f /var/run/reboot-required ] && cat /var/run/reboot-required.pkgs
Реальные ситуации
Вам достался сервер с SSH по паролю и открытой базой
Проблема
Клиент передаёт сервер, который работает годами. Root входит по паролю, MySQL слушает 0.0.0.0, никто не знает, какие cron-задачи важны, а сайт должен оставаться онлайн.
Как решить
Проведите аудит до любых изменений: сделайте снимок у провайдера, запустите ss -tulpn, составьте список пользователей, sudoers, authorized_keys, crontab и включённых сервисов, и запустите Lynis для отправной точки. Затем закройте самый большой риск минимальным изменением: привяжите MySQL к 127.0.0.1 (сначала проверьте, что от него не зависит ни одно внешнее приложение) и закройте 3306 в файрволе провайдера. Дальше создайте личного sudo-пользователя с ключом, проверьте его во второй сессии, затем отключите вход root и вход по паролю. Включите ufw, заранее разрешив SSH. Смените пароли базы и root — они могли утечь ещё годы назад. Задокументируйте каждый шаг для клиента.
CPU на 100 процентах из-за неизвестного процесса
Проблема
Мониторинг показывает постоянную полную загрузку CPU. top выявляет процесс со случайным именем, который работает от веб-пользователя и подключается к неизвестному адресу. Сайт при этом работает.
Как решить
Считайте это взломом, а не проблемой производительности. Сначала сделайте снимок диска как улику, затем изолируйте: ограничьте исходящий трафик в файрволе провайдера и переведите сайт в режим обслуживания. Соберите всё, что можно (ps auxf, ss -tupn, путь к бинарнику через /proc/PID/exe, crontab веб-пользователя, недавно изменённые файлы в web root). Найдите точку входа — обычно это устаревший плагин или форма загрузки, принимающая PHP. Не ограничивайтесь тем, чтобы убить процесс и работать дальше: поднимите чистый сервер по вашему эталону, задеплойте код из Git, восстановите данные из бэкапа, снятого до взлома, смените все секреты, которые хранились на сервере, и закройте дыру до выхода в онлайн.
Redis в Docker доступен из интернета
Проблема
Внешнее сканирование портов показывает открытый 6379, хотя ufw запрещает всё, кроме 22, 80 и 443. В Compose-файле опубликован '6379:6379', чтобы разработчик мог подключаться из дома.
Как решить
Опубликованные порты Docker обходят ufw, так что сканер прав. Немедленно поменяйте маппинг на 127.0.0.1:6379:6379 или вообще уберите ports, чтобы другие контейнеры ходили к Redis через сеть Compose, затем docker compose up -d. В любом случае задайте пароль Redis или ACL-пользователя. Разработчику дайте SSH-туннель: ssh -L 6379:127.0.0.1:6379 [email protected]. Проверьте Redis на признаки злоупотребления, например неизвестные ключи или изменённые dir и dbfilename, которые атакующие используют для записи файлов. Добавьте файрвол провайдера как второй слой и запланируйте внешнее сканирование портов, чтобы следующую ошибку поймал мониторинг, а не атакующий.
Шпаргалка
- Действующие настройки SSH
sudo sshd -T | grep -Ei 'permitrootlogin|passwordauthentication'- Применить смену порта SSH в Ubuntu 24.04+
sudo systemctl daemon-reload && sudo systemctl restart ssh.socket- Правила файрвола с номерами (чтобы удалить одно)
sudo ufw status numbered && sudo ufw delete 3- Всё, что слушает порты, с процессами
sudo ss -tulpn- Просканировать свой сервер снаружи
nmap -Pn -p- 203.0.113.10- Предпросмотр автоматических обновлений
sudo unattended-upgrade --dry-run --debug- Ожидаемая перезагрузка после обновлений
cat /var/run/reboot-required.pkgs- Оценить песочницу сервиса
systemd-analyze security nginx.service- Недавние неудачные входы
sudo journalctl -u ssh --since today | grep -i 'invalid user'- Короткоживущий SSH-сертификат для пользователя
ssh-keygen -s user_ca -I alice -n alice -V +8h id_ed25519.pub
В моих реальных проектах
- Я внедряю базовый набор из восьми пунктов на каждом сервере, который веду: SSH только по ключам, файрвол только с 22/80/443, приватные базы данных, fail2ban с unattended-upgrades, пользователь на приложение, снапшоты с проверенным восстановлением, мониторинг и HTTPS с Cloudflare впереди.
- Я управляю серверами по SSH с ключами и работаю с AI-агентом по строгим правилам: по умолчанию только чтение, каждое изменение одобряю я.
- На одном сервере я снизил заполненность диска примерно с 91% до 66%, почистив логи, старые сборки и раздутые node_modules, — напоминание о том, что мониторинг диска тоже часть безопасности.
Вопросы и ответы
Q1Что вы делаете первым делом на новом Linux-сервере?
Обновляю пакеты, создаю личного пользователя с sudo и устанавливаю свой SSH-ключ, проверяю вход по ключу во второй сессии, затем отключаю вход под root и аутентификацию по паролю. Дальше ufw с запретом входящего по умолчанию, разрешающий только SSH, 80 и 443, продублированный в облачном файрволе. Затем unattended-upgrades и fail2ban, часовой пояс и hostname и проверка через ss, что ничего неожиданного не слушает порты. Перед деплоем приложений я создаю системного пользователя на приложение, держу базы на localhost, настраиваю certbot с автопродлением, ставлю впереди Cloudflare в режиме Full (strict) и настраиваю бэкапы и мониторинг доступности. В идеале всё это — скрипт или роль Ansible, чтобы каждый сервер был идентичен.
Q2Смена порта SSH — хорошая мера безопасности?
Она снижает шум, а не риск. Перенос SSH с порта 22 сокращает число автоматических попыток входа в логах, потому что многие боты пробуют только порт по умолчанию, но любое целенаправленное сканирование находит новый порт за секунды. Настоящую защиту дают аутентификация только по ключам, запрет входа под root, файрвол, в идеале ограничивающий SSH известными IP или VPN, и fail2ban. Если команда меняет порт, я слежу, чтобы правило файрвола обновили до изменения SSH, чтобы никого не заперло, и чтобы это было задокументировано. Для меня это необязательная косметика поверх настоящих мер.
Q3Почему Docker может обходить ufw и как это предотвратить?
ufw управляет собственными цепочками iptables, но когда контейнер публикует порт, Docker вставляет свои правила NAT и пересылки в цепочки, которые проверяются раньше входящих правил ufw. Поэтому файл Compose с ports 5432:5432 делает PostgreSQL доступным из интернета, хотя ufw говорит deny. Самое простое решение — привязывать опубликованные порты к localhost, например 127.0.0.1:5432:5432, или вообще не публиковать внутренние сервисы, позволив контейнерам общаться через сеть Docker. Файрвол облачного провайдера — вторая страховка, потому что фильтрует трафик ещё до того, как он дойдёт до хоста. Я всегда проверяю снаружи сканированием портов.
Q4Как вы управляете секретами на сервере?
Секреты никогда не попадают в Git. На простом сервере они живут в env-файлах, принадлежащих пользователю deploy, доступных для чтения только группе приложения, с правами вроде 640, за пределами корня сайта. Для более крупных конфигураций менеджер секретов, например Vault, AWS Secrets Manager, Doppler или зашифрованные файлы с SOPS, подставляет их во время деплоя или запуска. Каждое приложение и окружение получает собственные учётные данные с минимальными правами, чтобы ключи staging не могли дотянуться до продакшена. Я ротирую секреты, когда люди уходят или после любого подозрения на утечку, и запускаю сканирование секретов в CI, потому что утёкшие ключи в старых коммитах — частый источник взломов.
Q5Что Cloudflare добавляет к безопасности сервера и какой режим SSL использовать?
Cloudflare стоит между посетителями и вашим сервером: скрывает IP origin, поглощает объёмные DDoS-атаки, даёт WAF, защиту от ботов и rate limiting и кэширует статический контент. Режим SSL должен быть Full (strict): посетители подключаются к Cloudflare по HTTPS, а Cloudflare подключается к вашему серверу по HTTPS, проверяя сертификат origin — от Let's Encrypt или origin-сертификат Cloudflare. Режим Flexible оставляет соединение с origin незашифрованным и часто вызывает циклические редиректы. Чтобы атакующие не обходили Cloudflare, ограничьте порты 80 и 443 диапазонами IP Cloudflare, используйте authenticated origin pulls или туннель, чтобы веб-порты вообще не были открыты.
Q6Как понять, что сервер действительно защищён, а не просто однажды настроен?
Проверяя постоянно, а не полагаясь на память. Я храню базовый набор как чек-лист или автоматизацию и прогоняю его повторно, использую Lynis для аудита системы и сравниваю оценки во времени, а также сканирую публичный IP сервера снаружи, чтобы увидеть, какие порты действительно открыты. Мониторинг шлёт алерты по диску, доступности и истечению сертификатов, а логи fail2ban и аутентификации показывают активность входов. Я периодически пересматриваю учётные записи и SSH-ключи и удаляю устаревшие. И я проверяю восстановление, потому что восстановление — часть безопасности. Конфигурация дрейфует, пока люди делают быстрые правки, поэтому защита сервера — это регулярный процесс с доказательствами, а не разовая задача.
Вопросы уровня senior
S1Патчить серверы на месте или пересобирать их из образов?
Патчинг на месте прост и подходит для нескольких долгоживущих серверов: автоматические обновления безопасности, окно для перезагрузок и управление конфигурацией против дрейфа. Слабость в том, что каждый сервер постепенно становится уникальным, и после инцидента нельзя быть уверенным, что на нём лежит. Immutable infrastructure собирает свежий образ или контейнер на каждое изменение — через Packer, cloud-init или Docker — и заменяет серверы, а не изменяет их. Дрейф исчезает, откат — это повторный деплой, а скомпрометированный хост просто уничтожается. Это требует stateless-серверов, автоматизации и пайплайна, то есть реальных вложений. Мой прагматичный путь: патчинг на месте со скриптовыми эталонами для небольших парков и неизменяемые образы, когда состояние живёт в managed-сервисах и появляется несколько одинаковых серверов приложения.
S2Как вы управляете SSH-доступом для растущей команды?
Копирование публичных ключей в authorized_keys не масштабируется: при уходе человека приходится править каждый сервер, а ключи никогда не истекают. Варианты получше, по возрастанию зрелости: централизованно управлять ключами через Ansible, чтобы добавление или удаление человека было одним изменением; поставить bastion или VPN, чтобы серверы вообще не открывали SSH наружу; затем перейти на SSH-сертификаты. С сертификатами серверы доверяют одному ключу CA через TrustedUserCAKeys, а люди получают сертификаты, подписанные на несколько часов, в идеале выдаваемые после single sign-on с MFA инструментом вроде identity-aware proxy. Доступ истекает автоматически, логи показывают, кто подключался, а offboarding происходит в identity provider. Доступ на запись в продакшен тоже должен выдаваться реже, чем на чтение, а sudo — логироваться.
S3Cloudflare Tunnel или allowlist в файрволе для защиты origin?
Allowlist оставляет порты 80 и 443 открытыми, но принимает только опубликованные диапазоны Cloudflare. Это просто и быстро, но список иногда меняется и требует обновления, а любой другой пользователь Cloudflare теоретически может пройти через него к вашему origin, если вы не используете ещё и authenticated origin pulls. Tunnel запускает на сервере небольшой демон, который подключается к Cloudflare исходящим соединением, так что у origin вообще нет входящих веб-портов, и через него можно даже пропускать SSH с политиками доступа Zero Trust. Цена — ещё один процесс для мониторинга, более тесная привязка к одному вендору и отладка через туннель. Для небольшого парка за Cloudflare я предпочитаю tunnel или allowlist плюс origin-сертификаты; оба варианта лучше, чем оставить origin открытым.
Глоссарий
- Поверхность атаки
- Всё, до чего атакующий может дотянуться и что может попробовать: открытые порты, сервисы, входы, загруженные файлы и открытые API.
- Радиус поражения
- Сколько вреда может нанести один скомпрометированный аккаунт, ключ или сервис, прежде чем его остановят другие средства защиты.
- Эшелонированная защита
- Наслоение независимых уровней безопасности, чтобы отказ одного не открывал всю систему.
- Drop-in файл
- Небольшой конфиг в каталоге .d, который переопределяет основной конфиг и переживает обновления пакетов.
- Socket activation
- systemd сам слушает порт и запускает сервис только при поступлении соединения.
- AppArmor
- Система мандатного контроля доступа в Ubuntu, ограничивающая, что конкретные программы могут читать, писать или запускать.
- sysctl
- Интерфейс для чтения и установки параметров ядра во время работы; сохраняются в файлах /etc/sysctl.d.
- HSTS
- Заголовок ответа, который велит браузерам в течение заданного срока использовать для домена только HTTPS.
- Bastion host
- Единственный укреплённый сервер, служащий единственной точкой входа по SSH в приватную сеть.
- SSH-сертификат
- Ключ пользователя или хоста, подписанный доверенным CA, со встроенным сроком действия; заменяет разрозненные записи authorized_keys.
Что изучить дальше
Есть идея продукта?Давайте создадим его.
Расскажите о своей идее, продукте или команде. Обычно отвечаю в течение одного рабочего дня.