In short, if you use reverse proxy like caddy and don’t want to expose the port directly, don’t do this in docker compose:

ports:
	- "8080:8080"

But instead do this:

ports:
	- "127.0.0.1:8080:8080"

Otherwise, Docker will add a rule to system’s iptables to allow the port through the firewall.

Databases

For databases (or anything that don’t need to expose to the outside world at all), use a docker network rather than using ports:

networks:
  network_name:
    external: false
services:
  db:
    image: postgres:17-alpine
    # Don't!
    # ports:
    #  - "127.0.0.1:5432:5432"
    restart: always
    # add a network
    networks:
      - network_name
  app:
    image: <image>
    ports:
      - "127.0.0.1:8080:80"
    volumes:
      - ./secrets.yaml:/secrets.yaml:ro
    restart: always
    # add a network
    networks:
      - network_name

References