Add three ADRs (025-027) and update five spec documents to close gaps identified in the security and bug review: - ADR-025: Rate limiter IP source must be ConnectInfo only (C1 fix) - ADR-026: Connector timeout ceiling of 30s for per-site timeouts (C3 fix) - ADR-027: Admin socket resource limits — 5s timeout, 4096 byte line limit (W4 fix) Spec changes: - proxy.md: add rate limiter IP source section, URI error handling constraint, connector ceiling description, renumber sections - operations.md: add ConnectInfo-only IP source, in-flight counter architectural requirement (C2), JSON format guarantee (C4), admin socket resource limits, 100ms drain polling interval - config.md: fix http_port type u32→u16 (W12), tighten upstream host validation (W1), tighten ACME contact validation (W2), add X-Forwarded-Proto cross-reference, clarify alknet ADR-030 reference - overview.md: fix ambiguous C1 reference, add ADR/OQ cross-references - open-questions.md: update OQ-09 resolution, add OQ-13 (acme_contact Vec) and OQ-14 (eviction configurability) - README.md: add ADR-025/026/027 and OQ-13/14, update doc statuses to draft Also fix reviewer findings: alknet ADR-030 scope clarification, RFC 2616 reference updated to RFC 7230.
status, last_updated
| status | last_updated |
|---|---|
| draft | 2026-06-12 |
Reverse Proxy — Architecture
Current State
Phase 1 (Implementation) — Complete. The proxy is deployed and running in a Docker container, replacing our vulnerable nginx 1.24.0 installation.
This project replaces our vulnerable nginx 1.24.0 installation with a memory-safe Rust/axum reverse proxy. The primary motivation is CVE-2026-42945 (unauthenticated RCE in nginx's rewrite module) and the broader pattern of memory corruption bugs in nginx's C codebase.
The proxy supports multiple domains from initial release (git.alk.dev and alk.dev), with per-domain host-based routing and a single multi-domain SAN certificate via ACME. HTTP/2 is supported on the client-facing side (between the client and the proxy) with ALPN-based protocol detection. Upstream connections remain HTTP/1.1.
Architecture Documents
| Document | Status | Description |
|---|---|---|
| overview.md | Draft | Vision, scope, crate dependencies, exports |
| proxy.md | Draft | Reverse proxy handler, request flow, header injection |
| tls.md | Reviewed | TLS termination, ACME, manual certs, SNI, ALPN |
| config.md | Draft | TOML config format, static/dynamic split, ArcSwap reload |
| operations.md | Draft | Rate limiting, logging, health check, systemd, shutdown |
ADR Table
| ADR | Title | Status |
|---|---|---|
| 001 | Rust with Axum | Accepted |
| 002 | Custom Proxy Handler | Accepted |
| 003 | TOML Configuration Format | Accepted |
| 004 | ACME-Primary Certificate Management | Accepted |
| 005 | tokio-rustls Directly, Not axum-server | Accepted |
| 006 | Token Bucket Rate Limiting | Accepted |
| 007 | Custom Structured Log Format | Accepted |
| 008 | Static/Dynamic Config Split with ArcSwap | Accepted |
| 009 | Signal Handling Strategy | Accepted |
| 010 | Multi-Site Support in Phase 1 | Accepted |
| 011 | Multi-Domain TLS Configuration | Accepted |
| 012 | Restrict Cipher Suites to nginx Scope | Accepted |
| 013 | Health Check on Separate Local Port | Accepted |
| 014 | Unix Domain Socket Config Reload API | Accepted |
| 015 | Per-Site Upstream Timeouts with Defaults | Accepted |
| 016 | Explicit Bind Address Requirement | Accepted |
| 017 | Upstream Connection Defaults | Accepted |
| 018 | Request Body Size Limit | Accepted |
| 019 | Multi-Config Listener Support | Accepted |
| 020 | Container Deployment Model | Accepted |
| 021 | X-Forwarded-For Edge Proxy Model | Accepted |
| 022 | Health Check Scope — Local Port and Admin Socket Only | Accepted |
| 023 | HTTP/2 Client-Facing Support | Accepted |
| 024 | ANSI-Disabled Logging for Container Deployments | Accepted |
| 025 | Rate Limiter IP Source — ConnectInfo Only | Accepted |
| 026 | Connector Timeout Ceiling for Per-Site Timeouts | Accepted |
| 027 | Admin Socket Resource Limits | Accepted |
Open Questions
See open-questions.md for the full tracker.
| OQ | Question | Priority | Status |
|---|---|---|---|
| resolved (ADR-012) | |||
| resolved (ADR-007) | |||
| resolved (ADR-013) | |||
| resolved (ADR-014) | |||
| resolved (single bind_addr sufficient) | |||
| resolved (ADR-015) | |||
| resolved (ADR-019) | |||
/health use a less common path to avoid upstream collision? |
resolved (ADR-022: no /health route on main listener) |
||
upstream_connect_timeout_secs be enforced? |
resolved (ADR-026: 30s connector ceiling) | ||
| resolved (already specified in config.md; implementation bug C2) | |||
X-Forwarded-Proto be derived per-listener? |
resolved (hardcoded https is correct for TLS-terminating proxy) |
||
| resolved (mandatory, always-on per operations.md) | |||
| OQ-13 | Should acme_contact support multiple email addresses? |
low | open |
| OQ-14 | Should rate limiter eviction interval and max age be configurable? | low | open |
Document Lifecycle
| Status | Meaning | Transitions |
|---|---|---|
draft |
Under active development. May change significantly. | → reviewed when open questions are resolved |
reviewed |
Architecture is final. Implementation may begin. Changes require review. | → stable when implementation is complete |
stable |
Locked. Changes require review and may warrant an ADR. | → deprecated when superseded |
deprecated |
Superseded. Kept for reference. | Removed when no longer referenced |