Docker на Linux VPS: production-развертывание, сеть, тома, HTTPS, обновления и резервное копирование

26.08.26
Схема production-развертывания Docker на Linux VPS: reverse proxy с HTTPS, Docker-приложение, база данных, тома, обновления и резервные копии

Приложение собрано в Docker, локально запускается одной командой и успешно открывается в браузере. Следующий шаг кажется очевидным: заказать Linux VPS, перенести туда проект и выполнить docker compose up -d.

Для тестового стенда этого иногда действительно достаточно. Для постоянной работы — нет.

После первой перезагрузки VPS может оказаться, что контейнер не запустился автоматически. После пересоздания контейнера — что база хранилась внутри него и данные пропали. А опубликованный «временно для проверки» порт PostgreSQL может остаться доступным из Интернета намного дольше, чем планировалось.

Production-развертывание Docker-приложения — это не отдельная магическая технология. Нужно просто заранее решить несколько эксплуатационных вопросов: где лежат постоянные данные, какие сервисы доступны снаружи, как работает HTTPS, что произойдет после reboot, как обновлять контейнеры и из чего восстанавливать приложение после сбоя.

В этой статье разберем именно такую схему для одного Linux VPS. Без Kubernetes и сложной оркестрации — обычное приложение, Docker Compose, reverse proxy, база данных и понятный порядок обслуживания.

Что такое Docker Compose: Docker Compose — инструмент для описания приложения из нескольких контейнеров в одном файле compose.yaml. В нем задаются сервисы, сети, тома и другие параметры, после чего всем стеком можно управлять как единым проектом.

Как выглядит production-схема Docker-приложения на VPS

Самый простой Docker-проект часто начинается с одного контейнера:


Интернет → контейнер приложения

Для production этого обычно мало. Если у приложения есть база, HTTPS и постоянные данные, схема становится примерно такой:


                Интернет
                    │
                 80 / 443
                    │
                    ▼
            Reverse proxy
             Nginx / другой
                    │
          внутренняя Docker-сеть
                    │
                    ▼
               Приложение
                    │
          внутренняя Docker-сеть
                    │
                    ▼
               База данных
                    │
                    ▼
             Persistent volume
Как читать схему: наружу выходит только точка входа для HTTP/HTTPS. Приложение и база общаются между собой по внутренней Docker-сети, а постоянные данные базы хранятся отдельно от жизненного цикла контейнера.

Reverse proxy, или обратный прокси, принимает запросы пользователей и передает их внутреннему приложению. На практике он удобен для HTTPS, работы с доменами и отделения публичной точки входа от самих контейнеров.

Такое разделение дает простой принцип:

  • снаружи открываем только то, что действительно должно быть публичным;
  • между контейнерами используем внутреннюю сеть;
  • данные базы храним независимо от жизненного цикла контейнера;
  • конфигурацию приложения описываем так, чтобы окружение можно было воспроизвести после сбоя.

Docker Compose по умолчанию создает сеть проекта, а сервисы внутри нее могут обращаться друг к другу по именам сервисов. Поэтому приложению обычно не нужен IP контейнера базы: достаточно, например, имени db.

Что важно запомнить: контейнер — расходуемый объект. Production-проект лучше проектировать так, чтобы любой контейнер можно было удалить и создать заново без потери постоянных данных.

Как подготовить Linux VPS и развернуть приложение

Что проверить до установки Docker

Если VPS только заказан, сначала нужно подготовить сам Linux:

  • установить обновления безопасности;
  • создать отдельного пользователя;
  • настроить SSH;
  • проверить firewall;
  • убедиться, что хватает RAM и дискового пространства;
  • настроить время;
  • продумать резервное копирование.

Этот этап подробно разобран в статье «Первичная настройка Ubuntu VPS после заказа: пользователь, SSH, обновления, firewall и резервное копирование».

Для Docker дополнительно полезно проверить архитектуру системы:

Терминал Linux
dpkg --print-architecture

И версию Ubuntu:

Терминал Linux
. /etc/os-release && echo "$PRETTY_NAME"

Устанавливаем Docker Engine и Compose plugin

Для рабочего VPS лучше использовать официальный apt-репозиторий Docker, а не запускать установку через случайный shell-скрипт.

Сначала добавим необходимые пакеты и каталог для ключа:

Терминал Linux
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings

Затем загрузим официальный ключ Docker:

Терминал Linux
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

Создадим описание репозитория:

Терминал Linux
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

Обновим индекс пакетов:

Терминал Linux
sudo apt update

И установим Docker Engine вместе с Compose plugin:

Терминал Linux
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

После установки проверьте службу Docker:

Терминал Linux
sudo systemctl status docker

И версию Compose:

Терминал Linux
sudo docker compose version
Важно: если Docker уже устанавливался раньше из другого источника, не удаляйте пакеты вслепую. Сначала проверьте, какая версия реально используется и нет ли на сервере работающих контейнеров.

Как организовать каталог проекта

Для небольшого приложения удобно держать deployment-конфигурацию в отдельном каталоге, например:

/opt/myapp/
├── compose.yaml
├── .env
├── nginx/
│   └── conf.d/
└── backup/

Это только пример. Код приложения может вообще не лежать на VPS, если используется готовый image из registry.

Для production полезно разделять:

  • image — код приложения и его зависимости;
  • Compose-конфигурацию — как именно приложение запускается;
  • постоянные данные — база и пользовательские файлы;
  • секреты — пароли, токены и ключи.

Чем меньше ручных изменений сделано внутри уже запущенного контейнера, тем проще потом восстановить сервер.

Минимальный compose.yaml

Возьмем условное веб-приложение и PostgreSQL.

services:
  app:
    image: registry.example.com/myapp:1.4.2
    restart: unless-stopped
    environment:
      DB_HOST: db
      DB_NAME: app
      DB_USER: app
      DB_PASSWORD: ${DB_PASSWORD}
    depends_on:
      db:
        condition: service_healthy
    networks:
      - backend

db:
image: postgres:17
restart: unless-stopped
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d app"]
interval: 10s
timeout: 5s
retries: 5
networks:
- backend

networks:
backend:

volumes:
postgres_data:

Здесь специально нет ports у PostgreSQL. Приложение и база находятся в одной Docker-сети и могут общаться напрямую.

Перед запуском полезно проверить конфигурацию:

Терминал Linux
sudo docker compose config -q

После этого можно запустить проект:

Терминал Linux
sudo docker compose up -d

И проверить состояние сервисов:

Терминал Linux
sudo docker compose ps

Сеть, порты и HTTPS

Не публикуйте каждый контейнер наружу

Одна из самых распространенных ошибок в первых Docker-проектах выглядит так:

db:
  ports:
    - "5432:5432"

Так делать можно, но только если внешний доступ к базе действительно нужен.

Когда используется ports или -p, Docker сопоставляет контейнерный порт с адресом хоста и создает соответствующие сетевые правила.

Если PostgreSQL нужен только приложению на этом же VPS, внешний порт обычно не требуется:


app → db:5432

Здесь db — имя Compose-сервиса.

То же относится к Redis, RabbitMQ, внутренним API и другим компонентам, которые не должны напрямую принимать соединения из Интернета.

Типичная ошибка: опубликовать порт базы «на время настройки», а потом забыть его убрать. Если удаленное подключение действительно нужно, ограничьте источник трафика и отдельно проверьте правила firewall.

Есть еще один важный нюанс: Docker сам управляет сетевыми правилами для опубликованных портов. Поэтому доступность контейнера нельзя оценивать только по выводу ufw status. После публикации порта проверяйте его фактическую доступность извне.

Где должен находиться HTTPS

Для обычного веб-приложения удобно оставить контейнер приложения во внутренней сети, а наружу вывести reverse proxy:


Интернет
   │
 443
   │
   ▼
 Nginx
   │
   ▼
 app:8000

У такого подхода несколько плюсов:

  • TLS завершается в одном понятном месте;
  • приложению не обязательно самому управлять сертификатами;
  • проще подключить несколько доменов;
  • внутренний порт приложения не нужно открывать всему Интернету.

Полную настройку Nginx здесь не разбираем — это отдельная тема. Для Docker важнее понять само разделение публичной и внутренней части.

Если Nginx установлен непосредственно на VPS, порт приложения можно привязать только к loopback-интерфейсу:

ports:
  - "127.0.0.1:8000:8000"

Тогда сервис будет доступен локально на хосте, но не станет слушать этот порт на всех внешних интерфейсах.

Тома, конфигурация и секреты

Почему данные нельзя оставлять только внутри контейнера

Writable layer контейнера не подходит для хранения данных, которые должны пережить удаление самого контейнера. Для этого используются volumes.

Плохая схема:


Контейнер PostgreSQL
└── база внутри writable layer

Нормальная схема:


Контейнер PostgreSQL
        │
        ▼
   Docker volume
        │
        ▼
 Постоянные данные

Например:

services:
  db:
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
postgres_data:

Named volume управляется Docker и продолжает существовать отдельно от конкретного контейнера.

Volume или bind mount

Оба варианта полезны, но задачи у них разные.

ВариантКогда удобенПример
Named volumeДанные, которыми управляет само приложение или СУБДPostgreSQL, MySQL, Redis с persistence
Bind mountФайлы, которые администратор хочет явно видеть и редактировать на VPSКонфигурация Nginx, статические файлы, локальные каталоги

Пример bind mount:

volumes:
  - ./nginx/conf.d:/etc/nginx/conf.d:ro

Bind mount сильнее привязывает Compose-проект к конкретной структуре каталогов на VPS. Named volume в этом смысле лучше отделяет данные контейнера от структуры хоста.

.env — это конфигурация, но не сейф

Compose умеет подставлять значения из файла .env.

Например:

DB_PASSWORD=replace-me

А в compose.yaml:

environment:
  DB_PASSWORD: ${DB_PASSWORD}

Это удобно, но файл .env сам по себе не шифрует секреты.

Поэтому:

  • не добавляйте рабочий .env в публичный Git;
  • ограничивайте права на файл;
  • не помещайте пароли и токены в Dockerfile;
  • не запекайте рабочие секреты внутрь image;
  • для более строгих требований используйте отдельную систему управления секретами.

Как обеспечить постоянную работу и безопасно обновлять приложение

Restart policy

Контейнер, который однажды запустили через docker compose up -d, должен возвращаться в работу после обычного reboot VPS.

Для этого используется restart policy.

Например:

restart: unless-stopped

Или в некоторых сценариях:

restart: always

После настройки полезно проверить поведение реальным контролируемым reboot в техническое окно, а не считать, что все обязательно запустится автоматически.

Healthcheck

Состояние running говорит только о том, что основной процесс контейнера не завершился. Но приложение при этом может не отвечать на HTTP или не иметь доступа к базе.

Что такое healthcheck: healthcheck — проверка состояния сервиса внутри контейнера. По ее результату Docker может отмечать контейнер как healthy или unhealthy, то есть различать просто запущенный процесс и реально отвечающий сервис.

Например:

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
  interval: 30s
  timeout: 5s
  retries: 3

Конкретная команда зависит от приложения. Не добавляйте фиктивный endpoint /health, если самого такого маршрута у приложения нет.

Проверить состояние можно командой:

Терминал Linux
sudo docker compose ps
Важно: healthcheck не заменяет внешний мониторинг. Контейнер может быть healthy, а сайт снаружи — недоступен из-за DNS, reverse proxy, сертификата или сетевых правил.

Логи

Для просмотра логов всего Compose-проекта:

Терминал Linux
sudo docker compose logs

Последние 100 строк:

Терминал Linux
sudo docker compose logs --tail=100

Для наблюдения в реальном времени:

Терминал Linux
sudo docker compose logs -f

Но для постоянной эксплуатации нужно подумать и о ротации. Если логи растут без ограничений, однажды они могут занять весь диск VPS.

Как обновлять контейнеры

Если в compose.yaml используются готовые images, базовая схема обновления выглядит так:

  1. Сделать актуальную резервную копию критичных данных.
  2. Проверить release notes новой версии.
  3. Скачать новые images.
  4. Пересоздать нужные сервисы.
  5. Проверить состояние и логи.
  6. При проблеме выполнить заранее подготовленный откат.

Скачать новые images без запуска контейнеров:

Терминал Linux
sudo docker compose pull

После этого:

Терминал Linux
sudo docker compose up -d

Проверяем состояние:

Терминал Linux
sudo docker compose ps

И последние логи:

Терминал Linux
sudo docker compose logs --tail=100
Типичная ошибка: использовать в production только тег latest и не фиксировать, какая версия image реально развернута. Для управляемого обновления администратор должен понимать, с какой версии он переходит и к какой сможет вернуться.

Будет ли обновление без простоя

Не обязательно.

Если приложение работает в одном экземпляре, пересоздание контейнера может дать короткий перерыв.

Docker Compose сам по себе не превращает один контейнер в отказоустойчивый кластер. Для обновлений без разрыва запросов нужна подходящая архитектура: несколько экземпляров приложения, балансировка, совместимые миграции базы и контролируемое переключение трафика.

Для обычного небольшого VPS честнее заранее планировать короткое техническое окно, чем обещать zero downtime там, где архитектура его не обеспечивает.

Что предусмотреть для отката

До обновления нужно знать:

  • какой image работал до обновления;
  • совместима ли старая версия приложения с уже измененной базой;
  • есть ли свежий backup базы;
  • сохранилась ли предыдущая Compose-конфигурация;
  • можно ли быстро получить старый image.

Особенно внимательно относитесь к миграциям базы. Если новая версия приложения необратимо изменила структуру данных, возврата старого image может оказаться недостаточно.

Резервное копирование и финальная проверка production-ready

Как делать резервные копии Docker-приложения

Что именно резервировать

Один архив каталога проекта редко является полноценным backup.

Что резервироватьЗачем
База данныхОсновные изменяемые данные приложения
Volumes и пользовательские файлыОни не входят автоматически в image
compose.yaml и конфигурацияНужны для воспроизведения окружения
СекретыБез них восстановленный сервис может не подключиться к зависимостям

Images обычно можно снова получить из registry. Если image существует только локально на этом VPS, это уже отдельный риск: его нужно либо сохранить, либо разместить в доступном registry.

docker export не копирует volumes

Команда docker export экспортирует файловую систему контейнера, но не содержимое подключенных volumes.

То есть такой вывод:

«Я экспортировал контейнер PostgreSQL — значит база сохранена»

может оказаться ошибочным.

Важно: резервная копия Docker-контейнера и резервная копия данных приложения — не одно и то же. Всегда отдельно определяйте, где физически находятся постоянные данные.

Базу лучше резервировать средствами самой СУБД

Для PostgreSQL обычно используется pg_dump или другой предусмотренный механизм, для MySQL/MariaDB — mysqldump либо выбранная схема физического резервирования.

Для большой production-базы способ backup нужно выбирать с учетом размера, нагрузки и требований к времени восстановления.

Просто архивировать файлы работающей СУБД из volume без понимания ее внутреннего устройства — не универсальный безопасный способ.

Backup volume

Для обычных пользовательских файлов volume можно архивировать через временный контейнер, которому монтируется сам volume и каталог для резервной копии.

Но при работе со stateful-сервисами важно учитывать состояние данных в момент копирования. Если приложение активно пишет в volume, файловый архив может оказаться несогласованным.

Поэтому:

  • для пользовательских файлов файлового backup часто достаточно;
  • для баз данных лучше использовать штатные механизмы самой СУБД;
  • для критичных сервисов нужно отдельно проверять консистентность восстановления.

Проверяем не backup, а восстановление

Сам факт появления файла резервной копии еще не означает, что система восстановления работает.

Проверочный сценарий выглядит примерно так:


Чистый VPS
   │
   ▼
Docker + Compose
   │
   ▼
compose.yaml
   │
   ├── восстановление БД
   ├── восстановление volumes
   └── возврат конфигурации
   │
   ▼
Запуск приложения
   │
   ▼
Функциональная проверка
Практика IPWAY: для небольшого Docker-проекта полезно хранить рядом с deployment-конфигурацией короткий recovery-чек-лист. Через несколько месяцев намного проще выполнить записанные шаги, чем вспоминать, где лежала база и какие переменные требовались сервисам.

Что проверить перед тем, как считать сервис production-ready

Контейнеры

  • все нужные сервисы запускаются;
  • настроена restart policy;
  • после reboot приложение возвращается в рабочее состояние;
  • healthcheck проходит там, где он действительно нужен.

Сеть

  • наружу опубликованы только необходимые порты;
  • база и внутренние сервисы не открыты в Интернет без причины;
  • правила Docker firewall проверены отдельно;
  • внутренние сервисы обращаются друг к другу по Docker network.

Данные

  • база хранится в volume или другом постоянном хранилище;
  • пользовательские файлы не зависят от writable layer контейнера;
  • пересоздание контейнера не уничтожает данные.

HTTPS

  • домен ведет на правильный VPS;
  • сертификат действителен;
  • HTTP при необходимости перенаправляется на HTTPS;
  • механизм продления сертификата проверен.

Обновления

  • понятна текущая версия image;
  • есть порядок pull → recreate → check;
  • перед критичными обновлениями создается backup;
  • существует сценарий отката.

Резервное копирование

  • резервируется база;
  • резервируются необходимые volumes;
  • сохранены Compose-файлы и конфигурация;
  • backup хранится не только на том же VPS;
  • восстановление хотя бы один раз проверялось.

Ресурсы

  • хватает RAM;
  • нет постоянного ухода в swap под обычной нагрузкой;
  • остается запас диска;
  • контролируется рост логов;
  • база и приложение не упираются в CPU.

Если после добавления базы, reverse proxy и фоновых сервисов VPS постоянно работает на пределе, изменением пары параметров Compose проблему уже не решить. Нужно либо увеличить ресурсы, либо сначала определить, какой сервис создает основную нагрузку.

Заключение

Docker хорошо упрощает доставку приложения на Linux VPS, но сам по себе не решает задачи эксплуатации.

Для production нужно отдельно подумать о постоянных данных, сети, HTTPS, автозапуске, обновлениях и резервном копировании. Если эти части описаны в Compose и понятны администратору, пересоздание контейнера перестает быть рискованной операцией.

Хороший признак рабочей Docker-схемы — сервер можно восстановить без ручного редактирования файлов внутри контейнеров. Есть Compose-конфигурация, известные версии images, отдельные данные и проверенный backup.

А ситуация «главное сейчас не трогать этот контейнер, потому что внутри что-то настраивали руками» — уже повод привести deployment в порядок.

Что почитать дальше

Если вы готовите Linux VPS для постоянной работы приложения, пригодятся связанные материалы:

Когда стоит обратиться к специалистам

Если приложение состоит из пары контейнеров и хорошо документировано, такую схему вполне можно развернуть самостоятельно. Главное — не оставлять постоянные данные внутри контейнеров и заранее проверить, что произойдет после reboot и обновления.

Если новый сервер еще только выбирается, можно подобрать Linux VPS IPWAY под весь Docker-стек. При расчете стоит учитывать не только основной контейнер, но и базу данных, reverse proxy, фоновые процессы и запас ресурсов под обновления.

Когда стоит обратиться к специалистам: если непонятно, сколько ресурсов потребуется всему стеку или приложение уже работает под реальной нагрузкой и переносить его методом проб и ошибок нежелательно, конфигурацию VPS лучше подобрать до миграции.

Если инфраструктуру вы администрируете самостоятельно, следующий шаг — выбрать подходящую конфигурацию Linux VPS и развернуть на ней Compose-проект. Если есть сомнения по CPU, RAM или диску, сначала лучше уточнить конфигурацию под конкретный набор контейнеров.

Кратко

  • Docker Compose удобен для описания сервисов, сетей и volumes одного приложения.
  • В Интернет нужно публиковать только те порты, которым действительно нужен внешний доступ.
  • Данные базы нельзя хранить только в writable layer контейнера.
  • Restart policy помогает контейнерам вернуться в работу после перезапуска Docker или VPS.
  • Healthcheck проверяет состояние сервиса, но не заменяет внешний мониторинг.
  • Обновление одного контейнера через Compose не гарантирует работу без простоя.
  • docker export не включает содержимое подключенных volumes.
  • Backup считается рабочим только после успешной проверки восстановления.
Headscale на VPS объединяет Linux-сервер, ноутбук, смартфон и офисную сеть в защищённую mesh-сеть.
12.10.26
Headscale на VPS: как объединить серверы и устройства в собственную mesh-сеть

Когда в частной сети несколько серверов, рабочих компьютеров и мобильных устройств, ручное управление отдельными конфигурациями WireGuard быстро усложняется. Администратору приходится самостоятельно распределять ключи, учитывать адреса узлов,…

Автор: Редакция блога
Схема удалённого доступа к домашней или офисной сети без белого IP через Linux VPS и защищённый туннель за CGNAT.
05.10.26
Как получить удалённый доступ к домашней или офисной сети без белого IP

Нужно подключиться из Интернета к домашнему роутеру, NAS, компьютеру или серверу в офисе, но провайдер не выдаёт белый IP. Внутри локальной сети устройства работают, однако открыть…

Автор: Редакция блога
Зашифрованные удалённые резервные копии на VPS с хранением ежедневных, еженедельных и ежемесячных снимков и проверкой восстановления.
28.09.26
Удалённые резервные копии на VPS: restic или Borg, шифрование и проверка восстановления

Резервная копия на том же сервере, где находятся рабочие данные, помогает не во всех случаях. Если выйдет из строя диск, сервер окажется скомпрометирован или администратор случайно…

Автор: Редакция блога
Как выбрать VPS для Telegram-бота: подбор CPU, RAM и SSD для подходящей конфигурации сервера IPWAY.
25.09.26
Как выбрать VPS для Telegram-бота: CPU, RAM, диск и запас для роста

Telegram-бот может без проблем работать на ноутбуке разработчика, но для круглосуточной эксплуатации ему нужен сервер. На этом этапе возникает практический вопрос: какую конфигурацию VPS выбрать, чтобы…

Автор: Редакция блога
Единый IP для удалённой команды: домашние, офисные и мобильные сотрудники подключаются через Linux VPS к CRM и API с IP-whitelist
22.09.26
Постоянный IP для удалённых сотрудников: VPS как единая точка выхода для IP-whitelist

Доступ к CRM, API, базе данных или административной панели нередко ограничивают списком доверенных IP-адресов. Такой список называют IP-whitelist. Пока сотрудники работают из одного офиса, в него…

Автор: Редакция блога
Nginx как reverse proxy на VPS: HTTPS, заголовки и диагностика 502
21.09.26
Nginx как reverse proxy на VPS: HTTPS, заголовки и диагностика 502

Приложение на VPS может исправно отвечать на локальном порту, например 127.0.0.1:3000, но оставаться недоступным по домену. Открывать этот порт напрямую в интернет обычно не требуется: перед…

Автор: Редакция блога

Мы используем файлы cookie и сервис веб-аналитики Яндекс Метрика для улучшения работы сайта. Оставаясь на сайте, вы соглашаетесь с Политикой конфиденциальности.