Title: Next.js standalone on Compose + domain: Docker-injected HOSTNAME makes the app bind only ONE of the two attached networks, chosen at random → intermittent, non-self-healing 502 after deploy
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 37.4k
- Forks
- 3k
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 73
Description
To Reproduce
Human Slop
I would like to say I am loving your product and this is my first issue I do for any open source system; I have used it to solve a problem in my company and it is going well.
Second of all, I apologize for the AI slop coming after you, so I will explain it in human words; though the slop isn't bad at all. Basically, there is an app used by one of the team that basically continuously failed in a weird way. It was a compose application and the containers would build, Traefik dashboard says it's connected, everything looks dandy, but I always get Bad Gateway. This was very frustrating, since the application doesn't deterministically fail, but it fails sometimes and sometimes it doesn't, so I was super confused.
The issue was related to you guys' decision to keep both the dokploy network and the default compose network. What happened was, one of the applications was using NextJS, NextJS was asking for process.env.HOSTNAME. Docker would resolve that to the container name. After that, Node would go and try to find an IP address for the container in /etc/hosts and find both addresses, the one from dokploy network and the default compose network and it would choose one of them, and therefore, non-deterministic failure.
AI SLOP:
To Reproduce
- Any Next.js app built with output: "standalone", in a Dockerfile that does not set ENV HOSTNAME (many guides omit
it), deployed as a Docker Compose service. - Attach a domain to the service. Dokploy attaches the service to both dokploy-network and the project's default
network (addDokployNetworkToService, the #3562 fix), and routes Traefik to the dokploy-network IP. - Deploy repeatedly. Some deploys serve 200; others return 502 permanently (never self-heals) until the next deploy
re-rolls it.
Mechanism (each step independently verified)
- Docker injects HOSTNAME= as a real env var: docker run --rm node:22-slim printenv HOSTNAME → prints the id.
- Next's generated standalone server.js binds it: const hostname = process.env.HOSTNAME || '0.0.0.0'
(next/dist/build/utils.js). So in Docker it calls listen(PORT, "") — not 0.0.0.0. - On a dual-network container, /etc/hosts contains two entries for the container's own hostname (one per network). Node's dns.lookup returns one address:
172.20.0.2 a9ee63ee8c33
172.21.0.2 a9ee63ee8c33
dns.lookup(HOSTNAME, {all:true}) → both; plain lookup → one
- So each new container binds exactly one interface, effectively at random. If the pick is the dokploy-network IP → site works. If it's the default-network IP → Traefik dials the dokploy-network IP and gets connection refused → 502 forever. Traefik's API meanwhile shows router enabled and the server UP, and the deployment is done — nothing looks wrong anywhere.
Live-incident evidence
- Traefik service backend IP exactly matched the container's dokploy-network IP — still 502.
- From a neighbor container on dokploy-network: </dev/tcp//3001 → connection refused (an RST, so packets were
delivered — not an overlay/dataplane fault). - Inside the failing container: </dev/tcp/127.0.0.1/3001 → also refused, while the process was healthy and serving on
the other network's interface. - Redeploying "fixes" it only by re-rolling the bind; we measured one incident of 1 real build + 8 blind redeploys
before it landed.
Current vs. Expected behavior
Current: silent, intermittent, permanent 502 with all dashboards green. Expected: at minimum a docs note; ideally a post-deploy reachability probe of the domain target (:) surfacing "domain target unreachable" instead of a silent 502.
Current vs. Expected behavior
Current vs. Expected behavior
Current: silent, intermittent, permanent 502 with all dashboards green.
Expected: at minimum a docs note; ideally a post-deploy reachability probe of the domain target (:) surfacing "domain target unreachable" instead of a silent 502.
Environment: Dokploy v0.29.13, Docker Compose (git provider), same server as Dokploy, Traefik v3, Next.js 16 standalone, node:22-slim base on a Ubuntu Box.
Workaround: ENV HOSTNAME="0.0.0.0" in the Dockerfile runner stage (the official Next.js example Dockerfile sets this). Fixed it deterministically for us.
Related: #4807 (same dual-network attachment from #3562, complementary Traefik-side failure mode), #3945 (same symptom, mechanism unidentified — some reports there may be this), #3562 (origin of the dual attach).
Provide environment information
Environment: Dokploy v0.29.13, Docker Compose (git provider), same server as Dokploy, Traefik v3, Next.js 16 standalone, node:22-slim base on a Ubuntu Box.
Which area(s) are affected? (Select all that apply)
Docker Compose, Traefik
Are you deploying the applications where Dokploy is installed or on a remote server?
Same server where Dokploy is installed
Additional context
I never looked at your guys' code, but I am down to try to fix it.
Will you send a PR to fix it?
Maybe, need help
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the Compose network attachment entry point named addDokployNetworkToService and trace how deployed services are exposed through Traefik. Reproduce the dual-network Next.js standalone case, then determine whether the change should be documentation or a post-deploy domain-target reachability check. Done means the failure is surfaced clearly rather than remaining a silent 502.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, docker-compose, nextjs, typescript
- Domain
- devops, infrastructure
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100