Skip to content

Reverse proxy and HTTPS

Pierre edited this page Oct 29, 2026 · 1 revision

Zukan serves the web UI at / and the API at /api on the same origin. The current client paths assume root hosting; a subpath such as /zukan/ is not a documented deployment mode.

Public settings

TCG_PUBLIC_URL=https://cards.example.com
TCG_COOKIE_SECURE=true
TCG_FORWARDED_ALLOW_IPS=REPLACE_WITH_TRUSTED_PROXY_ADDRESS_OR_NETWORK

TCG_PUBLIC_URL determines OIDC callbacks and logout return addresses. It must be the URL users actually open, including the correct scheme and any nonstandard port.

TCG_FORWARDED_ALLOW_IPS is substituted by Compose into Uvicorn's FORWARDED_ALLOW_IPS. Set the proxy IP/network as seen from the API container. Trusting a header is meaningful only when requests really arrive through that trusted proxy. Avoid * on a backend reachable by arbitrary clients.

Caddy running on the host

An illustrative Caddy site block is:

cards.example.com {
    reverse_proxy 127.0.0.1:8000
}

Bind the API host port to loopback using a local Compose override. On Compose versions supporting !override:

services:
  api:
    ports: !override
      - "127.0.0.1:8000:8000"

Save as compose.override.yaml, then inspect the merged docker compose config locally before applying it. Do not assume a second ports list automatically replaces the original one: ordinary Compose merging can preserve the public mapping. !override requires a compatible Compose plugin. Alternatively edit the deployment's port mapping directly and preserve that change during updates.

A host-to-container connection may appear under a Docker gateway address, not 127.0.0.1; determine the observed peer before setting forwarded-header trust.

Caddy in a container

Place Caddy and the API on a shared Docker network and use the API's network alias and container port, for example api:8000 when they are services on the same network. 127.0.0.1 inside Caddy refers to the Caddy container itself.

For separately managed Compose projects, explicitly attach both services to the same external network and use a unique network alias. Keep the database on a private network. Configure trust for the proxy's actual network address or narrowly scoped shared subnet.

Certificates and proxy behavior

Serve the full certificate chain and the correct hostname. Android reports missing intermediates and hostname mismatch distinctly. The identity provider also needs a valid, reachable TLS endpoint for both the user's browser and the Zukan backend.

Preserve the original host and forwarded scheme/client information using the proxy's normal reverse-proxy behavior. Do not cache authenticated API responses or strip cookies. Static assets under /assets are content-hashed and have long cache headers; the SPA shell is served with no-cache.

Verify the deployment

  1. Open the public root and /api/health.
  2. Sign in; navigate between pages to verify cookie persistence.
  3. Open a card image and test direct navigation to a card page.
  4. If SSO is configured, check the callback URI shown at the provider.
  5. Connect Android using the public hostname and verify the certificate chain.
  6. Confirm the API port is reachable only through the access path you intended.

Configuration changes need container recreation: docker compose up -d api worker. A plain restart does not replace environment values already attached to a container.

Implementation references

Clone this wiki locally