Set up TLS

Serve the team server and the runner over HTTPS: Caddy in compose, an Ingress, Gateway or the pod itself in Kubernetes.

The desktop app only talks to a team server or a runner over HTTPS (plain HTTP is accepted only to the same computer). Both programs refuse to listen on a non-loopback address without a certificate, unless they are told a TLS proxy is in front (--allow-plain-http).

Where TLS can end

SetupTLS ends atProgram setting
docker composeCaddyservers on plain HTTP on the internal backend network
Kubernetes with an Ingress or a Gatewaythe controller or gatewaypod on plain HTTP (OXYSDB_SERVER_ALLOW_PLAIN_HTTP)
Kubernetes, tls.enabledthe pod--tls-cert / --tls-key
a plain hostthe program--tls-cert FILE --tls-key FILE (or OXYSDB_SERVER_TLS_CERT/_KEY, OXYSDB_RUNNER_TLS_CERT/_KEY)

Certificates are reloaded when their files change (checked at most once a second, for new connections): a renewed certificate is served without a restart. A renewed pair that does not load is logged and the previous one kept.

docker compose (Caddy)

Set in .env:

OXYSDB_TLSCertificate
internal (default)Caddy’s own CA. Export its root (/data/caddy/pki/authorities/local/root.crt in the caddy container) and give it to the clients as CA certificate file
an e-mail address, with OXYSDB_SITE_ADDRESS=oxysdb.example.comACME (Let’s Encrypt or ZeroSSL). The name must resolve to the host and port 80 be reachable: OXYSDB_HTTP_PUBLISH=80, OXYSDB_HTTPS_PUBLISH=443

To use your own certificate, replace the tls line of caddy/Caddyfile.single or caddy/Caddyfile.ha with tls /certs/fullchain.pem /certs/key.pem and mount the files read-only into the caddy service.

To encrypt the hop between Caddy and the servers too, give the servers a certificate (OXYSDB_SERVER_TLS_CERT, OXYSDB_SERVER_TLS_KEY: paths of mounted secrets) and point Caddy at https://server-1:8443 with a tls_trust_pool.

Kubernetes

  • Ingress (ingress.enabled): needs ingress.tls (or ingress.allowInsecure when TLS ends in front of the controller) and server.trustedProxies set to the controller’s pod CIDR; the chart refuses either missing. ingress.certManager.clusterIssuer (or issuer) annotates it for cert-manager.
  • Gateway API (httpRoute.enabled, parentRefs, hostnames): TLS on the Gateway; set server.trustedProxies to the gateway’s pods. For HTTPS up to the pod, add a BackendTLSPolicy for your Gateway implementation.
  • On the pod (tls.enabled): tls.existingSecret, or a cert-manager Certificate with tls.certManager.enabled, issuerRef, dnsNames (duration 2160h and renewBefore 360h by default). Probes switch to HTTPS and the nginx Ingress gets backend-protocol: HTTPS (ingress.nginxBackendHttps).

The runner subchart has the same tls.* and ingress.* values.

Post-quantum key exchange

Both programs and the desktop offer the hybrid key exchange X25519MLKEM768 (ML-KEM-768 with X25519) first, and accept a classical one from an older client. Once every desktop is upgraded, require it: --tls-pq require (or OXYSDB_SERVER_TLS_PQ=require, OXYSDB_RUNNER_TLS_PQ=require) accepts only X25519MLKEM768 over TLS 1.3, and the desktops’ network setting pqTls: require (network.configure) refuses a server without it, and a team server reached over http:// other than on loopback. Where TLS ends at a proxy, the proxy chooses the key exchange: use one that offers X25519MLKEM768 (nginx or Caddy built with OpenSSL 3.5 or Go 1.24 and later, a recent Envoy). --tls-pq needs --tls-cert and --tls-key: a program that speaks plain HTTP behind the proxy refuses to start with it rather than ignore it.

Clients with a private CA

In the desktop app, give the CA’s PEM file in CA certificate file on the Team Sharing sign-in form and on Edit › Preferences › External tools › Remote Task Runner. The app reads a CA file of at most 1 MiB.

Troubleshooting

SymptomFix
The program refuses to start on 0.0.0.0give --tls-cert/--tls-key, or --allow-plain-http behind a TLS proxy
Every user shares one sign-in throttleserver.trustedProxies (or OXYSDB_SERVER_TRUSTED_PROXIES) does not name the proxy
ACME failsthe DNS name does not point to the host, or port 80 is not reachable
Certificate error in the appthe CA is private: give its PEM file to the app