1144 lines
29 KiB
Markdown
1144 lines
29 KiB
Markdown
---
|
|
title: "Ubuntu 24.04: базовая настройка и hardening для production"
|
|
date: 2026-07-07
|
|
draft: false
|
|
description: "Пошаговая настройка Ubuntu 24.04 LTS (Noble Numbat) для production: SSH, firewall, fail2ban, swap, sysctl, автообновления, логи, бэкап конфигов."
|
|
tags: ["ubuntu-24.04", "security", "hardening", "ssh", "ufw", "fail2ban", "sysctl", "production", "linux"]
|
|
categories: ["Безопасность"]
|
|
series: ["Linux Hardening"]
|
|
series_order: 3
|
|
---
|
|
|
|
# Ubuntu 24.04: базовая настройка и hardening для production
|
|
|
|
Ubuntu 24.04 LTS - production-ready дистрибутив с поддержкой до 2029 года (стандартная) и до 2034 года (расширенная через Ubuntu Pro). Из коробки он безопаснее голого Debian - UFW предустановлен, `unattended-upgrades` работает сразу - но настройки по умолчанию далеки от production-ready.
|
|
|
|
Статья покрывает всё что нужно для сервера без контейнеров. Docker - отдельная тема.
|
|
|
|
**Что получишь на выходе:**
|
|
- SSH доступен только по ключам с нестандартного порта
|
|
- Firewall блокирует всё лишнее
|
|
- Fail2ban режет брутфорс
|
|
- Swap настроен как файл (гибко, без переразбивки диска)
|
|
- Ядро защищено от базовых сетевых атак
|
|
- Автообновления безопасности без ручного вмешательства
|
|
- Ненужные сервисы отключены
|
|
- Логи ротируются, диск не забивается
|
|
- Конфиги забэкаплены
|
|
|
|
## Исходные данные
|
|
|
|
- Чистый Ubuntu 24.04 LTS (Noble Numbat)
|
|
- Root доступ или пользователь с sudo
|
|
- Статический IP
|
|
|
|
Проверь версию:
|
|
|
|
```bash
|
|
lsb_release -a
|
|
```
|
|
|
|
Ожидаемый вывод:
|
|
```
|
|
Distributor ID: Ubuntu
|
|
Release: 24.04
|
|
Codename: noble
|
|
```
|
|
|
|
**Про пользователя:** Ubuntu при установке создаёт непривилегированного пользователя с sudo. Если устанавливал с таким пользователем - используй его. Если получил root-only сервер (облако, VPS) - создадим пользователя в разделе SSH.
|
|
|
|
Все команды выполняются с `sudo` если не указано иное. Если работаешь от root - `sudo` можно опустить.
|
|
|
|
## Обновление системы
|
|
|
|
```bash
|
|
sudo apt update
|
|
sudo apt upgrade -y
|
|
sudo apt dist-upgrade -y
|
|
sudo apt autoremove -y
|
|
```
|
|
|
|
Ubuntu использует `needrestart` - после обновления сам сообщит какие сервисы нужно перезапустить. Если обновилось ядро, предложит перезагрузиться.
|
|
|
|
Проверь явно:
|
|
|
|
```bash
|
|
[ -f /var/run/reboot-required ] && echo "Reboot needed" || echo "No reboot needed"
|
|
```
|
|
|
|
Если нужна:
|
|
|
|
```bash
|
|
sudo reboot
|
|
```
|
|
|
|
### Snap пакеты
|
|
|
|
Ubuntu активно использует snap. Обнови snap пакеты отдельно:
|
|
|
|
```bash
|
|
sudo snap refresh
|
|
```
|
|
|
|
Посмотри что установлено из snap:
|
|
|
|
```bash
|
|
snap list
|
|
```
|
|
|
|
Удали ненужное - каждый snap это отдельный процесс и место на диске:
|
|
|
|
```bash
|
|
# Пример удаления
|
|
sudo snap remove lxd
|
|
sudo snap remove multipass
|
|
```
|
|
|
|
На минимальной серверной установке snap пакетов обычно нет или только `core` - это нормально.
|
|
|
|
## Базовые утилиты
|
|
|
|
```bash
|
|
sudo apt install -y \
|
|
curl wget git vim htop iotop iftop \
|
|
net-tools dnsutils tcpdump \
|
|
screen tmux \
|
|
rsync unzip \
|
|
ca-certificates gnupg2 lsb-release \
|
|
smartmontools
|
|
```
|
|
|
|
## Настройка системы
|
|
|
|
### Hostname
|
|
|
|
```bash
|
|
sudo hostnamectl set-hostname srv01.example.com
|
|
```
|
|
|
|
Добавь в `/etc/hosts`:
|
|
|
|
```bash
|
|
sudo nano /etc/hosts
|
|
```
|
|
|
|
```
|
|
127.0.0.1 localhost
|
|
YOUR_IP srv01.example.com srv01
|
|
|
|
::1 localhost ip6-localhost ip6-loopback
|
|
ff02::1 ip6-allnodes
|
|
ff02::2 ip6-allrouters
|
|
```
|
|
|
|
Замени `YOUR_IP` на реальный IP сервера.
|
|
|
|
### Timezone
|
|
|
|
```bash
|
|
sudo timedatectl set-timezone Europe/Moscow
|
|
```
|
|
|
|
Проверь:
|
|
|
|
```bash
|
|
timedatectl
|
|
```
|
|
|
|
Ubuntu 24.04 использует `systemd-timesyncd` для синхронизации времени - он работает из коробки. Проверь:
|
|
|
|
```bash
|
|
timedatectl show-timesync
|
|
```
|
|
|
|
Если нужен `ntpd` вместо `timesyncd` - это отдельная история. Для большинства серверов `timesyncd` достаточен.
|
|
|
|
### Локаль
|
|
|
|
```bash
|
|
sudo apt install -y locales
|
|
sudo dpkg-reconfigure locales
|
|
```
|
|
|
|
Выбери `en_US.UTF-8` как основную. Добавь `ru_RU.UTF-8` если нужна кириллица.
|
|
|
|
Проверь:
|
|
|
|
```bash
|
|
locale
|
|
```
|
|
|
|
Должно быть `LANG=en_US.UTF-8`.
|
|
|
|
### DNS и systemd-resolved
|
|
|
|
Ubuntu 24.04 использует `systemd-resolved` - DNS резолвер работает на `127.0.0.53`. `/etc/resolv.conf` это симлинк.
|
|
|
|
Проверь:
|
|
|
|
```bash
|
|
resolvectl status
|
|
```
|
|
|
|
Посмотри на какой файл указывает симлинк:
|
|
|
|
```bash
|
|
ls -la /etc/resolv.conf
|
|
```
|
|
|
|
Это нормально - не трогай если резолвинг работает. Если настраиваешь статический DNS:
|
|
|
|
```bash
|
|
sudo nano /etc/systemd/resolved.conf
|
|
```
|
|
|
|
```ini
|
|
[Resolve]
|
|
DNS=8.8.8.8 8.8.4.4
|
|
FallbackDNS=1.1.1.1
|
|
```
|
|
|
|
```bash
|
|
sudo systemctl restart systemd-resolved
|
|
```
|
|
|
|
**Важно:** Docker контейнеры не могут использовать `127.0.0.53` - это адрес loopback недоступный из контейнера. Для Docker-хоста это решается отдельно в следующей статье серии.
|
|
|
|
## Пользователь и SSH
|
|
|
|
### Создание пользователя (если нет)
|
|
|
|
Если получил сервер без непривилегированного пользователя:
|
|
|
|
```bash
|
|
adduser admin
|
|
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@YOUR_IP
|
|
```
|
|
|
|
```powershell
|
|
# Windows
|
|
type $env:userprofile\.ssh\id_ed25519.pub | ssh admin@YOUR_IP "mkdir -m 700 -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
|
|
```
|
|
|
|
Проверь вход по ключу - не должен спрашивать пароль:
|
|
|
|
```bash
|
|
ssh admin@YOUR_IP
|
|
```
|
|
|
|
### SSH hardening
|
|
|
|
Ubuntu 24.04 хранит конфигурацию SSH в `/etc/ssh/sshd_config.d/` - основной файл не трогаем.
|
|
|
|
Создай файл с настройками:
|
|
|
|
```bash
|
|
sudo nano /etc/ssh/sshd_config.d/99-hardening.conf
|
|
```
|
|
|
|
```
|
|
# Нестандартный порт - отсекает большинство ботов
|
|
Port 2222
|
|
|
|
# Только ключи, без паролей
|
|
PubkeyAuthentication yes
|
|
AuthorizedKeysFile .ssh/authorized_keys
|
|
PasswordAuthentication no
|
|
PermitEmptyPasswords no
|
|
ChallengeResponseAuthentication no
|
|
KbdInteractiveAuthentication no
|
|
|
|
# Запретить root логин
|
|
PermitRootLogin no
|
|
|
|
# Ограничения сессий
|
|
MaxAuthTries 3
|
|
MaxSessions 3
|
|
LoginGraceTime 30
|
|
|
|
# Таймауты
|
|
ClientAliveInterval 300
|
|
ClientAliveCountMax 2
|
|
|
|
# Отключить лишнее
|
|
X11Forwarding no
|
|
PrintMotd no
|
|
AcceptEnv LANG LC_*
|
|
|
|
# Только IPv4 (убери если используешь IPv6)
|
|
AddressFamily inet
|
|
```
|
|
|
|
**Важно:** Ubuntu 24.04 использует socket-активацию через `ssh.socket` - порт слушает не sshd напрямую, а сокет-юнит. Обычный `systemctl restart ssh` перезапускает только сервис, порт остаётся прежним. Для применения нового порта нужно перезапускать именно сокет.
|
|
|
|
**КРИТИЧНО:** Перед перезапуском открой вторую сессию и не закрывай её.
|
|
|
|
Проверь конфиг на ошибки:
|
|
|
|
```bash
|
|
sudo sshd -t
|
|
```
|
|
|
|
Нет вывода - нет ошибок. Примени:
|
|
|
|
```bash
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl restart ssh.socket
|
|
```
|
|
|
|
Проверь что сервис поднялся на новом порту:
|
|
|
|
```bash
|
|
sudo ss -tlnp | grep sshd
|
|
```
|
|
|
|
Ожидаемый вывод:
|
|
```
|
|
LISTEN 0 4096 0.0.0.0:2222
|
|
```
|
|
|
|
Убедись что конфиг сокета подхватил изменение:
|
|
|
|
```bash
|
|
sudo systemctl cat ssh.socket
|
|
```
|
|
|
|
Строка `ListenStream=0.0.0.0:2222` подтверждает что порт применился.
|
|
|
|
В новом терминале проверь подключение:
|
|
|
|
```bash
|
|
ssh -p 2222 admin@YOUR_IP
|
|
```
|
|
|
|
Если работает - старые сессии можно закрывать.
|
|
|
|
|
|
### SSH banner (опционально)
|
|
|
|
```bash
|
|
sudo nano /etc/ssh/banner
|
|
```
|
|
|
|
```
|
|
###############################################################################
|
|
# Доступ только для авторизованных пользователей. #
|
|
# Все действия логируются. #
|
|
# Несанкционированный доступ преследуется по понятиям! #
|
|
###############################################################################
|
|
```
|
|
|
|
Добавь в `/etc/ssh/sshd_config.d/99-hardening.conf`:
|
|
|
|
```
|
|
Banner /etc/ssh/banner
|
|
```
|
|
|
|
Перезапусти:
|
|
|
|
```bash
|
|
sudo systemctl restart ssh
|
|
```
|
|
|
|
## Firewall (UFW)
|
|
|
|
UFW в Ubuntu предустановлен, но **по умолчанию выключен**.
|
|
|
|
Проверь статус:
|
|
|
|
```bash
|
|
sudo ufw status
|
|
```
|
|
|
|
Скорее всего увидишь `Status: inactive`.
|
|
|
|
### Настройка правил
|
|
|
|
**Важно:** сначала правила, потом включение. Иначе заблокируешь себя.
|
|
|
|
```bash
|
|
# Блокировать все входящие
|
|
sudo ufw default deny incoming
|
|
|
|
# Разрешить все исходящие
|
|
sudo ufw default allow outgoing
|
|
```
|
|
|
|
Разрешаем SSH на новом порту:
|
|
|
|
```bash
|
|
# Замени 2222 на свой порт
|
|
sudo ufw allow 2222/tcp comment 'SSH'
|
|
```
|
|
|
|
Rate limiting на SSH:
|
|
|
|
```bash
|
|
sudo ufw limit 2222/tcp comment 'SSH rate limit'
|
|
```
|
|
|
|
Включаем:
|
|
|
|
```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 LIMIT IN Anywhere # SSH rate limit
|
|
2222/tcp (v6) LIMIT IN Anywhere (v6) # 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
|
|
```
|
|
|
|
## Fail2ban
|
|
|
|
```bash
|
|
sudo apt install -y fail2ban
|
|
```
|
|
|
|
Создай локальный конфиг:
|
|
|
|
```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
|
|
|
|
[sshd]
|
|
enabled = true
|
|
port = 2222
|
|
filter = sshd
|
|
logpath = /var/log/auth.log
|
|
maxretry = 3
|
|
bantime = 3600
|
|
```
|
|
|
|
Замени `2222` на свой SSH порт.
|
|
|
|
**Особенность Ubuntu 24.04:** `systemd-journald` по умолчанию не пишет в `/var/log/auth.log`. Если файл отсутствует или пустой:
|
|
|
|
```bash
|
|
ls -la /var/log/auth.log
|
|
```
|
|
|
|
Включи запись в файл:
|
|
|
|
```bash
|
|
sudo nano /etc/rsyslog.d/50-default.conf
|
|
```
|
|
|
|
Убедись что строка не закомментирована:
|
|
|
|
```
|
|
auth,authpriv.* /var/log/auth.log
|
|
```
|
|
|
|
Перезапусти rsyslog:
|
|
|
|
```bash
|
|
sudo systemctl restart rsyslog
|
|
```
|
|
|
|
Или используй journald backend в fail2ban - он умеет читать логи напрямую из journald без файлов:
|
|
|
|
```bash
|
|
sudo nano /etc/fail2ban/jail.local
|
|
```
|
|
|
|
Добавь в секцию `[sshd]`:
|
|
|
|
```ini
|
|
[sshd]
|
|
enabled = true
|
|
port = 2222
|
|
filter = sshd
|
|
backend = systemd
|
|
maxretry = 3
|
|
bantime = 3600
|
|
```
|
|
|
|
При `backend = systemd` параметр `logpath` не нужен - fail2ban читает journald напрямую.
|
|
|
|
Запусти:
|
|
|
|
```bash
|
|
sudo systemctl enable fail2ban
|
|
sudo systemctl start fail2ban
|
|
```
|
|
|
|
Проверь статус:
|
|
|
|
```bash
|
|
sudo fail2ban-client status
|
|
sudo fail2ban-client status sshd
|
|
```
|
|
|
|
## Swap
|
|
|
|
Swap в виде файла - гибче раздела: можно увеличить или уменьшить без переразбивки диска.
|
|
|
|
### Создание swap файла
|
|
|
|
Проверь текущий swap:
|
|
|
|
```bash
|
|
free -h
|
|
swapon --show
|
|
```
|
|
|
|
Ожидаемый вывод если swap отсутствует:
|
|
```
|
|
Swap: 0B 0B 0B
|
|
```
|
|
|
|
Создай файл (пример - 2GB):
|
|
|
|
```bash
|
|
sudo fallocate -l 2G /swapfile
|
|
```
|
|
|
|
Если `fallocate` не поддерживается файловой системой (например btrfs):
|
|
|
|
```bash
|
|
sudo dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progress
|
|
```
|
|
|
|
Установи права:
|
|
|
|
```bash
|
|
sudo chmod 600 /swapfile
|
|
```
|
|
|
|
Инициализируй и активируй:
|
|
|
|
```bash
|
|
sudo mkswap /swapfile
|
|
sudo swapon /swapfile
|
|
```
|
|
|
|
Проверь:
|
|
|
|
```bash
|
|
free -h
|
|
swapon --show
|
|
```
|
|
|
|
Ожидаемый вывод:
|
|
```
|
|
total used free shared buff/cache available
|
|
Mem: 1.9Gi 860Mi 240Mi 2.5Mi 1.0Gi 1.1Gi
|
|
Swap: 2.0Gi 0B 2.0Gi
|
|
|
|
NAME TYPE SIZE USED PRIO
|
|
/swapfile file 2G 0B -2
|
|
```
|
|
|
|
Добавь в `/etc/fstab` для автомонтирования после перезагрузки:
|
|
|
|
```bash
|
|
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
|
|
```
|
|
|
|
### Настройка swappiness
|
|
|
|
`swappiness` определяет агрессивность использования swap. Для production - снижаем:
|
|
|
|
```bash
|
|
cat /proc/sys/vm/swappiness
|
|
# по умолчанию 60
|
|
```
|
|
|
|
Установи постоянно:
|
|
|
|
```bash
|
|
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.d/99-swap.conf
|
|
sudo sysctl -p /etc/sysctl.d/99-swap.conf
|
|
```
|
|
|
|
Значение `10` - swap используется только когда RAM заполнена на 90%+.
|
|
|
|
### Изменение размера swap
|
|
|
|
Нельзя перезаписать активный swap файл - ядро блокирует его пока он используется:
|
|
|
|
```
|
|
$ sudo fallocate -l 4G /swapfile
|
|
fallocate: fallocate failed: Text file busy
|
|
|
|
$ sudo dd if=/dev/zero of=/swapfile bs=1M count=4096 status=progress
|
|
dd: failed to open '/swapfile': Text file busy
|
|
```
|
|
|
|
Сначала отключи swap, затем меняй размер:
|
|
|
|
```bash
|
|
sudo swapoff /swapfile
|
|
```
|
|
|
|
```bash
|
|
sudo fallocate -l 4G /swapfile
|
|
```
|
|
|
|
```bash
|
|
sudo mkswap /swapfile
|
|
```
|
|
|
|
```bash
|
|
sudo swapon /swapfile
|
|
```
|
|
|
|
Проверь результат:
|
|
|
|
```bash
|
|
free -h
|
|
```
|
|
|
|
Ожидаемый вывод:
|
|
```
|
|
total used free shared buff/cache available
|
|
Mem: 1.9Gi 872Mi 227Mi 2.5Mi 1.0Gi 1.1Gi
|
|
Swap: 4.0Gi 0B 4.0Gi
|
|
```
|
|
|
|
Запись в `/etc/fstab` менять не нужно - путь тот же.
|
|
|
|
### Удаление swap
|
|
|
|
```bash
|
|
sudo swapoff /swapfile
|
|
```
|
|
|
|
```bash
|
|
sudo rm /swapfile
|
|
```
|
|
|
|
Удали строку из `/etc/fstab`:
|
|
|
|
```bash
|
|
sudo nano /etc/fstab
|
|
# удали строку: /swapfile none swap sw 0 0
|
|
```
|
|
|
|
## Sysctl - защита ядра
|
|
|
|
```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
|
|
```
|
|
|
|
## Автообновления безопасности
|
|
|
|
Ubuntu 24.04 устанавливает `unattended-upgrades` автоматически. Проверь:
|
|
|
|
```bash
|
|
sudo systemctl status unattended-upgrades
|
|
```
|
|
|
|
Если не установлен:
|
|
|
|
```bash
|
|
sudo apt install -y unattended-upgrades apt-listchanges
|
|
sudo dpkg-reconfigure -plow unattended-upgrades
|
|
```
|
|
|
|
Настрой конфиг:
|
|
|
|
```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"` - перезагрузку после обновления ядра делаешь вручную в удобное время.
|
|
|
|
Расписание:
|
|
|
|
```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
|
|
systemctl list-units --type=service --state=running
|
|
```
|
|
|
|
Ubuntu 24.04 по умолчанию запускает больше сервисов чем Debian. Кандидаты на отключение:
|
|
|
|
```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
|
|
|
|
# snapd - если не используешь snap пакеты
|
|
# ОСТОРОЖНО: некоторые облачные образы зависят от snap
|
|
sudo systemctl disable --now snapd.service snapd.socket
|
|
```
|
|
|
|
**По поводу snapd:** если сервер облачный и ты не знаешь точно что использует snap - не отключай. Проверь сначала:
|
|
|
|
```bash
|
|
snap list
|
|
```
|
|
|
|
Если кроме `core` и `snapd` ничего нет - можно отключать.
|
|
|
|
Проверь открытые порты:
|
|
|
|
```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
|
|
```
|
|
|
|
### Ротация rsyslog
|
|
|
|
```bash
|
|
sudo nano /etc/logrotate.d/rsyslog
|
|
```
|
|
|
|
```
|
|
/var/log/syslog
|
|
/var/log/mail.log
|
|
/var/log/kern.log
|
|
/var/log/auth.log
|
|
/var/log/user.log
|
|
/var/log/cron.log
|
|
{
|
|
su root syslog
|
|
rotate 7
|
|
daily
|
|
missingok
|
|
notifempty
|
|
compress
|
|
delaycompress
|
|
sharedscripts
|
|
postrotate
|
|
/usr/lib/rsyslog/rsyslog-rotate
|
|
endscript
|
|
}
|
|
```
|
|
|
|
Директива `su root syslog` обязательна - без неё logrotate отказывается ротировать файлы в `/var/log`, потому что директория доступна на запись группе `syslog`, что считается небезопасным.
|
|
|
|
Проверь конфиг dry run:
|
|
|
|
```bash
|
|
sudo logrotate -d /etc/logrotate.d/rsyslog
|
|
```
|
|
|
|
Ожидаемый вывод:
|
|
|
|
```
|
|
...
|
|
rotating pattern: /var/log/syslog
|
|
/var/log/mail.log
|
|
/var/log/kern.log
|
|
/var/log/auth.log
|
|
/var/log/user.log
|
|
/var/log/cron.log
|
|
after 1 days (7 rotations)
|
|
empty log files are not rotated, old logs are removed
|
|
switching euid from 0 to 0 and egid from 0 to 104 (pid 76669)
|
|
...
|
|
```
|
|
|
|
## Мониторинг диска
|
|
|
|
### Определение имени диска
|
|
|
|
Имя диска зависит от окружения - не хардкодь `/dev/sda`:
|
|
|
|
```bash
|
|
lsblk
|
|
```
|
|
|
|
Ожидаемый вывод (ориентировочный) на физическом сервере:
|
|
```
|
|
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
|
|
sda 8:0 0 500G 0 disk
|
|
├─sda1 8:1 0 1G 0 part /boot
|
|
└─sda2 8:2 0 499G 0 part /
|
|
```
|
|
|
|
Ожидаемый вывод на виртуальной машине (KVM/Proxmox):
|
|
```
|
|
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
|
|
vda 253:0 0 30G 0 disk
|
|
├─vda1 253:1 0 1M 0 part
|
|
└─vda2 253:2 0 30G 0 part /
|
|
```
|
|
|
|
`vda` - virtio-диск на гипервизоре. `sda` - физический диск или SCSI-эмуляция.
|
|
|
|
### Физический сервер - SMART
|
|
|
|
На физическом сервере SMART даёт ранние признаки деградации диска:
|
|
|
|
```bash
|
|
sudo smartctl -H /dev/sda
|
|
```
|
|
|
|
Ожидаемый вывод:
|
|
```
|
|
SMART overall-health self-assessment test result: PASSED
|
|
```
|
|
|
|
Детали:
|
|
|
|
```bash
|
|
sudo smartctl -a /dev/sda
|
|
```
|
|
|
|
Обращай внимание на три атрибута - если ненулевые, диск проблемный:
|
|
- `Reallocated_Sector_Ct` - переназначенные секторы
|
|
- `Pending_Sector_Count` - ожидающие переназначения
|
|
- `Offline_Uncorrectable` - неисправимые ошибки
|
|
|
|
### Виртуальная машина - SMART недоступен
|
|
|
|
На VM `smartctl` не работает - гипервизор не пробрасывает SMART данные гостю:
|
|
|
|
```
|
|
/dev/vda: Unable to detect device type
|
|
Please specify device type with the -d option.
|
|
```
|
|
|
|
Это нормально. SMART мониторинг на виртуальных дисках делается на уровне гипервизора - в Proxmox через Datacenter → Node → Disks. Внутри VM контролируй заполнение и I/O:
|
|
|
|
```bash
|
|
df -h
|
|
```
|
|
|
|
```bash
|
|
iostat -x 1 3
|
|
```
|
|
|
|
`iostat` входит в пакет `sysstat`:
|
|
|
|
```bash
|
|
sudo apt install -y sysstat
|
|
```
|
|
|
|
Обращай внимание на `%util` в выводе `iostat` - значения близкие к 100% означают что диск перегружен.
|
|
|
|
## Бэкап конфигов
|
|
|
|
Скрипт архивирует `/etc/`, SSH ключи и список установленных пакетов.
|
|
|
|
```bash
|
|
sudo nano /root/backup-configs.sh
|
|
```
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
|
|
BACKUP_DIR="/root/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 > /root/installed-packages.txt
|
|
|
|
tar -czf "$BACKUP_FILE" \
|
|
/etc/ \
|
|
/root/.ssh/ \
|
|
/home/*/.ssh/ \
|
|
/root/installed-packages.txt \
|
|
2>/dev/null
|
|
|
|
find "$BACKUP_DIR" -name "config_backup_*.tar.gz" -mtime +30 -delete
|
|
|
|
echo "Backup: $BACKUP_FILE"
|
|
ls -lh "$BACKUP_FILE"
|
|
```
|
|
|
|
Установи права и запусти первый раз:
|
|
|
|
```bash
|
|
sudo chmod +x /root/backup-configs.sh
|
|
sudo /root/backup-configs.sh
|
|
```
|
|
Ожидаемый вывод:
|
|
```bash
|
|
Backup: /root/backups/config_backup_20260707_145620.tar.gz
|
|
-rw-r--r-- 1 root root 660K Jul 7 14:56 /root/backups/config_backup_ДАТА.tar.gz
|
|
```
|
|
|
|
Автоматизация через cron (каждое воскресенье в 3:00):
|
|
|
|
```bash
|
|
sudo crontab -e
|
|
```
|
|
|
|
```
|
|
0 3 * * 0 /root/backup-configs.sh >> /var/log/backup-configs.log 2>&1
|
|
```
|
|
|
|
**Важно:** архив лежит на том же диске что и система. Это защита от случайных изменений конфигов, не от отказа диска. Копируй архивы на внешний сервер или S3-совместимое хранилище.
|
|
|
|
### Восстановление конфигов
|
|
|
|
Восстановить `/etc/` и SSH ключи из архива:
|
|
|
|
```bash
|
|
sudo tar -xzf /root/backups/config_backup_ДАТА.tar.gz -C /
|
|
```
|
|
|
|
Восстановить список пакетов:
|
|
|
|
```bash
|
|
sudo dpkg --set-selections < /root/installed-packages.txt
|
|
```
|
|
|
|
```bash
|
|
sudo apt-get dselect-upgrade
|
|
```
|
|
|
|
### Финальная проверка
|
|
```bash
|
|
# Открытые порты
|
|
ss -tulnp
|
|
|
|
# Статус firewall
|
|
sudo ufw status verbose
|
|
|
|
# Статус fail2ban
|
|
sudo fail2ban-client status sshd
|
|
|
|
# Состояние диска
|
|
sudo smartctl -H /dev/sda
|
|
|
|
# Swap
|
|
free -h
|
|
```
|
|
|
|
## Что дальше
|
|
|
|
Сервер готов к установке приложений.
|
|
|
|
- Docker хост - следующая статья серии
|
|
- Nginx/Traefik - reverse proxy поверх этой базы
|
|
- PostgreSQL/MySQL - базы данных
|
|
- Postfix/Dovecot - почтовый сервер
|
|
|
|
**Стек этой статьи:** Ubuntu 24.04 LTS (Noble Numbat) · UFW · Fail2ban · OpenSSH · unattended-upgrades · systemd · systemd-resolved · smartmontools
|
|
|
|
## Послесловие: пока мы настраивали - они уже ломились
|
|
|
|
Пока эта статья писалась и проверялась на реальном сервере, снаружи шла своя работа. Проверяем:
|
|
|
|
```bash
|
|
sudo fail2ban-client status sshd
|
|
```
|
|
|
|
```
|
|
Status for the jail: sshd
|
|
|- Filter
|
|
| |- Currently failed: 4
|
|
| |- Total failed: 22863
|
|
| `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd
|
|
`- Actions
|
|
|- Currently banned: 3
|
|
|- Total banned: 18
|
|
`- Banned IP list: 167.99.72.161 104.236.83.40 47.77.182.54
|
|
```
|
|
|
|
22 863 неудачных попытки. 18 забаненных IP. 3 в бане прямо сейчас.
|
|
|
|
Сколько времени сервер вообще стоит в интернете:
|
|
|
|
```bash
|
|
uptime -p
|
|
```
|
|
|
|
```
|
|
up 4 days, 3 hours, 21 minutes
|
|
```
|
|
|
|
4 дня. ~235 попыток в час, почти 4 в минуту - непрерывно, круглосуточно.
|
|
|
|
Посмотрим на что они надеялись:
|
|
|
|
```bash
|
|
sudo grep "Invalid user" /var/log/auth.log | grep -oP "Invalid user \K\S+" | sort | uniq -c | sort -rn | head -10
|
|
```
|
|
|
|
```
|
|
124 ubuntu
|
|
101 user
|
|
91 test
|
|
75 debian
|
|
59 ftpuser
|
|
55 postgres
|
|
50 oracle
|
|
34 git
|
|
34 deploy
|
|
25 deployer
|
|
```
|
|
|
|
`ubuntu` - 124 попытки, классика для облачных серверов. `debian` - 75, логично для нашего дистрибутива. `ftpuser` - 59, кто-то ищет забытый FTP из 2005 года. `postgres`, `oracle` - надеялись что база данных торчит наружу с дефолтным пользователем. `git`, `deploy`, `deployer` - охота на CI/CD пайплайны с предсказуемыми именами.
|
|
|
|
Все эти попытки получили одинаковый ответ: порт 22 закрыт, нестандартный порт принимает только ключи, после трёх ошибок - бан на час.
|
|
|
|
Это не повод расслабиться. Это повод убедиться что всё настроено именно так, как описано выше - потому что 22 863 попытки за 4 дня на одном небольшом сервере это не целевая атака, это обычный фоновый шум интернета. Целевая атака выглядит иначе.
|