Domains and TLS
Attaching a hostname, why DNS is verified before a router is attached, certificate states, and the wildcard base domain.
Ingress is Traefik v3, in a compose project the control plane owns and starts. It runs with the Docker provider only — every route comes from a container label, so the only way to publish something is to deploy it.
Turn it on with PROXY_ENABLED=true, PROXY_ACME_EMAIL, and SERVER_PUBLIC_IP. The
installer sets all three.
Attaching a hostname
Add the hostname on the application. The portal shows the exact A
record to create.
Press Check DNS. The platform resolves the hostname and compares it to this server's public address. Only when they match does a router get attached and a certificate get requested.
This order is not ceremony
Attaching a router before DNS resolves makes Traefik ask Let's Encrypt for a certificate it cannot validate. Production allows five failures per hostname per hour — get it wrong and you are locked out of your own certificate for an hour.
A hostname that stops resolving to this server is un-verified on the next check and its router is dropped. That is by design: a router for a hostname somebody else now controls is worse than no router.
Certificate states
| State | Meaning |
|---|---|
AWAITING_DNS | The hostname does not resolve here yet. No router, no certificate request. |
PENDING | Issuance is in flight. More than a few minutes here means it is failing. |
ACTIVE | Issued and serving. |
FAILED | Issuance failed. See troubleshooting. |
The portal reads this state from Traefik's own acme.json rather than assuming it.
Staging
PROXY_ACME_STAGING=trueLet's Encrypt's staging directory has far looser limits and issues certificates browsers do not trust. Develop against it, and remember to switch back.
Once a hostname is attached
The application is no longer published to the internet on a numbered port. It keeps a loopback-only binding on the server so the platform can health-check it, and every external request arrives through Traefik.
PROXY_HTTPS_REDIRECT (default true) sends plain HTTP to HTTPS. It only takes effect once
ACME is configured — redirecting to a port serving nothing would turn every application into
an error.
A wildcard base domain
PROXY_BASE_DOMAIN=apps.example.comWith this set, every application also answers on <slug>.apps.example.com with no DNS step
per application, because the wildcard record already resolves. Point *.apps.example.com at
the server once and every future application is reachable the moment it deploys.
What is not exposed
- The Traefik dashboard. Ever.
- The Docker socket, which Traefik mounts read-only.
proxy.service.spec.ts asserts both.
Certificates on disk
They live in an acme.json volume belonging to the sthora-proxy compose project, at
mode 0600. Back it up — losing it means re-issuing everything, against the same rate limit
that makes the DNS-first order matter.
One proxy per managed server. A router on the control plane cannot serve a
container on a customer's VPS, so GET /proxy reports ingress and certificate
state for one server, named by an optional serverId query.