nix(gateway): self-signed TLS as the implicit default, deprecate the toggle

Make self-signed TLS the gateway's default whenever no external TLS source
is configured, and deprecate the explicit selfSignedTls toggle. Self-signed
is now derived as `tls.certDir == null && !tls.acme.enable`, so an operator
selects a TLS mode by setting tls.certDir or tls.acme — or neither, for the
self-signed default. There is no http-only mode: matrix discovery hardcodes
https, so the gateway always terminates TLS.

The selfSignedTls option is kept as a deprecated no-op (warns when set to
false) so existing configs still eval. The two selfSignedTls mutual-
exclusion assertions and the HSTS-requires-TLS assertion are dropped — they
are impossible or vacuous now that self-signed is the floor. The hive-tls
module and the forge ROOT_URL scheme consume the derived value: the gateway
always terminates TLS, so behind the gateway the forge is always advertised
over https.

Updates docs/gateway.md (TLS-modes table, self-signed section, the removed
http-only section, firewall + discovery notes). Eval-proven: default →
self-signed (hive CA active, https ROOT_URL); tls.certDir → CA inactive;
selfSignedTls=false → deprecation warning fires.
This commit is contained in:
atlas 2026-06-17 20:26:03 +02:00 committed by mara
commit 1a3f82a459
4 changed files with 112 additions and 109 deletions

View file

@ -14,15 +14,14 @@ let
# forgejo `DOMAIN` setting AND the gateway vhost server-name, so
# ROOT_URL just uses it directly (dropping the port suffix on the
# canonical port for the scheme — 80 for http, 443 for https). The
# scheme + port follow what the gateway actually serves: `https` when
# the gateway terminates TLS (a self-signed cert or an external
# `tls.certDir`), `http` otherwise — advertising `http://` for a TLS
# gateway produces broken clone links + mixed-content redirects.
# gateway always terminates TLS now — self-signed is the implicit floor
# when neither `tls.certDir` nor ACME is configured — so behind the
# gateway the forge is always advertised over `https` on `httpsPort`.
# When direct (gateway off or `behindGateway = false`), keep the
# host:httpPort shape so direct browser access still produces correct
# links. Operators can still override via `cfg.rootUrl` for bespoke
# shapes.
gatewayTls = gatewayCfg.selfSignedTls || gatewayCfg.tls.certDir != null;
gatewayTls = true;
defaultRootUrl =
if cfg.behindGateway then
let
@ -157,11 +156,11 @@ in
(default), `ROOT_URL` is derived from `cfg.domain` + gateway
state, including the scheme:
- `behindGateway = true` `https://''${cfg.domain}/` when the
gateway terminates TLS (`gateway.selfSignedTls = true` or
`gateway.tls.certDir` set), otherwise `http://''${cfg.domain}/`.
A non-canonical gateway port (`gateway.port` for http,
`gateway.httpsPort` for https) is appended as `:<port>`.
- `behindGateway = true` `https://''${cfg.domain}/`. The gateway
always terminates TLS (self-signed is the implicit floor when no
`gateway.tls.certDir` / ACME is set), so the forge is always
advertised over https. A non-canonical `gateway.httpsPort` is
appended as `:<port>`.
- `behindGateway = false` `http://''${cfg.domain}:''${cfg.httpPort}/`
The TLS scheme is derived automatically now, so you only need to