Update architecture specs to reflect live deployment findings and fix two bugs
Architecture updates based on gaps discovered during live deployment testing: - ADR-023: HTTP/2 client-facing support via ALPN-based protocol detection. The spec previously said HTTP/2 was out of scope, but the deployment revealed that modern browsers negotiate HTTP/2 via ALPN. The proxy now correctly detects the negotiated ALPN protocol and uses the appropriate HTTP server builder (http2::Builder for h2, auto::Builder for http/1.1). Upstream connections remain HTTP/1.1. Host resolution now falls back to URI host for HTTP/2 :authority pseudo-headers. - ADR-024: ANSI-disabled logging. All tracing-subscriber layers now use with_ansi(false) to prevent ANSI escape codes in log output, which broke fail2ban regex matching in Docker deployments. Also documents the fail2ban regex anchor fix (^RATE_LIMIT → RATE_LIMIT). Bug fixes found by architecture review: - Fix missing ALPN protocols in manual TLS mode. build_manual_server_config and build_multi_domain_server_config did not set alpn_protocols, meaning manual TLS mode could not support HTTP/2. Added h2 and http/1.1 ALPN entries to both functions (acme-tls/1 only in ACME mode). - Fix missing with_ansi(false) in JSON log format. The init_json function with file output did not disable ANSI on stdout or file layers, which would break fail2ban in production JSON logging mode. Other spec updates: - All document statuses updated from draft to reviewed - proxy.md: documented Server header removal, upstream HTTPS client, two-phase timeout enforcement, HTTP/2 host resolution, connect timeout - tls.md: documented ALPN configuration differing by mode (ACME vs manual) - overview.md: added HTTP/2 client-facing support to scope, updated crate deps (hyper-rustls, rustls-native-certs, hyper-util), clarified out-of-scope - config.md: fixed http_port type (u16→u32) to match implementation, added ANSI-disabled note for LoggingConfig - operations.md: documented ANSI-disabled logging, fail2ban regex anchor - open-questions.md: updated OQ-09 resolution (connect timeout fully implemented), OQ-10 (C2 bug is fixed)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-06-11
|
||||
status: reviewed
|
||||
last_updated: 2026-06-12
|
||||
---
|
||||
|
||||
# TLS Termination
|
||||
@@ -175,15 +175,33 @@ maps SNI hostnames to certificate/key pairs loaded from disk.
|
||||
For ACME mode, the `ServerConfig` is built with `with_cert_resolver()`, passing
|
||||
the `ResolvesServerCertAcme` resolver. The ACME configuration includes the
|
||||
domains listed in that listener's `acme_domains`, and the resolver manages the
|
||||
certificate. The ACME TLS-ALPN-01 protocol identifier (`acme-tls/1`) must be
|
||||
registered in the `alpn_protocols` list so the server can respond to
|
||||
TLS-ALPN-01 challenges.
|
||||
certificate.
|
||||
|
||||
The TLS `ServerConfig` advertises ALPN protocols to enable HTTP/2 negotiation.
|
||||
The ALPN configuration differs by TLS mode:
|
||||
|
||||
- **ACME mode**: `h2`, `http/1.1`, and `acme-tls/1`. The `acme-tls/1` entry is
|
||||
required for TLS-ALPN-01 challenge verification during certificate provisioning.
|
||||
- **Manual mode** (single-cert and multi-domain/SNI): `h2` and `http/1.1` only.
|
||||
The `acme-tls/1` entry is not included because manual mode does not use ACME
|
||||
challenges.
|
||||
|
||||
After the TLS handshake, the proxy inspects the negotiated ALPN protocol to
|
||||
select the appropriate HTTP server: `h2` triggers
|
||||
`hyper::server::conn::http2::Builder`, while `http/1.1` (or no ALPN) triggers
|
||||
`hyper_util::server::conn::auto::Builder`. See ADR-023 for details.
|
||||
|
||||
Both modes use the `aws_lc_rs` crypto provider with safe default protocol
|
||||
versions (TLS 1.2 and TLS 1.3).
|
||||
|
||||
## SNI-Based Certificate Selection
|
||||
|
||||
After the TLS handshake, the proxy inspects the negotiated ALPN protocol to
|
||||
determine whether to serve the connection as HTTP/2 or HTTP/1.1. If the client
|
||||
negotiated `h2` via ALPN, the proxy uses `hyper::server::conn::http2::Builder`;
|
||||
otherwise, it uses `hyper_util::server::conn::auto::Builder` with HTTP/1.1
|
||||
and upgrade support. See ADR-023 for details.
|
||||
|
||||
### Dedicated-IP Single-Domain (Multi-Config)
|
||||
|
||||
In the dedicated-IP model, each listener binds to its own IP address and serves
|
||||
@@ -305,6 +323,7 @@ All design decisions are documented as ADRs in [decisions/](decisions/).
|
||||
| [011](decisions/011-multi-domain-tls.md) | Multi-domain TLS config | Single SAN certificate covering all domains via rustls-acme |
|
||||
| [012](decisions/012-cipher-suite-restriction.md) | Restrict cipher suites | Match nginx scope: four ECDHE-AES-GCM suites for TLS 1.2, all TLS 1.3 suites |
|
||||
| [019](decisions/019-multi-config-listeners.md) | Multi-config listeners | `[[listeners]]` supporting both dedicated-IP and shared-IP deployment models |
|
||||
| [023](decisions/023-http2-client-facing.md) | HTTP/2 client-facing support | ALPN-based protocol detection; `h2` and `http/1.1` advertised |
|
||||
|
||||
## Open Questions
|
||||
|
||||
|
||||
Reference in New Issue
Block a user