Публікація порту (-p) відкриває доступ до контейнера ззовні: трафік на порт хоста перенаправляється в контейнер. На відміну від EXPOSE у Dockerfile, який лише документує порт, -p справді змінює мережеві правила хоста.
docker run -p 8080:80 nginx # 0.0.0.0:8080 - на ВСІХ інтерфейсах хоста
docker run -p 127.0.0.1:8080:80 nginx # лише з самого хоста
docker run -p 10.0.0.5:8080:80 nginx # лише на конкретному інтерфейсі
Ключова різниця: без вказаної адреси порт публікується на всіх мережевих інтерфейсах (0.0.0.0 і ::) - тобто доступний з інтернету, якщо сервер має публічну адресу.
Типова аварія: на сервері в compose.yaml бази даних залишили з розробки:
services:
postgres:
ports:
- "5432:5432" # база доступна всьому інтернету
Сканери знаходять відкриті бази й Redis за хвилини. Через те, що Docker керує правилами фаєрвола сам, ufw таку публікацію не блокує.
Як правильно:
- сервісам, до яких звертаються лише інші контейнери (база, Redis, черги), - не публікувати порти взагалі: контейнери в одній мережі звертаються один до одного за іменем сервісу (
postgres:5432) без публікації; - доступ з хоста для розробки чи адміністрування -
127.0.0.1:5432:5432, а на сервері - SSH-тунель; - назовні - лише зворотний проксі (Nginx, Caddy, Traefik) на 80/443.
services:
postgres:
ports:
- "127.0.0.1:5432:5432"
Перевірити, що реально опубліковано: docker ps (колонка PORTS) чи ss -tlnp на хості.