- Add reverse-proxy-4xx and reverse-proxy-badbots fail2ban filters
- Set backend=auto and ignoreip on all jails (fixes silent no-match
when defaults-debian.conf inherits systemd backend)
- Document three-jail setup and REQUEST log format in README
- Add review #007 covering connection lifecycle, logging, and deployment
drift triggered by the 2026-07-24 FD exhaustion incident
Extract shared read_and_validate_config() with before/after mtime check
to detect mid-write config file changes. Add ReloadError enum with
FileChangedDuringRead variant. Return HTTP 409 Conflict on mtime change
from admin reload endpoint. Store cli_allow_wildcard_bind in
ConfigReloadHandle and use it in reload() validation instead of hardcoded
false. Update all ConfigReloadHandle::new() call sites.
Remove src/admin/socket.rs and replace with Bearer token HTTP auth on the
health check listener (port 9900). New src/admin/auth.rs provides SHA-256
key hashing with constant-time comparison; src/admin/handler.rs implements
/admin/reload, /admin/status, and /admin/rotate-key. Admin endpoints return
404 when disabled (empty admin_key_path), 401 on bad auth. Config field
renamed admin_socket_path → admin_key_path. Deployment files updated for
key file mount instead of socket directory.
Security review #005 identified critical vulnerabilities in the Unix domain
socket admin API (C1 symlink race, C2 no auth, C3 info leak, W1-W7, S1-S6).
ADR-028 (already accepted) replaces the socket with an authenticated HTTP
admin API on the health check port. This commit adds the remaining spec work:
- ADR-029: Config file TOCTOU mitigation (mtime check on reload)
- ADR-030: Store cli_allow_wildcard_bind in ConfigReloadHandle for consistent
reload validation
- Implementation tasks for the admin HTTP migration (fix/admin-http-api),
TOCTOU fix (fix/config-reload-toctou), and wildcard flag fix
(fix/wildcard-flag-reload)
- Updated review #005 status to resolved with per-finding disposition
- Resolved OQ-16: POST for state-changing admin endpoints, GET for read-only
- Updated all architecture docs to reference new ADRs, use admin_key_path
instead of admin_socket_path, and reflect POST method for /admin/reload
Add host part validation to is_valid_upstream: IPv4/IPv6 addresses must parse
as valid IpAddr, bracket-enclosed hosts must parse as IPv6, DNS names must
pass is_valid_hostname. Previously, values like '!!!bad!!!:3000' would pass.
Removed #[non_exhaustive] from TlsMode and the wildcard _ arm in the
match tls_mode block in main.rs. Since setup_tls already rejects unknown
modes with bail!, the wildcard was unreachable dead code. Removing it
ensures the compiler catches future TlsMode variant additions. Added
defense-in-depth count mismatch check after the acceptor loop to catch
any silent listener/acceptor mismatch from zip truncation.
Remove unused log_rate_limit! and log_config_reload! macros,
format_event_fields() function, ProxyError::NotFound/BadRequest/
PayloadTooLarge/UpstreamTls variants, build_multi_domain_server_config(),
SniCertResolver struct, and dead test helper methods. Gate
AcmeTlsConfig::directory_url() and KvVisitor with #[cfg(test)].
Change build_upstream_uri to return Result<Uri, ()> so that URI parse
failures are properly handled instead of silently dropping the query
string and unwrapping a fallback. On parse failure, log a warning with
the malformed URI and return 502 Bad Gateway to the client.