Sthora
Deploying applications

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.

Create that record at your DNS provider.

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

StateMeaning
AWAITING_DNSThe hostname does not resolve here yet. No router, no certificate request.
PENDINGIssuance is in flight. More than a few minutes here means it is failing.
ACTIVEIssued and serving.
FAILEDIssuance failed. See troubleshooting.

The portal reads this state from Traefik's own acme.json rather than assuming it.

Staging

PROXY_ACME_STAGING=true

Let'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.com

With 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.

On this page