Docker на VPS: с чего начать
Docker позволяет запустить на сервере бота, сайт, базу данных и мониторинг так, что они не мешают друг другу, а переезд на другой VPS сводится к копированию пары файлов и данных. Установка занимает пять минут, а основные неприятности начинаются позже: открытые наружу порты базы, журналы на десятки гигабайт и данные, которые пропали вместе с контейнером. Разбираем, как избежать их с самого начала.
Контейнер — это приложение вместе со всеми библиотеками и настройками, упакованное в образ. На сервере он запускается одной командой и работает одинаково на любом Linux. Для VPS это значит: не нужно подбирать версии Python, Node.js или PostgreSQL под систему, несколько проектов уживаются на одном сервере, а файл compose.yaml описывает весь набор служб так, что его можно поднять на новом сервере за минуты.
Какой VPS нужен для Docker
Виртуализация — KVM. Docker использует возможности ядра Linux: пространства имён, cgroups, свои сетевые правила. На KVM у сервера своё ядро, и Docker работает без ограничений. На OpenVZ и LXC ядро общее с другими клиентами, и Docker там либо не запускается, либо работает с ограничениями, которые зависят от хостера. Подробнее — в статье KVM или OpenVZ.
Память и ядра. Сам Docker занимает немного, память съедают контейнеры. Ориентиры:
- 1 ГБ — один-два лёгких контейнера: бот, небольшой API, мониторинг;
- 2 ядра и 2 ГБ — сайт с базой данных и обратным прокси, несколько небольших служб;
- 2–4 ядра и 4 ГБ — несколько проектов, PostgreSQL, Redis, сборка образов прямо на сервере;
- от 8 ГБ — GitLab, n8n с большим числом сценариев, Elasticsearch и другие тяжёлые службы.
Диск. Образы занимают место: базовый образ с Python или Node.js весит сотни мегабайт, а старые версии копятся при каждом обновлении. Берите от 30 ГБ на NVMe, для сборки образов на сервере — больше.
По каталогу accsly на 1 ноября 2026 года тариф на KVM с 2 ядрами и 2 ГБ памяти в середине рынка стоит 1 286 ₽ в месяц, четверть таких тарифов дешевле 750 ₽. С 2 ядрами и 4 ГБ — 1 706 ₽, четверть дешевле 1 041 ₽. Подборки: VPS для Docker, VPS на KVM, VPS с 4 ГБ. Для пробы удобна почасовая оплата: сервер на вечер стоит десятки рублей.
Перед установкой
Возьмите свежую Ubuntu 22.04 или 24.04 LTS либо Debian 12 и сначала сделайте базовую защиту: обновления, вход по ключу, отдельный пользователь, файрвол. Всё это — в статье Первые 10 шагов после покупки VPS. Панель управления сайтами для сервера с контейнерами обычно не нужна, почему — в статье Панели управления сервером.
Установка из официального репозитория
Пакет docker.io из репозитория Ubuntu часто отстаёт от актуальной версии и не всегда содержит Compose. Надёжнее ставить из репозитория Docker. Команды для 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
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Для Debian команды те же, только в адресах linux/ubuntu меняется на linux/debian, а вместо UBUNTU_CODENAME берётся VERSION_CODENAME. Проверьте установку:
sudo docker run hello-world
docker compose version
Есть и установка одной командой через get.docker.com, но сама документация Docker не советует её для рабочих серверов: она ставит много пакетов без подтверждения и всегда берёт последнюю версию.
Группа docker. Чтобы не писать sudo перед каждой командой, пользователя добавляют в группу docker: sudo usermod -aG docker $USER и повторный вход. Помните, что это права root: участник группы может запустить контейнер с доступом ко всей файловой системе сервера. Добавляйте туда только свою рабочую учётную запись.
Первый проект на Docker Compose
Отдельные команды docker run с десятком параметров быстро забываются. Удобнее описать проект в файле compose.yaml в отдельной папке, например /opt/app. Пример — веб-приложение с базой PostgreSQL:
services:
app:
image: ghcr.io/example/app:1.4.2
restart: unless-stopped
environment:
DATABASE_URL: postgres://app:${DB_PASSWORD}@db:5432/app
ports:
- "127.0.0.1:8080:8080"
depends_on:
- db
db:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
Пароль положите рядом в файл .env со строкой DB_PASSWORD=... и закройте его от чтения другими пользователями: chmod 600 .env. Запуск — docker compose up -d, журнал — docker compose logs -f app, остановка — docker compose down.
Три вещи в этом примере важны:
restart: unless-stopped— контейнеры поднимутся после перезагрузки сервера;- у базы нет раздела
ports: приложение видит её по имениdbво внутренней сети проекта, а снаружи она недоступна; - порт приложения опубликован только на
127.0.0.1, а наружу его отдаёт nginx или Caddy с сертификатом TLS.
Порты и файрвол
Главная ловушка для новичков. Когда контейнер публикует порт как "5432:5432", Docker сам добавляет правила iptables, и такой порт открывается наружу независимо от правил ufw или firewalld. Документация Docker прямо предупреждает: опубликованные порты контейнеров идут мимо правил файрвола. Именно так в интернет чаще всего попадают базы PostgreSQL, MongoDB и Redis без пароля.
Правило простое: наружу публикуйте только то, что должно быть доступно всем, — обычно порты 80 и 443 обратного прокси. Остальное либо без раздела ports, либо с привязкой к 127.0.0.1. Проверить, что реально слушает сервер, можно командой ss -tlnp, а снаружи — с другого компьютера командой nc -zv IP-сервера 5432.
Журналы и место на диске
По умолчанию Docker пишет вывод контейнеров в JSON-файлы без ограничения размера. Болтливое приложение за пару месяцев заполняет диск, и сервер встаёт. Ограничьте журналы для всех контейнеров в файле /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
Затем sudo systemctl restart docker. Настройка действует для контейнеров, созданных после неё, поэтому пересоздайте проекты: docker compose up -d --force-recreate.
Второй пожиратель места — старые образы. Сколько занято, покажет docker system df, удалить неиспользуемые образы — docker image prune -a. Команду docker system prune --volumes без понимания не запускайте: она удалит и тома остановленных проектов вместе с данными.
Где живут данные и как их копировать
Всё, что приложение записало внутри контейнера, исчезает при его пересоздании. Сохраняется только то, что лежит в томах (volumes) или в подключённых папках сервера. Перед запуском любого образа проверьте в его документации, какие папки нужно вынести в том: для PostgreSQL это /var/lib/postgresql/data, для других приложений — свои пути.
Копировать файлы базы данных на ходу ненадёжно. Делайте дамп через сам контейнер:
docker compose exec -T db pg_dump -U app app | gzip > /backup/app-$(date +%F).sql.gz
Добавьте эту команду в cron и отправляйте копии за пределы сервера, вместе с compose.yaml и .env. Как устроить внешнее хранение и проверку копий — в статье Резервные копии VPS.
Обновление контейнеров
Указывайте в compose.yaml конкретную версию образа (postgres:16, app:1.4.2), а не latest: тогда обновление происходит, когда вы его запланировали, а не при случайном перезапуске. Порядок обновления:
- сделать дамп базы;
- поменять версию в
compose.yaml; docker compose pullиdocker compose up -d;- проверить журнал и работу приложения, затем удалить старый образ.
Мажорные версии баз данных, например PostgreSQL 16 → 17, так не обновляются: новой версии нужен перенос данных через дамп и загрузку. Систему сервера и сам Docker обновляйте обычным apt upgrade.
Куда дальше
Когда на сервере несколько проектов, удобно поставить обратный прокси, который сам получает сертификаты, и мониторинг доступности. Для бота на Python или Node.js в контейнере хватит небольшого сервера, подробности — в статье VPS для Telegram-бота. Если контейнеров становится много и одного сервера мало, следующий шаг — несколько серверов под оркестратором, тарифы в подборке VPS для Kubernetes. Под автоматизацию и CI в контейнерах есть подборки VPS для n8n и VPS для GitLab.