Coolify setup lessons from shipping this site
Deploying dacforge.com on Coolify and Hetzner taught us four things a shell script install will not. A short field report.
- #coolify
- #devops
- #self-hosting
We ship clients on Coolify because it is the least sad path to running your own PaaS in 2026. You get Heroku-style ergonomics on a server you own, Docker underneath, and no seat-based pricing surprise in month eight. The install script is a one-liner. The production-ready install is not.
This site, dacforge.com, runs on Coolify on Hetzner. Setting it up took about a day of focused work. Here are the four gotchas that ate the most time, written up for anyone standing up their first Coolify box.
1. The port-80 trap
Coolify’s app settings default the “ports exposes” field to 3000. That default is right for a Node app. It is wrong for a static site served by nginx inside your container.
We deployed the first version of this site and got a polite 502 Bad Gateway from Traefik. The container was running. The nginx inside it was answering on port 80. Traefik was trying to reach it on port 3000. Nothing was listening there.
The fix is to set the app port to 80 in Coolify’s UI, matching where the in-container nginx actually listens. The UI does not surface this as a likely gotcha, so if you are deploying anything other than a Node app for the first time, check your container’s listen port against the Coolify field before you wonder why TLS termination hates you.
2. The HTTPS→HTTP→HTTPS redirect chain
The second 502 was more interesting. Every non-trailing-slash URL on the site went through two redirects:
GET https://dacforge.com/work → 301 → http://dacforge.com/work/ → 307 → https://dacforge.com/work/
Two hops. The first hop drops to plain HTTP for a microsecond before Traefik bounces it back. Google’s crawler tolerates one redirect, grudgingly tolerates two, and occasionally stops following after the first.
The cause was nginx emitting absolute redirects from inside the container. Traefik handles TLS termination upstream, so the nginx process sees the request come in as plain HTTP. When nginx issues a trailing-slash redirect, it writes the scheme it sees (http://) into the Location header. Traefik then has to re-redirect that to HTTPS.
The fix is a three-line addition to nginx.conf:
absolute_redirect off;
server_name_in_redirect off;
port_in_redirect off;
With those set, nginx emits relative redirects (just a path, no scheme). The browser carries forward whatever scheme the original request used, and the chain collapses to one hop. You need a custom nginx.conf copied into your Docker image; the default config the nginx:alpine base image ships with will not set these.
3. Cloudflare, proxy off
Cloudflare is lovely for DNS, a trap for TLS until you commit to it.
We put the domain on Cloudflare with the orange cloud off on every record. That tells Cloudflare to act as a dumb resolver: it answers DNS, it does not terminate TLS. Coolify and Traefik then see the real client IP, issue real Let’s Encrypt certificates via HTTP-01, and renew them quietly.
The alternative, proxy on, is not wrong but is not cheap. You have to flip Cloudflare’s TLS mode to Full (strict), make sure your origin cert is trusted or your upstream has a valid Let’s Encrypt cert that Cloudflare can verify, and accept that Cloudflare sits in every hot path. For a small site that is overhead for a benefit we do not currently need. If you are going to end up using Cloudflare’s WAF or Workers, flip it on deliberately. Otherwise leave it off and let Let’s Encrypt do its job without a proxy in the way.
4. The runbook is the part nobody writes
The thing we have had to rebuild from memory three times, and will never rebuild from memory again, is the runbook. A Coolify setup is not complete without:
- Which defaults in the UI are wrong for your case. Port 80 vs 3000 is one. Health checks are another (Coolify’s default interval is aggressive; turn it down for slow-cold-starting apps).
- How to deploy a new app from scratch. One page, screenshots, the exact order of clicks.
- How to roll back a bad release. Coolify keeps previous deploys; there is a button. Know where it is before you need it.
- Where the logs actually live. Application logs in the Coolify UI; Docker logs on the server; Traefik access logs in the Traefik container. All three have a reason to be consulted; none of them is the default place you will look.
This is the part most consultants skip and most self-installers learn the expensive way. If you are setting up Coolify for yourself, write the runbook for the you of six months from now who has forgotten how TLS renewal works.
That is most of it
Coolify is a small, opinionated, genuinely nice PaaS. The install script does the install; the gotchas above are what it does not warn you about. If you want help landing your own setup cleanly, our Coolify setup consultant engagement is the one-block version of this post.
← All writing