How it works
Three journeys worth understanding
If you can follow a request, a deploy and a reboot through this server, you can debug almost anything that happens on it.
Journey 1
A request, from browser to container
- DNSEvery
*.persmon.cloudname — and the client domains that CNAME to it — points at the same IPv4 address. The hostname is the only thing that distinguishes one app from another. - Firewallufw lets the packet in on 443. fail2ban has already dropped anyone who was brute-forcing SSH.
- TraefikTerminates TLS with the site's Let's Encrypt certificate, reads the
Hostheader, and looks up which container declared that hostname in its Docker labels. - Private networkThe request crosses a Docker bridge network that only that app and Traefik are attached to. The app's database sits on the same network and is unreachable from anywhere else.
- AppThe container answers; Traefik streams the response back. Nothing on the box ever sees the internet directly except Traefik.
Journey 2
A deploy, from git push to live
- PushCode lands on the main branch of a repository the Coolify GitHub App can see.
- WebhookGitHub calls Coolify. Coolify queues a build through Redis (two builds can run at once).
- BuildCoolify clones the repo on the server and builds an image with BuildKit (Nixpacks/Railpack or your Dockerfile).
- SwapThe new container starts on the app's network; Traefik picks up its labels; the old container is stopped. Health checks decide when traffic moves.
- ObserveLive build logs in Coolify, runtime logs in Dozzle, resource graphs in Beszel, and an Uptime Kuma check within a minute.
Journey 3
A reboot, and why the firewall matters
- KernelThe new kernel boots; Docker starts; every container with
restart: unless-stoppedcomes back — but each one gets a fresh IP on its bridge network. - Lesson from 22 SepThe firewall used to allow web traffic to the proxy by its old IP (10.0.1.6). After the reboot the proxy was 10.0.1.8, the rule matched nothing, and every site was unreachable from outside while working perfectly from inside. The fix is a rule by port, not by IP.
- CertificatesTraefik re-reads
acme.json; nothing needs to be re-issued. - CronBackups and reseeds resume on their next slot; a missed heartbeat would alert via Telegram.
- VerifyThe runbook on the Operations page has the four commands to run.
Reference
The map again
Entry pointContainer or groupDashed = internal only