Docs
Domains and proxy
Routing with Traefik per server (nginx is legacy), TLS modes, the base domain, custom domains, redirects and a note on Cloudflare.
Two routing modes per server
Each server has two settings, proxy and tls_mode. Change them on the server's page in the dashboard (open a server from the Servers page). New servers start on traefik.
proxy = 'traefik'(the supported mode): apps are routed by Traefik labels that powder keeps in its own generateddocker-compose.powder.ymlunder/var/lib/powder/compose/(your file is never edited). This turns on custom domains, traffic stats (read from the Traefik access log), atomic rollback, snapshots, label sync on every deploy, and www and path redirects.proxy = 'nginx'andproxy = 'nginx-container'(legacy): a host nginx (or nginx in a container) plus a host port, with redirects as managed nginx server blocks. These still work for servers that already use them but new servers should use Traefik: custom domains, traffic stats, atomic rollback, snapshots and path redirects need it.
tls_mode is only read when proxy = 'traefik':
acme(default): a certificate resolver issues certificates over HTTP-01 on the first request.origin-cert: the router uses TLS without a resolver, for servers that serve a Cloudflare origin certificate from Traefik's default store.
Health path for Traefik
Traefik's service health check probes the path of the app's health URL, with scheme, host and query dropped, or / when unset. That path must answer 2xx or 3xx without a Host header, otherwise Traefik marks the service unhealthy and serves 503. Set the health URL to a path that does, for example /api/health.
Base domain
Each app gets a default host <app>.<base_domain>, and each preview gets pv-<app>-<branch>.<base_domain>. Set the base domain on the server's page: a bare lowercase hostname such as apps.example.com, without a scheme or wildcard.
Point a wildcard DNS record *.apps.example.com at the server's public IP. On acme, each host gets a certificate on its first request. On origin-cert, the default-store certificate must cover *.apps.example.com. "check DNS" on the server's page resolves a random name under the base domain and compares it with the server's ingress IP. Behind a Cloudflare proxy it shows a mismatch, because the record answers with Cloudflare's addresses.
With no base domain, an app has no default host: it gets no router label until you attach a custom domain, uptime checks need a health URL or a live custom domain, HTTP crons need a live custom domain, snapshots are unavailable, and the webhook ignores branch pushes (previews need the base domain).
Custom domains
On a project's page choose domains, then add a domain, and enter the hostname. Set the DNS record at your DNS provider and click verify.
- A record pointing at the server's public IP (the server's ingress IP from its page, else the server's host when it is an IP).
- CNAME to
<app>.<base_domain>, preferred for subdomains.
On success powder adds the host to the app's Traefik router rule and recreates the container. The certificate is issued on the first HTTPS request, usually within about 30 seconds. The label writer emits one Host(...) || Host(...) rule per app; wildcards and other non-Host rules belong in the file provider.
Redirects
- nginx servers (legacy): www-to-apex and apex-to-www redirects are managed from the Domains page as nginx server blocks.
- Traefik servers: redirects are written as a Traefik file-provider fragment at
/opt/infra/traefik/dynamic/redirects-<app>.yml. Before each write, powder checks withdocker inspect traefikthat the Traefik container is namedtraefikand runs the file provider on a directory mounted from/opt/infra/traefik/dynamicwith watch on (--providers.file.directory=...and--providers.file.watch=true). If not, the apply fails with a message naming the missing setting. A Traefik with only the Docker provider cannot take www or path redirects until you add the file provider.
Cloudflare
Cloudflare is optional. If a domain is proxied through Cloudflare, create the wildcard record as proxied and use tls_mode = 'origin-cert' with a Cloudflare origin certificate. HTTP-01 issuance needs the request to reach the server directly, so a proxied host cannot rely on acme. DNS-only records work with either mode.