Docker Compose ports versus expose

Publish a port deliberately and understand why expose neither starts a listener nor enforces network isolation.

Best practices
Illustration of server operations and log analysis

ports publishes a container port through the Docker host. expose declares intended container ports without publishing them. It is documentation and metadata, not a firewall rule: services on the same Docker network can normally reach listening ports whether or not expose lists them.

Publish a host port

For an HTTP service:

services:
  web:
    image: nginx:stable
    ports:
      - "127.0.0.1:8080:80"

The host's loopback port 8080 forwards to port 80 in the container. Omitting the IP, as in "8080:80", normally publishes on all host interfaces. Actual external reachability still depends on routing, firewall rules, and platform behavior; publication is not proof that every machine can connect.

A container-only number requests an automatically allocated host port:

services:
  web:
    image: nginx:stable
    ports:
      - "80"

Find the allocation with docker compose port web 80 or docker compose ps. It may change when the container is recreated. Quote short-syntax port values in YAML.

Communicate within the project network

services:
  database:
    image: mysql:8.4
    environment:
      MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD:?Set a database password}"
    expose:
      - "3306"
  app:
    image: myapp:1.2
    environment:
      DB_HOST: database
      DB_PORT: "3306"

This sketch supplies the database's required initialization setting; use your deployment's secret-management approach for real credentials. Both services join the default project network and the app connects to database:3306. The application must handle database startup/readiness and use valid credentials.

Removing expose does not close port 3306 to peers on that network. Conversely, adding it does not make MySQL start, listen on the right address, or authorize clients. Services attached to separate networks do not become connected merely because they appear in the same Compose file.

FAQ

Can the host reach a port without ports?

It is not published as a host-port mapping. Native Linux hosts may nevertheless reach bridge-container addresses directly, subject to routing and filtering. Docker Desktop has different VM networking. Therefore, “not published” is more precise than “impossible for the host to access.”

Should databases publish ports?

Leave them unpublished when only application peers need access. For deliberate host-side administration, a loopback-bound mapping such as "127.0.0.1:3306:3306" narrows exposure. For remote administration, design authentication, transport protection, and network restrictions explicitly.

What creates a real boundary?

Network membership, routing and firewall policy, host configuration, and application authentication. expose describes intent; it does not enforce that boundary.

See Compose service attributes and Docker port publishing.

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting