github ferronweb/ferron 3.0.0-rc.7

pre-release4 hours ago

Breaking changes

Reverse proxy

  • Shorter breaker and timeout defaults: circuit_breaker.open_duration default is now 5s (was 30s) and upstream connection_timeout default is now 2s (was 5s), so brief Docker Compose recreates and Apache graceful reloads recover quickly. Increase them explicitly if you need the old behavior.

Forwarded authentication

  • Forwarded auth URI behavior change: Ferron no longer appends the original URI path to the redirect URL by default, instead relying on X-Forwarded-Uri header. Use the append_uri subdirective to restore the previous behavior.

HTTP response control

  • ferron.rule_id no longer duplicates the status code: the ferron.response.status_rule_matched metric now labels each match with the rule's name when set, or status-<code>-rule-<n> (1-based rule position) otherwise. Update dashboards that filter ferron.rule_id by bare status code to use http.response.status_code or the new identifiers instead.

URL rewriting

  • rewrite_log logs DEBUG instead of INFO: the rewrite_log directive now logs each rewrite operation to the error log at DEBUG level instead of INFO, so that it does not pollute normal logs. Update log-level filters to include DEBUG for rewrite logs, or use the new structured log attributes instead.

Added

Reverse proxy

  • retry_interval directive: delay between same-upstream retry attempts plus up to 25% jitter (default 200ms, "0s" disables waiting). Masks brief backend restarts such as Docker Compose recreates or Apache graceful reloads.

Forwarded authentication

  • append_uri subdirective: when enabled, the original URI path is appended to the redirect URL. This can be used to restore the previous default behavior before this version.

Observability

  • HTTP/2 and HTTP/3 stream error logging: stream failures (for example malformed requests, flow-control violations, or resets) are now logged to the configured observability sinks with client and server addresses, similarly to connection errors. HTTP/2 stream errors use error.type tcp_stream_error or unix_stream_error, and HTTP/3 stream errors use quic_stream_error.
  • Clearer HTTP/2 and HTTP/3 connection errors: connection-level protocol violations are now returned as errors (instead of closing silently), so they are logged as connection errors with a descriptive message.

HTTP cache

  • LSCache staleness suffix support: ~s staleness suffix is now parsed in LSCache compatibility, allowing stale cache entries to be purged by single tag or URL.
  • X-LiteSpeed-Vary: value= support via request variables: responses declaring value=<name> are now stored instead of bypassed, partitioned per request by the set_var variable <name> (empty when unset). Only one value dimension is supported (last wins); values are normalized and truncated past 256 characters.

HTTP response control

  • name subdirective for status rules: status blocks accept an optional plain-string name, surfaced as the ferron.rule_id metric label so same-code rules can be told apart in dashboards.

URL rewriting

  • name option for rewrite rules: rewrite blocks accept an optional plain-string name, surfaced as ferron.rewrite.rule_name across rewrite metrics, spans, logs, and access-log fields.
  • Per-rule rewrite attribution: ferron.rewrite.rewrites_applied and ferron.rewrite.invalid now carry ferron.rewrite.rule_index (1-based rule position); spans, access logs, and rewrite_log output additionally report matched-rule counts and per-step from/to URLs for chained rewrites.

Abuse protection and rate limiting

  • log_rejections option: abuse_protection and rate_limit blocks accept an optional log_rejections flag that re-enables per-request rejection debug logs for forensics (default off).

Changed

Reverse proxy

  • localhost exception from strict DNS resolution: localhost URLs are no longer resolved via strict DNS; they are treated as local addresses and bypassed to avoid unnecessary DNS lookups.
  • Stale pooled-connection forgiveness: a first failure on a reused keepalive connection (SendRequestError) is no longer counted toward the circuit breaker when a same-upstream retry will be attempted. This prevents one dead socket closed during reloads from tripping the breaker when the retry succeeds.

URL rewriting

  • ferron.rewrite.rewrites_applied counts rule firings: the counter now increments once per matched rule (instead of once per rewritten request), so chained rewrites contribute one increment per step. Single-rule rewrites are unaffected.

Abuse protection and rate limiting

  • Transition-only rejection logging: ban rejections and rate-limit rejections no longer emit a debug log per request, which could exhaust the observability pipeline under abuse waves. Bans now log Ban triggered / Ban expired transitions plus a ferron.abuseban.active_bans gauge; rate limiting logs the first rejection per key (then at most once per minute) without the raw key value. Set the new log_rejections option to restore per-request debug logs for forensics.

Fixed

Abuse protection and rate limiting

  • Ban eviction race fix: observing an expired ban and evicting it is now atomic, so concurrent requests can no longer delete a freshly re-triggered ban, and each ban expiry is reported exactly once.

HTTP cache

  • LSCache stale purge now serves stale: purge operations carrying the stale marker expire matching entries in place instead of deleting them, so they keep serving stale while revalidating (or on error) when a stale window applies, and miss otherwise.

HTTP server core

  • Jammed unquoted IP address fix: previously, unquoted IP addresses in ferron.conf files could be jammed together leading to unexpected behavior.
  • HTTP/2 flow control fixes: fixed a flow-control bug that caused stream resets when downloading large response bodies with hyper (see zincio-http changelog).
  • HTTP/2 and HTTP/3 hardening: improved robustness of HTTP/2 and HTTP/3 server implementation (see zincio-http changelog).
  • Active request metric decrement fix: previously, canceled HTTP/2 connections caused active request metric to not be decremented properly, leading to incorrect active request counts.

Admin API

  • Admin API listen fail fix: previously, when configuration is reloaded, the admin API listener would sometimes fail to bind to the configured address due to a race condition.

Observability

  • Prometheus reload listen fail fix: previously, when configuration is reloaded, the Prometheus listener would sometimes fail to bind to the configured address due to a race condition.
  • Global span links fix: the server now fallback back into global span links (control plane metadata) properly.

Reverse proxying

  • Reverse proxy stall fix: fixed stalls on some connections caused by aborted connections when the reverse proxy was waiting for a response from an HTTP/1.x upstream server.
  • Circuit breaker metric fix: fixed missing circuit breaker metrics when circuit breaker is enabled but not yet opened, so that the ferron.proxy.circuit_breaker.state metric is always emitted.
  • Reverse proxy canceled span fix: the server now emits span attributes even when the reverse proxy request is canceled (due to timeout or explicit cancellation), so that the span is not empty and can be correlated with the request.

Don't miss a new ferron release

NewReleases is sending notifications on new releases.