Это гайд-памятка по базовой настройке VPS. Гайд написан под Ubuntu 24.04 LTS на DigitalOcean. На других дистрибутивах базовая логика та же, отличаться будут только команды и расположение конфигов. Все разделы опциональные и собирались под мои задачи.
Содержание:
- Настройка non-root юзера и привязка ssh-ключа
- Запрет root-логина и паролей по SSH
- Файрвол UFW
- fail2ban от брутфорса
- Автообновления безопасности
- Базовые утилиты
- Часовой пояс и hostname
- Выделение swap
- Git, Docker + Docker Compose
- DigitalOcean Metrics Agent
- Resource Alerts в DO
- SSH-конфиг на локальной машине
- Бэкапы DO
- Лимит логов journald
В конце чеклист настроек.
Главное
- Минимальные привилегии - каждый сервис и каждый юзер должны иметь минимум прав. Не запускаем ничего от root. Не открываем порты, которые не нужны. Не даем sudo юзеру, которому хватит непривилегированного шелла.
- Минимизация поверхности атаки. Базовое правило: deny по дефолту, разрешать точечно. VPS должен снаружи отвечать только на 22, 80 и 443 и не выходить за
127.0.0.1, либо проксироваться.
Этап 1. Настройка non-root юзера и привязка ssh-ключа
На VPS создаём отдельного пользователя <username> для повседневной работы:
adduser username
usermod -aG sudo username # даем права sudo
mkdir -p /home/username/.ssh
cp ~/.ssh/authorized_keys /home/username/.ssh/
chown -R username:username /home/username/.ssh
chmod 700 /home/username/.ssh
chmod 600 /home/username/.ssh/authorized_keys
- Переносим публичный ключ в
~/.sshнового юзера, чтобы можно заходить по ключу под ним. - Ставим владельцем файлов нового юзера.
- Права на 700 (чтение+запись+выполнение для владельца, остальным ничего)
~/.sshи 600 (чтение+запись для владельца, остальным ничего) наauthorized_keys- требование sshd.
Этап 2. Запрет root-логина и паролей по SSH
Отключаем небезопасные способы входа в ssh конфиге: sudo nano /etc/ssh/sshd_config.
PermitRootLogin no # не пускать под root
PasswordAuthentication no # не пускать под паролем
PubkeyAuthentication yes # пускать под ключом
Применить:
sudo systemctl reload ssh
Перед тем, как закрыть сессию под рутом, проверяем коннект с локальной машины (в новом терминале, не закрывая текущий рут-сеанс): ssh username@<IP_VPS>.
Этап 3. Файрвол UFW
UFW (Uncomplicated Firewall) - это обёртка над iptables. Закрываем всё входящее, оставляем 22, 80, 443:
sudo ufw default deny incoming # дефолт - блокировать входящий трафик
sudo ufw default allow outgoing # дефолт - разрешить исходящий трафик
# открываем порты на ssh
sudo ufw allow 22/tcp
# открываем порты на http(s), если нужно сервисам
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# включаем файрвол
sudo ufw enable
# посмотреть текущее состояние
sudo ufw status verbose
Вывод последней команды будет примерно таким:
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN Anywhere (v6)
80/tcp (v6) ALLOW IN Anywhere (v6)
443/tcp (v6) ALLOW IN Anywhere (v6)
Если в будущем планируется ставить какие-то сервисы, то они должны работать на 127.0.0.1 и проксироваться через реверс-прокси (например, Caddy) на 80/443. Не открываем новые порты наружу без причины.
Этап 4. fail2ban от брутфорса
fail2ban защищает от ботов, которые будут стучаться на открытые порты. Он читает логи, находит неудачные попытки логина и временно банит IP.
sudo apt install -y fail2ban
sudo nano /etc/fail2ban/jail.local
- В fail2ban jail - это блок правил для конкретных служб. Настроим правила для ssh. В
jail.localпишем только переопределения — пакет сам подмёрджит их поверх дефолтов изjail.conf(копироватьjail.confцеликом нельзя, иначе при апдейте пакета мы пропустим новые дефолты).
[sshd]
enabled = true # включает jail
maxretry = 3 # лимит попыток коннекта
bantime = 3600 # бан на 1 час
findtime = 600 # окно, в течение которого происходит maxretry. 10 минутsudo systemctl enable --now fail2ban
sudo fail2ban-client status sshdЭтап 5. Автообновления безопасности
unattended-upgrades - механизм автоматических апдейтов Ubuntu/Debian.
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
“Automatically download and install stable updates?” -> yes.
--priority=lowнужен, чтобы мы получили диалоговое окно с подтверждением автоапдейтов.
Проверяем, в /etc/apt/apt.conf.d/20auto-upgrades должно быть:
# Раз в день обновляем список пакетов
APT::Periodic::Update-Package-Lists "1";
# Раз в день запускаем установку обновлений
APT::Periodic::Unattended-Upgrade "1";
Перезагрузку после обновлений ядра оставим ручной, это ок. Раз в месяц можно делать ребут: sudo reboot.
Этап 6. Базовые утилиты
sudo apt install -y curl wget htop ncdu tmux tree
htop - мониторинг процессов, ncdu - найти кто ест диск, tmux - детачаемые сессии, tree - визуализация папок.
Этап 7. Часовой пояс и hostname
Часовой пояс необходимо настроить, чтобы логи писались и cron-таски работали по твоему времени, а не по UTC.
Имя хоста просто для удобства.
sudo timedatectl set-timezone <таймзона>
sudo hostnamectl set-hostname <хостнейм>Этап 8. Выделение swap
При нехватке памяти в Linux процесс убивается OOM-killer’ом, поэтому выделяем своп (обычно x2 от RAM).
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -hЭтап 9. Git, Docker + Docker Compose
sudo apt install -y git
Дока Docker Engine: https://docs.docker.com/engine/install/ubuntu/
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
После добавления в группу docker нужно перелогиниться, чтобы изменения применились. Проверка:
docker run hello-worldЭтап 10. DigitalOcean Metrics Agent
Этапы 10-11 про базовую настройку метрик средствами DO. Помимо этого у меня работает Prometheus + Grafana / Alerts, об этом будет в отдельном гайде.
Дока DO Metrics Agent: https://docs.digitalocean.com/products/monitoring/how-to/install-metrics-agent/
Без do-agent DO видит только базовые внешние метрики. С ним работают расширенные графики, алерты по памяти/диску/CPU.
curl -sSL https://repos.insights.digitalocean.com/install.sh -o /tmp/install.sh
less /tmp/install.sh # просмотреть, что делает
sudo bash /tmp/install.sh # запустить
systemctl status do-agent # проверить
Агент работает под отдельным пользователем do-agent.
Этап 11. Resource Alerts в DO
После установки do-agent создаем в Monitoring -> Create Alert Policy:
-
Disk Utilization > 80% / 5 min
-
Memory Utilization > 90% / 5 min
-
CPU Utilization > 95% / 10 min
-
Public Outbound Bandwidth > 100 Mbps / 10 min — защита от взлома и спам-рассылок
-
Account → Billing Alert > $20 — страховка от неожиданных расходов
-
Алерты со временем (например, через неделю) стоит подтюнить в зависимости от нагрузки.
Этап 12. SSH-конфиг на локальной машине
На локальной машине добавить в ~/.ssh/config:
Host vps
HostName <IP VPS>
User <username>
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 60
ServerAliveCountMax 3
- vps - алиас для подключения, произвольный.
ServerAliveIntervalшлёт keepalive, чтобы соединение не отваливалось при долгом простое.
Теперь вместо ssh username@IP_VPS — просто ssh vps.
Этап 13. Бэкапы DO
Бэкап средствами DigitalOcean: Droplets -> дроплет -> Backups & Snapshots -> Setup Automated Backups -> Weekly Backups.
Стоит 20% стоимости дроплета.
Этап 14. Лимит логов journald
Ограничим journald место под логи. В /etc/systemd/journald.conf:
SystemMaxUse=500Msudo systemctl restart systemd-journald
sudo journalctl --vacuum-size=500M # подрезать накопленные логи разово
Чеклист
Безопасность
- Создан non-root пользователь с sudo
- SSH-ключ скопирован non-root юзеру, проверен вход
-
PermitRootLogin noиPasswordAuthentication noвsshd_config - UFW активен, открыты только 22/80/443
- fail2ban установлен и активен
- unattended-upgrades включены
Базовая система
-
apt upgradeвыполнен - Часовой пояс и hostname заданы
- Swap создан
- Установлены: curl, wget, htop, ncdu, tmux, tree
- journald ограничен 500M
Инфраструктура
- Git, Docker + Docker compose установлены
- Текущий пользователь в группе docker
- do-agent установлен и работает
- DO Backups включены
- Resource Alerts настроены
- Billing Alert настроен
На локальной машине
-
~/.ssh/configс алиасом -
Алиас работает (
ssh vpsпускает)