Skip to main content
Traefik reads its routes from labels on the containers, so it fits when it already sits in front of your other Docker services. If it does not, Caddy is less work for the same result. Traefik reaches PostQueen over the Docker network, not through the host. It therefore talks to port 5000, the port PostQueen listens on inside the container, and the 4007 mapping is no longer needed.

Set it up

1

Add Traefik and the labels

Edit docker-compose.yaml from the Compose repository. Add labels to the postqueen service, remove its ports: lines, and add a traefik service:
docker-compose.yaml
Put your domain in the Host rule and your address in acme.email. Keep the existing volumes: entries and add traefik-letsencrypt to them.
  • traefik.enable=true is required, because exposedbydefault=false makes Traefik ignore every container without it.
  • Removing ports: from postqueen matters: left in place, PostQueen also answers on host port 4007 over plain HTTP, past Traefik.
  • readTimeout is raised because Traefik stops reading a request after 60 seconds by default, which cuts off a large upload on a slow connection. PostQueen accepts files up to 1 GB.
  • providers.docker.network tells Traefik which network to reach PostQueen on, since the postqueen container is on two. It takes the network’s full name, which Compose prefixes with the project folder’s name: docker network ls shows it.
2

Start it

Traefik requests the certificate as soon as it sees the router. The domain has to resolve to this server and port 80 has to be open for the challenge.
3

Tell PostQueen its address

Put the public address in the .env file next to docker-compose.yaml. The shipped Compose file reads that file and fills these three values into the postqueen service, so there is no YAML to edit:
Keep /api on the last one, and leave off trailing slashes. Leave BACKEND_INTERNAL_URL as it ships, http://localhost:3000: it is the path from the web app to the API inside the container, not a public address.Recreate the app container so it reads the new values. A plain docker restart or docker compose restart keeps the old container and its old environment.In the folder that holds docker-compose.yaml, recreate only the postqueen service:
The database, Redis and Temporal keep running. Avoid docker compose down for a settings change: on a host that runs other Compose services in the same project, it stops them too. On Kubernetes, see Kubernetes with Helm.
4

Check it

HTTP/2 200 with a certificate from Let’s Encrypt, and a sign-in that holds in the browser.
Traefik does not buffer responses and sets no body size limit by default, so streamed Copilot replies and large uploads pass as they are. Do not attach a buffering middleware to this router.

If it does not work

The router was not created. The usual cause is a missing traefik.enable=true label, or a Host rule that does not match the name you open.
Traefik is serving its default self-signed certificate because the ACME request failed. docker compose logs traefik gives the reason, most often DNS that does not point here yet or port 80 blocked.
That is expected once ports: is removed: PostQueen is reachable only through Traefik. To check the container itself: docker compose exec postqueen node -e "require('http').get('http://localhost:5000/',r=>console.log(r.statusCode))" prints 200.
Traefik cannot reach the container. Check that both services are on postqueen-network, that providers.docker.network names it as docker network ls shows it, and that the service label says port 5000, not 4007.
Last modified on September 23, 2026