Перейти до вмісту
VPS і сервери · 6 хв

Docker і Docker Compose на VPS — і пастка з файрволом

Майже будь-який самохостинг сьогодні постачається у вигляді docker-compose.yml. Встановити Docker на VPS — одна команда. А щоб він працював безпечно, треба знати ще одну річ, яку пропускають майже всі інструкції: опубліковані порти Docker обходять ufw.

Який тариф

Сам Docker легкий, а от те, що ви в ньому запускаєте, — ні. Орієнтир такий: один застосунок із базою вміщується на Pulse (2 vCPU, 2 ГБ), зв’язка з трьох-п’яти сервісів — на Drive (4 ГБ, $15 на місяць) або Forge (8 ГБ, $22 на місяць). Образи й томи непомітно ростуть, тож стежте не лише за пам’яттю, а й за диском.

1. Встановлення

Офіційний скрипт встановлює Docker Engine і плагін Compose з репозиторію Docker:

curl -fsSL https://get.docker.com | sh
docker run --rm hello-world
docker compose version

Працюєте під звичайним користувачем — виконайте usermod -aG docker користувач і перелогіньтеся. Пам’ятайте: членство в групі docker по суті дорівнює root на сервері.

2. Справжній стек

/opt/app/docker-compose.yml: застосунок і PostgreSQL. Застосунок опубліковано лише на localhost — до нього проксуватиме nginx на самому сервері.

services:
  db:
    image: postgres:16
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db:/var/lib/postgresql/data

  app:
    image: ghcr.io/example/app:latest
    restart: unless-stopped
    depends_on: [db]
    environment:
      DATABASE_URL: postgres://postgres:${DB_PASSWORD}@db:5432/postgres
    ports:
      - "127.0.0.1:8080:8080"

volumes:
  db:
cd /opt/app && echo 'DB_PASSWORD=змініть-пароль' > .env && chmod 600 .env
docker compose up -d
docker compose ps
docker compose logs -f app

restart: unless-stopped піднімає контейнери після падіння та після перезавантаження сервера.

3. Пастка з файрволом

На цьому щотижня хтось потрапляє. Ви вмикаєте ufw, дозволяєте лише SSH і HTTPS, публікуєте контейнер із ports: - "5432:5432" — і база відкрита всьому інтернету. Docker записує власні правила iptables, і вони спрацьовують раніше за правила ufw.

Дві звички рятують від цього:

  • Публікуйте на localhost (127.0.0.1:8080:8080) усе, до чого мають звертатися лише nginx або ви через SSH-тунель.
  • Порти баз даних не публікуйте взагалі. Контейнери одного compose-проєкту бачать одне одного за іменем сервісу (db:5432 у прикладі вище) без жодних ports:.

Перевірте ззовні, що насправді відкрито: nmap -Pn <IP сервера> зі свого комп’ютера.

4. Логи й диск

За замовчуванням Docker зберігає логи контейнерів вічно, і балакучий застосунок може заповнити диск за кілька тижнів. Обмежте їх у /etc/docker/daemon.json:

{ "log-driver": "json-file", "log-opts": { "max-size": "20m", "max-file": "3" } }
systemctl restart docker
docker system df            # що займає місце
docker image prune -a       # видалити невикористовувані образи

Обмеження діє для контейнерів, створених після зміни, тому перестворіть свої: docker compose up -d --force-recreate.

Чого Docker за вас не зробить

Не збереже томи. docker compose down -v видаляє їх, як і необережний prune. Для PostgreSQL мінімум — нічний дамп docker compose exec -T db pg_dump -U postgres postgres > dump.sql з копіюванням за межі сервера.

Docker і Docker Compose на VPS — і пастка з файрволом · dedisrv