--- title: "Debian 12: базовая настройка и hardening для production" date: 2026-05-22 draft: false description: "Пошаговая настройка чистого Debian 12 (Bookworm) для production: SSH, firewall, fail2ban, swap, sysctl, автообновления, логи, бэкап конфигов." tags: ["debian-12", "security", "hardening", "ssh", "ufw", "fail2ban", "sysctl", "production", "linux"] categories: ["Безопасность"] series: ["Linux Hardening"] series_order: 1 --- # Debian 12: базовая настройка и hardening для production Поставил чистый Debian 12 и думаешь сразу накатывать приложения? Не торопись. Час на базовую настройку сейчас - это недели сэкономленного времени на разгребание последствий взлома или падения. Статья покрывает всё что нужно для production-сервера без контейнеров. Пройдёшь по шагам и получишь сервер с закрытым SSH, firewall, защитой от брутфорса, ограничением ресурсов ядра и автоматическими обновлениями безопасности. Docker - в следующей статье серии. ## Исходные данные - Чистый Debian 12 (Bookworm) - Root доступ по SSH - Статический IP Проверь версию: ```bash lsb_release -a ``` Ожидаемый вывод: ``` Distributor ID: Debian Description: Debian GNU/Linux 12 (bookworm) Release: 12 Codename: bookworm ``` Все команды выполняются от `root` если не указано иное. ## Обновление системы ```bash apt update apt upgrade -y apt dist-upgrade -y apt autoremove -y ``` Проверь нужна ли перезагрузка: ```bash [ -f /var/run/reboot-required ] && echo "Reboot needed" || echo "No reboot needed" ``` Если нужна - перезагрузись: ```bash reboot ``` ## Базовые утилиты ```bash apt install -y \ sudo curl wget git vim htop iotop iftop \ net-tools dnsutils tcpdump screen tmux rsync \ util-linux unzip ca-certificates gnupg2 lsb-release \ smartmontools ``` ## Настройка системы ### Hostname ```bash hostnamectl set-hostname srv01.example.com ``` Добавь в `/etc/hosts`: ```bash nano /etc/hosts ``` ``` 127.0.0.1 localhost 203.0.113.10 srv01.example.com srv01 ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters ``` Замени `203.0.113.10` на реальный IP сервера, `srv01.example.com` - на своё имя. Проверь FQDN: ```bash hostname -f # srv01.example.com ``` ### Timezone ```bash timedatectl set-timezone Europe/Moscow ``` Проверь: ```bash timedatectl ``` ### Локаль ```bash apt install -y locales dpkg-reconfigure locales ``` Выбери `en_US.UTF-8` как основную. Добавь `ru_RU.UTF-8` если нужна кириллица в системных сообщениях. Проверь: ```bash locale # LANG=en_US.UTF-8 ``` ## Пользователь и SSH ### Создание пользователя Root сессия - одна ошибка без возможности откатиться. `sudo` даёт контроль и лог действий. Создай непривилегированного пользователя: ```bash adduser admin ``` Добавь в sudo: ```bash usermod -aG sudo admin ``` Проверь: ```bash groups admin # admin : admin sudo ``` ### SSH ключи На своей рабочей машине сгенерируй ключ: ```bash # Linux/macOS ssh-keygen -t ed25519 -C "admin@srv01" ``` ```powershell # Windows ssh-keygen -t ed25519 ``` Скопируй публичный ключ на сервер: ```bash # Linux/macOS ssh-copy-id admin@203.0.113.10 ``` ```powershell # Windows type $env:userprofile\.ssh\id_ed25519.pub | ssh admin@203.0.113.10 "mkdir -m 700 -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys" ``` Проверь вход по ключу - не должен спрашивать пароль: ```bash ssh admin@203.0.113.10 ``` ### SSH hardening Залогинься под `admin` и открой конфиг: ```bash sudo nano /etc/ssh/sshd_config ``` Замени содержимое (или найди и измени каждый параметр): ``` # Нестандартный порт - отсекает 90% ботов Port 2222 # Только ключи PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys # Запретить root логин PermitRootLogin no # Только ключи, без паролей PasswordAuthentication no PermitEmptyPasswords no KbdInteractiveAuthentication no # Ограничения сессий MaxAuthTries 3 MaxSessions 3 LoginGraceTime 30 # Таймауты - отключать неактивные сессии ClientAliveInterval 300 ClientAliveCountMax 2 # Отключить лишнее X11Forwarding no PrintMotd no UsePAM yes AcceptEnv LANG LC_* # Только IPv4 (убери если используешь IPv6) AddressFamily inet ``` **КРИТИЧНО:** Перед перезапуском SSH открой вторую сессию и не закрывай её - страховка если что-то пойдёт не так. Проверь конфиг на ошибки: ```bash sudo sshd -t ``` Нет вывода - нет ошибок. Перезапусти: ```bash sudo systemctl restart sshd ``` В новом терминале проверь подключение на новом порту: ```bash ssh -p 2222 admin@203.0.113.10 ``` Если работает - старые сессии можно закрывать. ### SSH banner (опционально) Создай предупреждение при входе: ```bash sudo nano /etc/ssh/banner ``` ``` ############################################################################### # Доступ только для авторизованных пользователей. # # Все действия логируются. # # Несанкционированный доступ преследуется по закону. # ############################################################################### ``` Добавь в `sshd_config`: ``` Banner /etc/ssh/banner ``` Перезапусти SSH: ```bash sudo systemctl restart sshd ``` ## Firewall (UFW) **Важно:** сначала настраиваем правила, потом включаем. Иначе заблокируешь себя. ```bash sudo apt install -y ufw ``` Политика по умолчанию: ```bash # Блокировать все входящие sudo ufw default deny incoming # Разрешить все исходящие sudo ufw default allow outgoing ``` Разрешаем SSH на новом порту: ```bash # Замени 2222 на свой порт если менял sudo ufw allow 2222/tcp comment 'SSH' ``` Включаем firewall: ```bash sudo ufw enable ``` Проверь статус: ```bash sudo ufw status verbose ``` Ожидаемый вывод: ``` Status: active Logging: on (low) Default: deny (incoming), allow (outgoing), disabled (routed) New profiles: skip To Action From -- ------ ---- 2222/tcp ALLOW IN Anywhere # SSH 2222/tcp (v6) ALLOW IN Anywhere (v6) # SSH ``` ### Rate limiting на SSH ```bash # Блокировать IP после 6 подключений за 30 секунд sudo ufw limit 2222/tcp comment 'SSH rate limit' ``` ### Открытие дополнительных портов Когда будешь ставить сервисы - открывай только нужные порты: ```bash # HTTP/HTTPS sudo ufw allow 80/tcp comment 'HTTP' sudo ufw allow 443/tcp comment 'HTTPS' # PostgreSQL только с конкретного IP sudo ufw allow from 192.168.1.10 to any port 5432 comment 'PostgreSQL' ``` Проверь что слушает на хосте: ```bash ss -tulnp ``` Всё что слушает - должно быть либо закрыто firewall, либо намеренно открыто. ## Fail2ban ```bash sudo apt install -y fail2ban ``` Создай локальный конфиг - не редактируй `jail.conf`, он перезаписывается при обновлении: ```bash sudo nano /etc/fail2ban/jail.local ``` ```ini [DEFAULT] # Бан на 1 час bantime = 3600 # За 10 минут findtime = 600 # После 3 неудачных попыток maxretry = 3 # Не банить свои IP ignoreip = 127.0.0.1/8 ::1 # Явно указываем backend - важно для совместимости в серии Ubuntu/Rocky backend = systemd [sshd] enabled = true port = 2222 filter = sshd maxretry = 3 bantime = 3600 ``` Замени `2222` на свой SSH порт. Запусти: ```bash sudo systemctl enable fail2ban sudo systemctl start fail2ban ``` Проверь статус: ```bash sudo fail2ban-client status ``` ``` Status |- Number of jail: 1 `- Jail list: sshd ``` Проверь статус конкретного jail: ```bash sudo fail2ban-client status sshd ``` ## Swap Swap в виде файла гибче раздела: можно увеличить или уменьшить без переразбивки диска. ### Создание swap файла Проверь текущий swap: ```bash free -h sudo swapon --show ``` Создай файл (пример - 2GB): ```bash # Создать файл нужного размера sudo fallocate -l 2G /swapfile ``` Если `fallocate` не поддерживается файловой системой: ```bash sudo dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progress ``` Установи права - swap файл не должен читаться другими пользователями: ```bash sudo chmod 600 /swapfile ``` Инициализируй и активируй: ```bash # Разметить как swap sudo mkswap /swapfile # Включить sudo swapon /swapfile ``` Проверь: ```bash free -h sudo swapon --show ``` Добавь в `/etc/fstab` для автомонтирования после перезагрузки: ```bash echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab ``` ### Настройка swappiness `swappiness` определяет агрессивность использования swap. Для production снижаем - swap только когда RAM заполнена на 90%+: ```bash # Проверить текущее значение (по умолчанию 60) cat /proc/sys/vm/swappiness ``` Установи постоянно: ```bash echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.d/99-swap.conf sudo sysctl -p /etc/sysctl.d/99-swap.conf ``` ### Изменение размера swap (когда потребуется) ```bash # Отключить текущий swap sudo swapoff /swapfile # Изменить размер (пример - увеличить до 4GB) sudo fallocate -l 4G /swapfile # Переинициализировать sudo mkswap /swapfile # Включить sudo swapon /swapfile ``` Проверь результат: ```bash free -h ``` Запись в `/etc/fstab` менять не нужно - путь тот же. ### Удаление swap (если потребуется) ```bash sudo swapoff /swapfile sudo rm /swapfile ``` Удали строку из `/etc/fstab`: ```bash sudo sed -i '/\/swapfile/d' /etc/fstab ``` ## Sysctl - защита ядра Создай отдельный файл - чище чем писать в `/etc/sysctl.conf`: ```bash sudo nano /etc/sysctl.d/99-hardening.conf ``` ``` # Защита от SYN flood net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_max_syn_backlog = 2048 net.ipv4.tcp_synack_retries = 2 # Игнорировать ICMP redirects (защита от MITM) net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.default.accept_redirects = 0 net.ipv6.conf.all.accept_redirects = 0 net.ipv6.conf.default.accept_redirects = 0 # Не отправлять ICMP redirects net.ipv4.conf.all.send_redirects = 0 net.ipv4.conf.default.send_redirects = 0 # Игнорировать source routed packets net.ipv4.conf.all.accept_source_route = 0 net.ipv6.conf.all.accept_source_route = 0 # Защита от IP spoofing net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.default.rp_filter = 1 # Логировать подозрительные пакеты net.ipv4.conf.all.log_martians = 1 # Защита от time-wait assassination net.ipv4.tcp_rfc1337 = 1 # Отключить IPv6 если не используешь # net.ipv6.conf.all.disable_ipv6 = 1 # net.ipv6.conf.default.disable_ipv6 = 1 ``` Примени: ```bash sudo sysctl -p /etc/sysctl.d/99-hardening.conf ``` Проверь что применилось: ```bash sudo sysctl net.ipv4.tcp_syncookies # net.ipv4.tcp_syncookies = 1 ``` ## Автообновления безопасности ```bash sudo apt install -y unattended-upgrades apt-listchanges ``` ```bash sudo nano /etc/apt/apt.conf.d/50unattended-upgrades ``` Раскомментируй/измени: ``` Unattended-Upgrade::Mail "root"; Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; Unattended-Upgrade::Remove-Unused-Dependencies "true"; Unattended-Upgrade::Automatic-Reboot "false"; ``` `Automatic-Reboot "false"` - важно для production. Перезагрузку после обновления ядра делать вручную в удобное время. Включи: ```bash sudo dpkg-reconfigure -plow unattended-upgrades ``` Выбери `Yes`. Настрой расписание: ```bash sudo nano /etc/apt/apt.conf.d/10periodic ``` ``` APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Download-Upgradeable-Packages "1"; APT::Periodic::AutocleanInterval "7"; APT::Periodic::Unattended-Upgrade "1"; ``` Проверь что сервис работает: ```bash sudo systemctl status unattended-upgrades ``` ## Отключение ненужных сервисов (при наличии) Посмотри что запущено: ```bash systemctl list-units --type=service --state=running ``` Стандартные кандидаты на отключение - проверь что не используешь перед отключением: ```bash # Bluetooth - на сервере не нужен sudo systemctl disable --now bluetooth.service # avahi-daemon - mDNS/DNS-SD, нужен редко sudo systemctl disable --now avahi-daemon.service # ModemManager - управление модемами sudo systemctl disable --now ModemManager.service ``` Проверь что слушает на сетевых портах: ```bash ss -tulnp ``` Всё незнакомое - выясни что это и реши нужно ли. ## Логи и ротация ### Ограничение journald ```bash sudo nano /etc/systemd/journald.conf ``` Раскомментируй/измени: ``` SystemMaxUse=500M SystemMaxFileSize=100M MaxRetentionSec=1month ``` Перезапусти: ```bash sudo systemctl restart systemd-journald ``` Проверь размер: ```bash sudo journalctl --disk-usage ``` На чистом Debian 12 rsyslog не установлен - логи пишутся только в journald. Настройки выше достаточно. Если устанавливаешь rsyslog отдельно - создай /etc/logrotate.d/rsyslog с правилами ротации вручную. ## Мониторинг диска На VPS имя устройства зависит от гипервизора - не всегда `/dev/sda`. Определи актуальное: ```bash # Найти дисковые устройства lsblk -d -o NAME,TYPE | grep disk # NAME TYPE # vda disk # # Результат зависит от гипервизора и провайдера: # /dev/sda - KVM у некоторых провайдеров, Xen # /dev/vda - KVM (наиболее распространённый вариант) # /dev/xvda - Xen ``` Проверь состояние: ```bash # Замени vda на своё устройство sudo smartctl -H /dev/vda ``` Ожидаемый вывод: ``` # ATA диски: # SMART overall-health self-assessment test result: PASSED # # SCSI/NVMe диски (типично для VPS): # SMART Health Status: OK # # Оба варианта означают одно: диск здоров ``` Если `FAILED` - диск умирает. Срочно бэкап и замена. Детали SMART: ```bash sudo smartctl -a /dev/vda ``` Обращай внимание на `Reallocated_Sector_Ct`, `Pending_Sector_Count`, `Offline_Uncorrectable` - если ненулевые, диск проблемный. Примечание: На виртуальных дисках (VMware, KVM) SMART может быть недоступен: `SMART support is: Unavailable - device lacks SMART capability.` В этом случае smartctl полезен только для физических серверов. На VPS ориентируйся на мониторинг от провайдера. ## Бэкап конфигов Конфиги на диске - не бэкап. Скрипт архивирует `/etc/` и SSH ключи. ```bash nano ~/backup-configs.sh ``` ```bash #!/bin/bash BACKUP_DIR="$HOME/backups" DATE=$(date +%Y%m%d_%H%M%S) BACKUP_FILE="$BACKUP_DIR/config_backup_$DATE.tar.gz" mkdir -p "$BACKUP_DIR" # Сохранить список установленных пакетов dpkg --get-selections > "$HOME/installed-packages.txt" # Архивировать конфиги и SSH ключи sudo tar -czf "$BACKUP_FILE" \ /etc/ \ /root/.ssh/ \ /home/*/.ssh/ \ "$HOME/installed-packages.txt" \ 2>/dev/null echo "Backup: $BACKUP_FILE" ls -lh "$BACKUP_FILE" # Удалить бэкапы старше 30 дней find "$BACKUP_DIR" -name "config_backup_*.tar.gz" -mtime +30 -delete ``` Права и первый запуск: ```bash chmod +x ~/backup-configs.sh ~/backup-configs.sh ``` Ожидаемый вывод: ``` Backup: /home/admin/backups/config_backup_20260522_030000.tar.gz -rw-r--r-- 1 root root 1.2M May 22 03:00 /home/admin/backups/config_backup_20260522_030000.tar.gz ``` Автоматизация через cron (каждое воскресенье в 3:00): ```bash crontab -e ``` ``` 0 3 * * 0 /home/admin/backup-configs.sh >> /var/log/backup-configs.log 2>&1 ``` ### Восстановление Восстановить конфиги: ```bash sudo tar -xzf ~/backups/config_backup_ДАТА.tar.gz -C / ``` Восстановить список пакетов: ```bash sudo dpkg --set-selections < ~/installed-packages.txt sudo apt-get dselect-upgrade ``` ## Финальная проверка ```bash # Открытые порты ss -tulnp # Статус firewall sudo ufw status verbose # Статус fail2ban sudo fail2ban-client status sshd # Состояние диска sudo smartctl -H /dev/vda # Swap free -h ``` ## Что дальше Сервер готов к установке приложений. База одинакова для любой нагрузки - веб, база данных, почта. Если следующий шаг - контейнеры, читай продолжение серии: [Debian 12: настройка Docker-хоста для production](/posts/debian-12-docker-hardening/). **Стек этой статьи:** Debian 12 (Bookworm) · UFW · Fail2ban · OpenSSH · unattended-upgrades · systemd · smartmontools