Настройка Ubuntu VPS для production — 8 шагов
Как подготовить Ubuntu-сервер к production: firewall, SSH, Docker, Nginx, SSL, бэкапы. Реальный опыт настройки VPS.
Подготовка VPS к production — это настройка firewall, SSH-доступа, Docker, Nginx, SSL и резервного копирования до того, как на сервере окажется код приложения. Без этих шагов сервер уязвим к атакам, потере данных и простоям.
Эта статья написана по следам реальной настройки VPS под fullstack-приложение (NestJS + React + PostgreSQL + Redis). Каждая команда проверена на Ubuntu 22.04. Если VPS ещё не арендован — в сравнении облачных провайдеров России 2026 разобраны Timeweb, SpaceWeb и Selectel с ценами и рекомендациями. Если хотите проходить настройку с отслеживанием прогресса — есть интерактивный чеклист, где можно отмечать выполненные пункты.
Требования к серверу
Минимальная конфигурация, на которой fullstack-стек работает без тормозов:
| Параметр | Значение |
|---|---|
| OS | Ubuntu 22.04 LTS |
| RAM | 4 GB (NestJS + React + PostgreSQL + Redis одновременно) |
| CPU | 2 cores |
| Disk | 50 GB SSD |
| Network | Статический IP |
Ubuntu 22.04 LTS — 5 лет поддержки, обновления безопасности до 2027, наибольшее количество документации и совместимых пакетов среди серверных дистрибутивов.
Первый вход и обновление системы
Первое подключение идёт от root — единственный пользователь, который существует на свежем VPS:
ssh root@YOUR_SERVER_IP
apt update && apt upgrade -y
apt install -y curl wget git vim htop ufw
htop и ufw понадобятся на следующих шагах. Остальное — базовый набор для работы с сервером.
Настройка Firewall (UFW)
UFW (Uncomplicated Firewall) — интерфейс к iptables, встроенный в Ubuntu. Правила нужно добавить до включения firewall, иначе текущее SSH-соединение оборвётся.
sudo ufw default deny incoming
sudo ufw default allow outgoing
# SSH — добавить первым, до включения UFW
sudo ufw allow 22/tcp comment 'SSH'
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
sudo ufw show added
sudo ufw enable
sudo ufw status numbered
Три правила, которые ломают продакшн чаще всего:
- Не закрывать текущую SSH-сессию до проверки нового подключения в отдельном терминале
- Не открывать порты 5432 (PostgreSQL) и 6379 (Redis) наружу — Docker-контейнеры общаются через внутреннюю сеть, внешний доступ к базам не нужен
- Не открывать порт pgAdmin (8082) — для удалённого доступа достаточно SSH-туннеля:
ssh -L 8082:localhost:8082 user@server
Безопасный доступ по SSH
Минимум, который нужен прямо сейчас: отдельный пользователь вместо root и вход по ключу вместо пароля.
# Создать пользователя с sudo
adduser deployer
usermod -aG sudo deployer
# Скопировать SSH-ключ с локальной машины
ssh-copy-id deployer@YOUR_SERVER_IP
После проверки входа по ключу в отдельном терминале — отключить пароль и root-доступ:
sudo sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sshd -t && sudo systemctl restart sshd
Это базовый уровень. Генерация ключей ed25519, ~/.ssh/config для нескольких серверов, agent forwarding, fail2ban и смена стандартного порта — в отдельном гайде по SSH-ключам.
Установка Docker
Docker используется для контейнеризации приложения и баз данных. Установка по официальной инструкции Docker для Ubuntu:
# Удалить конфликтующие пакеты
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do
sudo apt-get remove $pkg 2>/dev/null
done
# Зависимости и GPG-ключ
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Репозиторий
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] 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
# Текущий пользователь — в группу docker
sudo usermod -aG docker $USER
После добавления в группу docker нужно перелогиниться (выйти из SSH и зайти заново) — newgrp docker создаёт дочерний shell, и некоторые переменные окружения в нём могут отличаться.
Проверка:
docker --version
docker compose version
Nginx как reverse proxy
Nginx принимает внешние запросы и проксирует их в Docker-контейнеры — frontend, backend, WebSocket. Установка:
sudo apt install -y nginx
sudo systemctl status nginx
Конфиг-файлы создаются в /etc/nginx/sites-available/ с симлинком в /etc/nginx/sites-enabled/. Перед каждым systemctl reload nginx — обязательно sudo nginx -t:
sudo nginx -t && sudo systemctl reload nginx
Если nginx -t возвращает ошибку — reload не пройдёт, и рабочий конфиг не пострадает. Привычка проверять перед перезагрузкой спасает от даунтайма.
SSL-сертификаты через Let's Encrypt
Let's Encrypt выдаёт бесплатные сертификаты сроком на 90 дней. Certbot автоматизирует и получение, и обновление. Перед запуском certbot DNS-записи уже должны указывать на IP сервера — Let's Encrypt проверяет это при выдаче.
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Certbot сам вносит изменения в Nginx-конфиг, добавляя SSL-блок. Таймер автообновления активен по умолчанию:
sudo systemctl status certbot.timer
sudo certbot renew --dry-run
Если dry-run отработал без ошибок — сертификаты обновятся автоматически за 30 дней до истечения срока.
Мониторинг и логирование
Минимальный набор, без которого невозможно диагностировать проблемы на продакшне:
# Системные ресурсы в реальном времени
htop
# Логи Nginx — ошибки проксирования, 502/504
sudo tail -f /var/log/nginx/error.log
# Логи конкретного Docker-контейнера
docker logs -f --tail 100 container_name
# Системный журнал по сервису
sudo journalctl -u nginx -f --no-pager
docker logs -f --tail 100 показывает последние 100 строк и продолжает поток — без --tail в тяжёлых контейнерах лог может выдать сотни мегабайт в stdout.
Резервное копирование PostgreSQL
pg_dump через Docker — самый простой способ делать ежедневные бэкапы. Скрипт сохраняет дамп в gzip и удаляет файлы старше 7 дней:
sudo vim /usr/local/bin/backup-db.sh
#!/bin/bash
set -euo pipefail
BACKUP_DIR="/backups/postgres"
DATE=$(date +%Y%m%d_%H%M%S)
CONTAINER="your_postgres_container"
DB_USER="your_user"
DB_NAME="your_db"
mkdir -p "$BACKUP_DIR"
docker exec "$CONTAINER" pg_dump -U "$DB_USER" "$DB_NAME" \
| gzip > "$BACKUP_DIR/backup_${DATE}.sql.gz"
find "$BACKUP_DIR" -name "backup_*.sql.gz" -mtime +7 -delete
sudo chmod +x /usr/local/bin/backup-db.sh
# Добавить в cron
sudo crontab -e
Строка для ежедневного бэкапа в 03:00:
0 3 * * * /usr/local/bin/backup-db.sh >> /var/log/backup-db.log 2>&1
Перенаправление в лог-файл позволяет отследить, если бэкап тихо перестал работать. set -euo pipefail в скрипте гарантирует, что ошибка на любом этапе (контейнер не найден, нет места на диске) не проглотится молча.
FAQ
Какой VPS выбрать для production?
Для стека Node.js + PostgreSQL + Redis хватает 4 GB RAM и 2 vCPU. В России хорошо работают Timeweb Cloud, Selectel, SpaceWeb — подробное сравнение цен и возможностей в обзоре облачных провайдеров. Из зарубежных — Hetzner (цена/производительность) и DigitalOcean (документация).
Можно обойтись без Nginx и проксировать напрямую?
Технически — да, Node.js умеет слушать 80/443. Практически — нет. Nginx обрабатывает SSL-терминацию, статику, rate limiting и gzip-сжатие эффективнее Node.js. При 1000+ одновременных соединений разница в потреблении памяти — в 5–8 раз.
Зачем UFW, если в Docker уже есть iptables?
Docker добавляет свои правила iptables напрямую, минуя UFW. Это значит, что docker run -p 5432:5432 откроет порт наружу, даже если UFW его блокирует. Решение — не публиковать порты баз данных: вместо -p 5432:5432 использовать Docker-сети, чтобы контейнеры общались между собой.
Как проверить, работают ли бэкапы?
Раз в месяц разворачивать дамп на тестовом окружении: gunzip < backup.sql.gz | docker exec -i postgres psql -U user dbname. Бэкап, который ни разу не восстанавливали — это не бэкап.
Полезные ссылки
- DigitalOcean: Initial Server Setup with Ubuntu 22.04
- Docker: Install on Ubuntu
- Certbot: Getting Started
- Nginx Documentation
- SSH-ключи на Ubuntu — генерация, настройка, безопасность — ssh-keygen, config, agent, fail2ban
- Сравнение облачных провайдеров России 2026 — Timeweb vs SpaceWeb vs Selectel с ценами
- Интерактивный чеклист: подготовка сервера к production — те же шаги с отслеживанием прогресса