Breaking changes
If you are upgrading to this beta version, you must update your configuration files to accommodate the following syntax refactors:
- Rate limit windows - syntax updated to enforce standard duration strings (e.g.,
10s,5m,1h). - OTLP verification -
no_verifyhas been renamed tono_verificationand now operates strictly as a configuration flag. - OTLP defaults - OTLP sink now uses
log_style moderndefault, which may break existing configurations with custom OTLP log formats. - Proxy configuration - syntax for passive/active health checks, load balancing algorithms, and connection retries has been unified into a cleaner, more consistent format.
- Incoming trace context discarded by default - Ferron no longer trusts incoming
traceparent,tracestate, orbaggageheaders unlesstrust_request trueis explicitly set in thetraceblock. Previously, incoming trace context was always parsed and used as the parent span. To restore the old behavior, addtrust_request trueto yourhttp { trace { ... } }block.
Added
Modules
http-abuseban- a new module for lightweight, native Fail2ban-like IP banning with temporary lockouts based on rate limit breaches and brute-force failures.http-traceid- a new module that injects the current request's trace ID into HTTP response headers (configurable header name, optional on-demand reflection viaX-Ferron-Trace-Reflect).tls-http- support for obtaining TLS certificates from a remote HTTP endpoint, featuring automatic refresh cycles and dedicated observability metrics.- OS metrics - added Windows support for native process metrics in the
metrics-processmodule.
Reverse proxy & load balancing
circuit_breaker- new directive with rolling failure windows, temporary backend ejection, and half-open recovery states.p2c_ewma- a new adaptive, latency-aware load balancing algorithm combining Power of Two Choices with Exponentially Weighted Moving Average (EWMA) latency scoring.- Session affinity (sticky sessions) - native support for
cookie,header,ip, andhashtypes utilizing a Ketama-style hash ring for deterministic backend routing. - String interpolation - upstream URLs and Unix socket paths now support interpolated strings.
- SRV routing - added active health check support for SRV upstream URLs.
- Outbound mTLS - reverse proxy upstreams now support presenting client certificates (
certandkeysubdirectives) for mutual TLS authentication with HTTPS backends, including per-upstream credential scoping and SRV upstream support.
DNS & ACME
- 58 new DNS providers - native ACME DNS-01 challenge support expanded to include Alibaba Cloud DNS, Azure DNS, ClouDNS, Hetzner DNS, Oracle Cloud DNS, Vercel, Vultr, Yandex Cloud DNS, and 50+ others.
- CLI arguments in post-obtain command - added support for passing CLI arguments to the post-obtain command in automatic TLS configurations.
HTTP server core
basic_auth_concurrency- global directive to limit concurrent, resource-heavy password verification tasks across allbasic_authblocks.- Cache purging - native
PURGEHTTP method support for targeted cache invalidation via thepurge_methodandpurge_allowed_ipssubdirectives. force_trace- global directive to force trace context creation for every request even when tracing is not explicitly enabled by a module, useful for debugging or log correlation.trust_request- new directive in thetraceblock to accept incomingtraceparent,tracestate, andbaggageheaders as the parent trace context. Default:false. When disabled (default), incoming trace headers are discarded and Ferron generates a fresh trace ID for each request.- Optimal server-preferred compression algorithm - now supports automatic detection of the optimal compression algorithm based on client preferences (GitHub issue).
Authentication
- Forwarded authentication backend chaining - the forwarded authentication module now supports chaining multiple backends together, allowing for flexible and secure multi-backend authentication scenarios.
Observability & metrics
- Edge-case visibility - granular HTTP observability metrics for pre-handler failures, server redirects, client-IP rewrites, CORS preflights, connection lifecycle failures, forward-proxy outcomes, reverse-proxy failures, and static-file response outcomes.
- Admin sinks - added a dropped-events admin metric for non-blocking observability sinks.
- Unix file descriptor metrics - added
process.unix.file_descriptor.count(UpDownCounter) to track the change in number of unix file descriptors since the last measurement. (Linux only) - Backend exclusion tracking - new
ferron.proxy.backend.excludedcounter that records each exclusion event withbackend_urlandreasonattributes, covering passive-check failures, open circuit breakers, retry exclusion, and overloaded backends. - Retry observability - new
ferron.proxy.retry.countcounter andferron.proxy.retry.finalgauge to track retry attempts and whether the final attempt succeeded. - Connection pool metrics - new
ferron.proxy.pool.hitandferron.proxy.pool.misscounters, plusferron.proxy.pool.idleandferron.proxy.pool.outstandingworker-scoped gauges for per-upstream connection pool depth monitoring. - Connect latency & TTFB - new
ferron.proxy.connect.latencyandferron.proxy.ttfbhistograms measuring TCP connection establishment time and time to first response byte. - Health check instrumentation - new
ferron.proxy.health.success,ferron.proxy.health.failure, andferron.proxy.health.durationmetrics for active health probe outcomes. - Circuit breaker metrics - new
ferron.proxy.circuit.stategauge (0/1/2 for Closed/HalfOpen/Open) andferron.proxy.circuit.open_totalcounter tracking circuit breaker state transitions. - Unified certificate expiration gauge - a single
ferron.tls.certificate_not_aftergauge is emitted by every TLS provider (manual,acme,http,local) whenever a certificate is mounted into the in-memory rustls context. The value is the certificatenotAfterfield as Unix epoch seconds; attributes areferron.host(SNI hostname or IP),ferron.tls.provider(provider name), andcrypto.certificate.serial_number(lowercase hex). Replaces the previous provider-specific expiration gauges. - Baggage promotion - new
baggagesub-directive in observability backend blocks (otlp,prometheus) to promote specific W3C Baggage keys into telemetry attributes for logs, metrics, and traces. Supports per-signal filtering and amax_distinctcap to prevent high-cardinality metric label explosion. - Baggage propagation - Baggage is now propagated from incoming requests to outgoing ones, allowing distributed tracing context to be preserved across service boundaries.
- CGI/FastCGI/SCGI observability metrics - added request count, failure count, upstream duration, and stderr error metrics for the
http-fcgi,http-cgi, andhttp-scgimodules. FastCGI also exposes connection pool wait and upstream duration metrics; CGI exposes process duration and exit code metrics; SCGI exposes upstream duration metrics. log_styledirective - newlog_style legacy|moderndirective in the OTLP observability backend block to opt into OTEL-style structured logs. Inmodernmode, each log record publishes a shortsummarybody plus typed per-event attributes (string, bool, integer, float) instead of the human-readable message. Access logs are remapped to OTEL semantic conventions (url.path,http.request.method,http.response.status_code,client.address,http.server.request.duration, etc.). The defaultlegacymode preserves existing behavior.- Application log formatters via
error_format- theerror_logdirective andprovider filenow support anerror_formatsubdirective to choose how application (error) log messages are formatted. Thetextformatter (default) produces human-readable lines with timestamp, level, optional trace ID, and message. Thejsonformatter produces structured JSON records withsummary,level,target,attributes, andtrace_contextfields. Formatter implementations are provided by thelogformat-textandlogformat-jsonmodules respectively. - Logs for OTLP errors - Errors with the logs, metrics and traces providers are now logged.
Admin API
- Added
GET /reloadandGET /runtimeendpoints to the admin listener.
Configuration syntax
- Globs in
includedirectives -include "path.conf"now supports glob patterns, e.g.include "/etc/ferron/conf.d/**/*.conf".
Configuration validation
- Best-practice enforcement -
ferron doctorsubcommand for validating best practices across the configuration. - Print "all good" message - a message is now printed when the configuration is valid with no diagnostics.
- JSON configuration validation results are now printed to stdout when
--jsonis specified, improving observability for automated tools and CI/CD pipelines. - Unused subdirectives are now reported as well as directives.
Docker
- Entrypoint configuration - Docker images now include a dedicated entrypoint config with JSON console logging, trace ID forcing, and an
include /etc/ferron/conf.d/**/*.confdirective for user-provided split configurations.
Changed
Reverse proxy
- Weighted load balancing - both
least_connandround_robinalgorithms now support per-upstreamweightdirectives for proportional traffic distribution. - Metric attributes - multiple HTTP reverse proxy metrics now embed the specific backend URL or Unix socket path as a context attribute.
DNS & TLS
- Early OCSP verification - OCSP responses are now strictly verified before being cached and stapled.
- Verbose errors - significantly improved error reporting layouts for local automatic TLS and specific TLS handshake failures.
/var/cache/ferron-acmeprioritized over user's cache dir - for Docker images with Ferron running asroot, the ACME cache directory is now/var/cache/ferron-acme, which takes precedence over user's ACME cache directory.
HTTP server core
- Safe configuration reloads - configuration failures during a live reload no longer crash or stop the server; errors are logged, and execution safely continues using the previous valid configuration.
- Smarter brute-force locking - protection now locks by IP address instead of username, preventing malicious actors from intentionally locking out legitimate users.
- Accurate status codes - refactored error handling to return context-aware status codes over generic
500or404errors:- File pipeline returns
408 Request Timeoutif a request takes too long (instead of404). - Basic Auth returns
429 Too Many Requestswhen max failed attempts are reached. - File serving errors return
403 Forbidden(permissions) or400 Bad Request(invalid filenames) instead of500.
- File pipeline returns
- Support for multi-range partial static file serving - now supports serving multiple ranges from a single request, improving efficiency and reducing latency.
- String interpolation - forwarded authentication now supports interpolated string values for backend URLs.
- Security tightening - URL canonicalization now strictly rejects paths containing null bytes (
\0or%00). - Cache cleanliness -
X-LiteSpeed-Cacheheaders are no longer emitted by default; can be re-enabled via theemit_litespeed_headerssubdirective.
Observability & tracing
- Unified request tracing - HTTP tracing now rolls up into a single
ferron.requestroot span with nested child spans for pipelines, stages, file-serving, and error pipelines. - Log correlation - OTLP request and access logs now include the active request span context out of the box.
- Backend exporting - admin API metrics are now also pushed directly to configured observability backends, not just the local admin endpoint.
- Cardinality control - Prometheus label values are now sanitized to heavily reduce high-cardinality label inflation.
- Structured log events - every log emission site now carries a short OTEL-friendly
summaryplus typedattributes, enabling downstream OTLP consumers to receive structured events without changing existing console or file log output. - Trace ID in console and file logs - console and file loggers now prefix log messages with
[trace=<span_id>]when a trace context is available, enabling grep-based filtering by trace ID. - Trace context injection for CGI/FastCGI/PHP-FPM/SCGI - trace context headers are now automatically propagated to the backend environment via CGI/FastCGI/PHP-FPM/SCGI.
- Incoming trace context discarded by default - Ferron now generates a fresh trace ID for every request by default, discarding incoming
traceparent/tracestate/baggageheaders unlesstrust_request trueis configured. Existing deployments relying on incoming trace context must addtrust_request trueto thetraceblock. - Sanitized trace header injection -
inject_trace_headersnow removes any existingtraceparent,tracestate, andbaggageheaders before injecting new values, preventing header duplication or conflicts.
Core runtime
- Unified durations - improved configuration-wide consistency for duration formatting values.
- Graceful shutdown - the server process now handles standard Unix
SIGTERMsignals for seamless graceful shutdowns. - Frictionless local TLS - the server now issues a clean warning if local automatic TLS is configured but the cache directory isn't writable, instead of refusing to boot.
Docker
- Split configuration layout - Docker images now use a two-file layout:
/etc/ferron/ferron.confas the entrypoint config and/etc/ferron/conf.d/for user configuration files. Docker Compose bind mounts now target theconf.d/directory.
Package configuration
- Log rotation and structured logging - Default package configurations now include log rotation settings and commented-out structured logging and trace ID format options.
Fixed
Reverse proxy
- Fixed a bug where pool limits weren't being respected when pulling connections from the pool, leading to possible handle exhaustion.
- Fixed a bug where reverse proxy boolean subdirectives with empty values (implying
true) were being ignored. - Fixed an issue where the proxy failed to strip headers specified by the
Connectionheader per RFC 7230.
DNS & ACME
- Fixed an "invalid socket address" error that broke RFC 2136 dynamic DNS updates for the ACME DNS-01 challenge.
- Resolved an edge case where OCSP stapling failed to immediately fetch the response after new certificates were registered.
HTTP server core
- Auth bypass closed - fixed a critical flaw where a misconfigured forwarded authentication block could result in bypassing authentication entirely.
- Cache thundering herd fixed - implemented request coalescing for cache misses to prevent thundering herd scenarios when multiple requests hit the same uncached resource simultaneously.
- Several HTTP/1.x protocol handling bugs fixed - fixed chunked-length encoding DoS vulnerability and other protocol-related issues (see
vibeio-httpchangelog). - Fixed a
500 Internal Server Errorwhen using theauth_to { ... }syntax inside forwarded authentication blocks. - Fixed a bug where case-insensitive HTTP cache control directives were not recognized correctly.
- Fixed a bug where CONNECT requests with authority-form URIs were erroneously blocked by the URL canonicalizer.
- Fixed a bug where HTTP connections couldn't be accepted on 32-bit Windows (see
vibeiochangelog; GitHub issue). - Fixed a bug where HTTP connections were accepted by only one OS thread on Windows.
- Fixed a bug where HTTP timeout durations were not being respected correctly.
- Fixed a bug where TLS certificate resolver from domain name level higher (non-wildcard) was incorrectly used for TLS handshakes if the one from the domain name level matching the requested SNI isn't present.
- Fixed HTTP-to-HTTPS redirects to correctly target the original requested URL rather than internal rewritten URLs.
Observability
- Log injection fixed - implemented strict sanitization of log fields to prevent potential log injection attacks for plain-text logs via malicious header values or other user input.
- Fixed a data blind spot where malformed and timed-out requests rejected before normal handler completion went uncounted by the observability pipeline.
- The server now removes sensitive HTTP headers from access logs (such as
cookie,authorization), to prevent sensitive data exposure in log output. - Corrected inaccurate memory metrics that were calculating values relative to initial memory usage instead of absolute usage.
Security
- DNS rebinding fixed - closed a vulnerability where forward-proxy DNS validation could be bypassed via a race condition combined with a DNS rebinding attack.
- Fixed an issue where forward-proxy allowed ports and denied IP addresses were being treated as additive rather than strictly respecting user configuration overrides.
Runtime operations
- Fixed an Admin API-initiated reload loop that caused infinite configuration reload loops.
- Fixed admin API over-redacting configuration directives in
/configendpoint responses, which could lead to confusion when verifying configuration values. - Eliminated a rate limiting race condition when initializing a brand new key bucket, which previously allowed traffic to briefly exceed configured capacities.
- Fixed manual TLS session ticket key rotation to properly read from configured key files instead of silently falling back to in-memory generation.
- Fixed a bug on Linux where
io_uringcould not be explicitly disabled through the server configuration file. - Fixed an edge case where cached responses replaced by non-cached default error pages could be returned stale.