Skip to content

Document deploying behind Coolify - #14

Merged
Loa212 merged 1 commit into
mainfrom
docs/coolify-deploy
Jul 30, 2026
Merged

Document deploying behind Coolify#14
Loa212 merged 1 commit into
mainfrom
docs/coolify-deploy

Conversation

@Loa212

@Loa212 Loa212 commented Jul 30, 2026

Copy link
Copy Markdown
Owner

What changed

Why

Coolify derives the Traefik backend port by parsing it out of the domain string, in bootstrap/helpers/docker.php:

$port = $url->getPort();                    // from the DOMAIN, not from the compose file
if (is_null($port) && ! is_null($onlyPort)) {
    $port = $onlyPort;
}
...
if ($port) {                                // no port found ⇒ no backend label at all
    $labels->push("traefik.http.services.{$https_label}.loadbalancer.server.port=$port");
}

With a domain of https://nudo.example.com and no port, the generated labels contain routers matching the hostname and no loadbalancer.server.port. Traefik matches the request, has no backend, and answers 502 — in front of a container that started cleanly and passed its healthcheck, which is what makes this hard to place from the symptom.

Worth stating explicitly in the docs because the obvious candidates all look right and none of them work: expose, a published ports mapping, and the Connect To Predefined Network toggle. None is an input to the code above.

The section also covers NUDO_BASE_URL, which is a second, quieter failure: auth.rs:152 derives the session cookie's Secure flag from the scheme alone, so left at the http://localhost:3000 default behind HTTPS the login page renders and the session silently fails to persist. It is also the base for webhook callback URLs (webhook.rs:347).

On the expose comment

#13 added expose with a comment claiming Coolify reads it to learn the port. The source above shows it does not. The key is kept — stating the dashboard's port in the file a reader is looking at earns its line — but the stated reason was wrong and would send the next person down the same path.

Validation

  • NUDO_SECRET_KEY=validation-only docker compose config --quiet
  • re-verified both NUDO_BASE_URL claims against crates/web/src/auth.rs, crates/web/src/routes/auth.rs, crates/web/src/webhook.rs
  • git diff --check; heading order confirmed (### Docker### Coolify### Binaries)

Coolify decides the Traefik backend port by parsing it out of the domain
string — `https://nudo.example.com:3000` — and emits the label naming that
port only when it finds one. Without it the generated config has a router
matching the hostname and no service behind it, so the proxy answers 502 in
front of a container that started and passed its healthcheck. Nothing about
the compose file changes that, which is what makes it worth writing down:
`expose`, a published `ports` mapping and the predefined-network toggle all
look like the thing to reach for and none of them are.

Also corrects the comment on `expose` added in #13, which claimed Coolify
reads that key to learn the port. It does not. The key is kept because
stating the dashboard's port in the file is worth a line on its own, but the
reason given for it was wrong.
@Loa212
Loa212 merged commit 0d22237 into main Jul 30, 2026
3 checks passed
@Loa212
Loa212 deleted the docs/coolify-deploy branch July 30, 2026 18:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant