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,5 +1,5 @@
|
||||
---
|
||||
status: draft
|
||||
status: reviewed
|
||||
last_updated: 2026-06-12
|
||||
---
|
||||
|
||||
@@ -44,6 +44,9 @@ details.
|
||||
(SAN certificate) deployment models (ADR-019)
|
||||
- TLS termination with ACME (Let's Encrypt) and manual certificate management
|
||||
- Cipher suite restriction matching nginx scope (ECDHE-AES-GCM + TLS 1.3)
|
||||
- HTTP/2 support on the client-facing side (between client and proxy),
|
||||
with ALPN-based protocol detection (ADR-023). Upstream connections
|
||||
remain HTTP/1.1.
|
||||
- HTTP → HTTPS redirect
|
||||
- Host-based routing to multiple upstream services
|
||||
- Reverse proxy to Gitea at `127.0.0.1:3000` (git.alk.dev)
|
||||
@@ -55,7 +58,7 @@ details.
|
||||
- Configurable bind addresses (must be explicit, no `0.0.0.0`)
|
||||
- Local health check endpoint on separate port (default: 9900, localhost only)
|
||||
- Unix domain socket admin API for config reload with feedback
|
||||
- Graceful shutdown (SIGTERM handling)
|
||||
- Graceful shutdown (SIGTERM handling with in-flight request drain)
|
||||
- Systemd unit file
|
||||
- Dual licensing: MIT OR Apache-2.0
|
||||
|
||||
@@ -70,8 +73,10 @@ details.
|
||||
|
||||
### Out of Scope
|
||||
|
||||
- HTTP/2 or HTTP/3 proxying (services that need these run their own native
|
||||
Rust servers — e.g., `api.alk.dev` runs its own HTTP/2+ server)
|
||||
- HTTP/2 or HTTP/3 **proxying to upstreams** — the proxy communicates with
|
||||
upstreams over HTTP/1.1 (or HTTPS/1.1). HTTP/2 **from clients** is supported
|
||||
(see ADR-023). Services that need HTTP/2+ to their backends can handle
|
||||
termination themselves.
|
||||
- Load balancing or round-robin upstream selection
|
||||
- WebSocket proxying (can be added later if needed)
|
||||
- Static file serving
|
||||
@@ -143,11 +148,14 @@ loopback, LAN, and tunnel endpoints for multi-host deployments.
|
||||
|-------|---------|---------|-------|
|
||||
| `axum` | 0.8 | HTTP framework | Routing, middleware, extractors |
|
||||
| `tokio` | 1 (full) | Async runtime | Multi-threaded runtime |
|
||||
| `hyper` | 1 | HTTP protocol | Used via axum, and directly for proxy `Client` |
|
||||
| `hyper` | 1 | HTTP protocol | Used via axum, and directly for HTTP/2 server builder |
|
||||
| `hyper-util` | 0.1 | Hyper utilities | Client builder, TokioExecutor, auto::Builder |
|
||||
| `tower` | 0.5 | Middleware ecosystem | Service trait, layers |
|
||||
| `rustls` | 0.23 | TLS implementation | `aws_lc_rs` crypto provider |
|
||||
| `tokio-rustls` | 0.26 | Async TLS I/O | Wraps TCP with TLS |
|
||||
| `rustls-acme` | 0.12 | ACME client | Let's Encrypt auto-provisioning and renewal |
|
||||
| `hyper-rustls` | 0.27 | HTTPS client | Upstream HTTPS connections with rustls TLS |
|
||||
| `rustls-native-certs` | 0.8 | Native cert loading | System root certificates for upstream HTTPS validation |
|
||||
|
||||
### Supporting
|
||||
|
||||
@@ -206,6 +214,9 @@ All design decisions are documented as ADRs in [decisions/](decisions/).
|
||||
| [019](decisions/019-multi-config-listeners.md) | Multi-config listeners | `[[listeners]]` supporting both dedicated-IP and shared-IP deployment models |
|
||||
| [020](decisions/020-container-deployment.md) | Container deployment model | Defense-in-depth via container isolation; file-primary logging; flexible upstream addressing |
|
||||
| [021](decisions/021-x-forwarded-for-edge-proxy.md) | X-Forwarded-For edge proxy model | Replace, don't append — proxy is the edge, no trusted upstream proxies |
|
||||
| [022](decisions/022-health-check-scope.md) | Health check scope — local port and admin socket only | No `/health` route on main listener; health check is port 9900/admin socket only |
|
||||
| [023](decisions/023-http2-client-facing.md) | HTTP/2 client-facing support | ALPN-based protocol detection; HTTP/2 to clients, HTTP/1.1 to upstreams |
|
||||
| [024](decisions/024-ansi-disabled-logging.md) | ANSI-disabled logging | All log output uses `with_ansi(false)` for fail2ban and Docker compatibility |
|
||||
|
||||
## Open Questions
|
||||
|
||||
|
||||
Reference in New Issue
Block a user