Skip to content

TLS and Reverse Proxy

Tommi Grönlund edited this page Oct 23, 2026 · 3 revisions

Documentation for the image tag 1.0.0-rc1. See Versions for the documentation of a release.

TLS and Reverse Proxy

By default every service speaks plain HTTP, including the OIDC authority. That is fine on a trusted LAN. It is not fine on an untrusted network: bearer tokens and ACME account keys would cross it in the clear.

What can sit behind a TLS proxy

Service Behind a TLS-terminating proxy?
Web UI (8080), Identity (8081), API (8082) Yes
ACME (8083) No. Leave it out of the proxy. ACME clients sign the request URL into each request, and behind a proxy the service answers "URL mismatch". ACME runs plain HTTP, or terminates TLS itself (multi container)
EST (8084, multi container) Only a proxy that passes TCP through or forwards the client certificate. The EST container terminates TLS itself by default

Per-port, not per-subdomain

Qertum builds every advertised URL from one host name plus each service's port. A proxy therefore keeps the same shape: https://ca.example.com:8080, :8081, :8082, each forwarded to the container's port of the same number. Merging everything onto port 443 or onto subdomains is not supported.

Steps (single container)

  1. Run a TLS proxy (Caddy, Traefik, nginx) listening on 8080, 8081 and 8082 and forwarding to the container. A Caddy example:

    ca.example.com:8080 { reverse_proxy qertum:8080 }
    ca.example.com:8081 { reverse_proxy qertum:8081 }
    ca.example.com:8082 { reverse_proxy qertum:8082 }
    

    Run it as a second service on the same Docker network as qertum, and do not publish the container's own 8080–8082 to the host any more (the proxy owns those ports). Caddy's automatic HTTPS also needs port 80 reachable for its certificate challenge, or you supply your own certificates.

  2. Set QERTUM_HOST to the proxy's public host name.

  3. Switch the HTTP-transport flags back to their secure values:

    • IdentityService__DisableTransportSecurity=false
    • OpenIdConnect__RequireHttpsMetadata=true
    • Identity__RequireHttpsMetadata=true
  4. Add Services__webfrontend__https__0=https://<QERTUM_HOST>:<WEB_PORT>. Without it the web client keeps registering an http:// redirect URI and sign-in fails with a redirect-URI mismatch.

  5. Re-create the container.

The proxy must send X-Forwarded-Proto: https and preserve the original Host header (Caddy and Traefik do both by default; nginx needs proxy_set_header Host $host). The identity service builds its endpoint URLs from the incoming request's scheme and host.

Multi container

Set QERTUM_SCHEME=https in .env for web, identity and API behind a proxy. Never set it for ACME or EST. See Multi Container for ACME TLS.

Trusting the root

Clients reject certificates from Qertum until its root is installed as a trust anchor. Download the root from the onboarding page, the enrollment wizard, or GET /v1/ca/certificate (?format=pem, der or p7b), and install it on every relying party before pointing an ACME or EST client at the CA. Each client's TLS handshake fails until it is. Do not work around this with --insecure.

On ECDSA roots created by early versions, OpenSSL 3 may refuse the chain with "Certificate public key has explicit ECC parameters". Settings, Authority and qca ca info warn when the root is affected; the fix is to replace the CA and reissue.

Clone this wiki locally