DocsInfrastructure
Proxy & domain
Turning on the Traefik reverse proxy, pointing domains at applications, automatic HTTPS from Let's Encrypt, and checking DNS.
- Proxy
- Traefik v3, the aoox-proxy container
- HTTPS
- Let's Encrypt HTTP-01 automatic per host, or your own certificate
- Scope
- The aoox host and each remote server
One request's flow
- 01browserhttps://app.example.com
- 02DNSA record → server IP
- 03Traefik :443the <app>-secure router, ACME certificate
- 04containerthe aoox network → :<container port>
Traefik uses the docker provider: it reads labels on application containers and only exposes the ones with a label (exposedbydefault=false). There's no configuration file to edit — aoox writes the labels when a container is created.
Provisioning the reverse proxy
Traefik runs per daemon: one on the aoox host, and optionally one on each remote server with its own port and ACME email. The steps below are for the host.
Make sure ports 80/443 are free on the host
ss -ltnp | grep -E ':80 |:443 ' # should be emptyThe ports can be changed via
PROXY_HTTP_PORT/PROXY_HTTPS_PORTin.env.dist, but Let's Encrypt HTTP-01 needs port 80 and browsers expect 443.Set PROXY_ACME_EMAIL (for HTTPS)
.env.distPROXY_ACME_EMAIL=you@example.com PROXY_ACME_STAGING=false # true while testing, to avoid the rate limitWithout an email, Traefik runs without an ACME resolver: domains are served over http only and the HTTPS toggle in the UI is disabled. Changing this value after provisioning → remove the proxy then provision it again.
Settings → Reverse proxy (Traefik) → provision (owner)
The
aoox-proxycontainer is created on theaooxnetwork with theaoox_proxy_acmevolume for certificates. The card shows a Running status and whether ACME is active.
Adding a domain to an application
Point DNS
DNSapp.example.com. A 203.0.113.10 # or app.example.com. CNAME server.example.com.DNS can be set up later — aoox doesn't block on it. But a certificate can only be issued once DNS is correct.
Application page → Domain tab → add
Fill in the Hostname (
app.example.com, no scheme/path) and turn on HTTPS if the proxy has ACME. The container is recreated with the new Traefik label — no build. One application can have several hostnames.Clear the Host port (recommended)
With a domain, a host port isn't needed; clearing it enables blue/green deploys and closes off direct IP:port access.
Check DNS
The DNS check button on the domain row compares the resolved result with the expected IP —
PUBLIC_IPif set, auto-detected via ipify (cached 10 minutes), or the remote server's host:Badge Meaning Action okPoints at this server. — mismatchResolves to a different IP. Fix the A/CNAME record; wait out the TTL. unresolvedNo record yet. Create the record with your DNS provider. ?The server's public IP is unknown. Set PUBLIC_IPin.env.dist(server behind NAT/Cloudflare).
When another container already uses the domain
If a container on the same daemon already routes the host (typically a leftover of a project deleted on an older version, or another stack), two routers answer for it and requests are split between them. The Domain tab shows a warning on that domain naming the container, and adding the domain returns the same information. Nothing is blocked. When the container is a leftover, the warning points to the Docker page (Details), where the owner can remove it. The deployment log also notes it.
How HTTPS works
| Router | Entrypoint | Created when | Does |
|---|---|---|---|
<app> | web (:80) | Always | Serves http for hosts without HTTPS |
<app>-secure | websecure (:443) | When HTTPS is on | TLS via the le certresolver |
<app>-redirect | web (:80) | HTTPS on + ACME set up | 301 http → https |
- A certificate is requested via HTTP-01 the first time the host is reached; Let's Encrypt must be able to reach port 80 on the server from the internet. Traefik renews it automatically.
- The http → https redirect is only created when ACME is active, so that without
PROXY_ACME_EMAIL(dev) a host is still reachable over http, rather than redirected to Traefik's self-signed certificate. - A container that becomes
unhealthyis automatically dropped from the router (404) — that's what the health check is for.
Behind Cloudflare
- The DNS check shows mismatch because the hostname resolves to a Cloudflare IP — ignore it if it's proxied on purpose. When issuing a certificate for the first time, set the record to DNS only first so HTTP-01 can reach the server, then switch proxying back on.
- Cloudflare's SSL mode must be Full (strict) so the origin is served over Traefik's HTTPS; Flexible mode causes a redirect loop with the
-redirectrouter.
Don't want Let's Encrypt? Upload your own certificate (corporate CA, wildcard, Cloudflare Origin CA) and pick it per domain on the Domain tab — see Custom SSL certificates. It applies to application domains; the panel's domains keep using ACME.
Need basic auth, security headers, rate limiting, an IP allowlist or a www redirect for a domain? Write your own Traefik middleware (or use a preset) and attach it per domain on the Domain tab — see Proxy configuration.
Operations
| Action | Effect |
|---|---|
| Maintenance mode | Show a 503 page on all of an application's domains without stopping it — see Applications. |
| Remove a domain | The container is recreated without that host's label; the certificate stays on the ACME volume. |
| Toggle HTTPS | The container is recreated; the -secure/-redirect routers are added/removed. |
| Remove the proxy (owner) | All domains stop being served; application containers aren't touched. You'll be asked about the ACME volume. |
| Change PROXY_ACME_EMAIL / port | Change .env.dist → remove the proxy → provision it again. |
Notes
- Applications on a remote server use that server's own proxy: provision it from the server card (port + ACME email), then point DNS at that server's IP — see Remote servers. Without a proxy there, use a host port instead.
- Compose stacks use a domain per service — see Compose stacks. A compose file can also carry its own
traefik.*labels, as long as it joins theaooxnetwork. - The domain for the aoox panel itself is set via env, not the Domain tab — see Domain for the panel.
- Local dev uses ports 8088/8443 (80 is often taken); production uses 80/443. Don't mix values between environments.
Common pitfalls
| Symptom | Cause & fix |
|---|---|
| Domain tab: Proxy not running | Provision it in Settings first. |
| HTTPS toggle disabled | PROXY_ACME_EMAIL was empty at provision time. Fill it in, remove the proxy, provision again. |
| 404 page not found from Traefik | The container isn't healthy yet, or the domain was added but the container hasn't been recreated (check the deploy log). |
| Self-signed certificate / TRAEFIK DEFAULT CERT | ACME failed: DNS isn't correct yet, port 80 is closed, or a rate limit was hit. Check the aoox-proxy container's log in the terminal; test with PROXY_ACME_STAGING=true. |
| Redirect loop | Cloudflare in Flexible mode, or another reverse proxy in front terminating TLS. Use Full (strict), or turn off HTTPS in aoox. |
| Works via IP:port but not via the domain | A host port still being set isn't a problem — check DNS and that the proxy is Running. |
Next steps
Found a mistake? Edit this page on GitHub ↗