Docker Compose check · medium

Database and queue ports published on all interfaces

A ports entry like "5432:5432" publishes the database on every network interface of the host, not just to other containers. The explainer flags the default ports of Postgres (5432), MySQL (3306), MongoDB (27017), Redis (6379), Elasticsearch (9200), RabbitMQ (5672) and Memcached (11211) as medium unless they are bound to 127.0.0.1, localhost or ::1.

$ explain docker-compose.yml
! db publishes datastore port 5432 medium
line 5
fix: see below
$ 

What the free Docker Compose explainer reports on the risky example below.

Why it matters

Services on the same Compose network already reach each other by service name without any `ports` entry. Publishing a database port exists only to let things outside Docker connect, and by default that includes other machines.

Docker writes its own firewall rules for published ports. Its documentation notes that these can bypass host firewalls such as ufw, so a port you thought was blocked may still be open.

Datastore ports are scanned for constantly, and many images start with default or no authentication.

Risky and safer docker-compose.yml

Riskydocker-compose.yml
services:
  db:
    image: postgres:16.4
    ports:
      - "5432:5432"
    restart: unless-stopped
    mem_limit: 512m
Saferdocker-compose.yml
services:
  db:
    image: postgres:16.4
    # Reachable from this machine only; other services use db:5432
    ports:
      - "127.0.0.1:5432:5432"
    restart: unless-stopped
    mem_limit: 512m

How to fix it

  • If only other containers need the database, remove the ports entry; they reach it as db:5432 on the Compose network.
  • If tools on the host need it, bind to loopback: "127.0.0.1:5432:5432".
  • If other machines really need it, restrict access with a firewall rule that Docker's published ports respect, and require authentication and TLS.

When it's acceptable

  • A development machine that is not reachable from other networks, where the port is published for local tools.
  • A database that must accept remote clients and sits behind a network firewall you have verified, with authentication on.

Check your own docker-compose.yml

The risky example is loaded below. Paste your own file to check it for this and every other Docker Compose rule. It runs in your browser; nothing is uploaded.

docker-compose.yml

Parsed in your browser. Nothing is uploaded.

Explanation

1 service0 networks0 volumes1 medium

Top level

dbpostgres:16.4

  • Docs for image (opens in a new tab)

    Runs the image postgres:16.4.

  • Docs for ports (opens in a new tab)

    Publishes: host port 5432 forwards to container port 5432, on all network interfaces.

    A database or queue port bound to all interfaces can be reached from outside the host, where it is often probed with default credentials.

    Safer: Bind it to loopback, e.g. "127.0.0.1:5432:5432", or drop the publish and use the internal network.

  • Docs for restart (opens in a new tab)

    Restarts if it stops or after a daemon restart (unless-stopped), but stays down if you stopped it manually.

  • Docs for mem_limit (opens in a new tab)

    Limits memory to 512m. The container is killed if it exceeds this.

Questions

Does "5432:5432" in docker-compose expose Postgres to the internet?

It publishes the port on all host interfaces. If the host has a public address and nothing in front blocks the port, yes. Bind it to 127.0.0.1 to keep it local.

Do containers need ports to talk to a database in the same compose file?

No. Services on the same Compose network reach each other by service name and container port without any ports entry.

Which ports does the explainer check?

5432, 3306, 27017, 6379, 9200, 5672 and 11211, as the container port. Short syntax without a host port ("5432") is flagged too, because Docker still publishes it on a random host port.