Less time configuring. Less time debugging.

Configuration that helps catch typos before production does. Correlated logs and trace IDs that turn debugging into a lookup — so you know why a backend failed, not just that it did.

$ cat /var/log/ferron/access.log /var/log/ferron/error.log | grep 6dea16fb9aa089a37bd163a5dc232785

[2026-08-17 06:20:27.487 WARN] [trace=6dea16fb9aa089a37bd163a5dc232785] Reverse proxy: TCP connect to 127.0.0.1:5000 failed: Connection refused (os error 111)

...

[2026-08-17 06:20:27.487 WARN] [trace=6dea16fb9aa089a37bd163a5dc232785] Reverse proxy: TCP connect to [::1]:5000 failed: Connection refused (os error 111)

[2026-08-17 06:20:27.487 ERROR] [trace=6dea16fb9aa089a37bd163a5dc232785] Reverse proxy: Bad gateway — upstream: http://localhost:5000: Connect failed: TCP connect failed: Connection refused (os error 111)

See how Ferron turns debugging into a lookup with correlation.

Web servers shouldn't feel like this

Your web server should be clear and predictable — not something you have to wrestle with to find out what went wrong.

Configuration sprawl

One minor directive change silently breaks unrelated routes. As your configuration grows over time, every deployment feels unpredictable.

No trail to follow

Tracing a single failure across distributed services is slow, manual work. Without log correlation, you're left grepping timestamps just to guess what went wrong.

Operational uncertainty

When production dips, you shouldn't have to investigate by hand. Did the config reload succeed? Is the backend healthy? You may have to SSH just to see the server status.

No fast path to root cause

When the circuit breaker gets tripped, you shouldn't have to manually correlate logs to find out why, and end up guessing instead of doing a lookup.

Configuration that stays clear

Readable defaults and few directives, with consistent behavior even as your setup grows.

NGINX host configuration

server {
    listen 80;
    listen 443 ssl http2;

    server_name example.com;
    server_tokens off;

    # Assuming you use Certbot for automatic certificate management
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    root /var/www/html;
    gzip on;

    location / {
        try_files $uri $uri/ =404;
    }
}

Ferron 3

# TLS certificate is obtained automatically for public hosts
example.com {
    root /var/www/html
}

Built for operators

Validate configuration and inspect runtime state for daily server management.

$ ferron doctor -c /etc/ferron/ferron.conf

[2026-07-11 20:26:18.807 WARN] Best practice violation (block 'http port 8443' in file '/etc/ferron/ferron.conf' at line 2, column 19): OTLP configured without an explicit `service_name`; data might be attributed incorrectly for multi-service environments

[2026-07-11 20:26:18.807 WARN] Best practice violation (block 'http port 8443' in file '/etc/ferron/ferron.conf' at line 19, column 5): `directory_listing` exposes generated indexes for directories without index files; enable it only for intentionally public file listings

Configuration best-practice warnings from ferron doctor.

Debug production without guessing

When things break, you see what's happening: live runtime state with no extra setup.

A demonstration of debugging Ferron infrastructure via Grafana

A Grafana dashboard over Ferron's live metrics.

Correlate logs and traces

When latency rises or backends fail, follow trace IDs across logs and metrics to see what happened.

Spot problems before users report them

Watch latency, error rates, circuit breakers, and backend health as they change.

Catch configuration drift early

Monitor your running state; detect manual, out-of-band edits as they happen, before they cause a broken reload.

Keep using the tools you already know

Send logs, metrics, and traces to Grafana, Better Stack, OpenTelemetry collectors, and other observability systems.

Even grep can be enough

Access and application logs carry the same trace ID. When a request fails, grep that ID across both: see the full chain without a collector.

$ cat access.log error.log | grep e9bedf4ca114e998cf8d2b578ccba761

::1 - - [16/Sep/2026:14:42:10 +0200] "GET / HTTP/2.0" 502 - "-" "curl/8.22.0" "localhost:8443" "e9bedf4ca114e998cf8d2b578ccba761"

[2026-09-16 14:42:10.725 WARN] [trace=e9bedf4ca114e998cf8d2b578ccba761] Reverse proxy: TCP connect to 127.0.0.1:80 failed: Connection refused (os error 111)

[2026-09-16 14:42:10.725 WARN] [trace=e9bedf4ca114e998cf8d2b578ccba761] Reverse proxy: backend failed, retrying same upstream (1/1) — upstream: http://demo.local:80: Connect failed: TCP connect failed: Connection refused (os error 111)

[2026-09-16 14:42:10.725 ERROR] [trace=e9bedf4ca114e998cf8d2b578ccba761] Reverse proxy: Bad gateway — upstream: http://demo.local:80: Connect failed: TCP connect failed: Connection refused (os error 111)

Search across access and application logs.

Follow a request across your logs

One trace ID ties multiple logs. Grep it and the full sequence appears: what it returned, where it failed.

Works with your existing log tooling

Plain text log files, compatible with logrotate, journald, and any log shipper you already have configured.

Plain text logs, no pipeline required

Log files need no extra setup. No collector, dashboard, nor additional process to keep running.

Performance without constant tuning

Steady throughput under real-world workloads; no performance expertise required to keep it stable.

High concurrency

Built to hold up under load, with no artificial keep-alive limits and no pool starvation.

Modern protocols

HTTP/2 and HTTP/3 support, keeping connections stable under heavy traffic.

Efficient by design

Low memory usage and consistent behavior as traffic scales: no thread-per-connection overhead eating into your resources.

No tuning required

Sensible defaults out of the box: no worker counts, connection pools, or hidden limits to tune.

Common questions, answered without guessing

Production debugging scenarios answered with Ferron capabilities.

Why did this backend just get pulled out of rotation?

Circuit breaker transitions are emitted as named events and tracked as a live metric, not buried in a log line you'd only find if you knew to look.

Did my reload actually change anything?

Query the admin API's /config and /status endpoints and see the running configuration and its state directly: no restart, no diffing files by hand.

A request failed at 2:52am, where do I even start?

Grep the trace ID out of the access log and pull every related line from the application log in one grep. No collector, nor dashboard login, just the terminal you already have open.

Is this backend actually slow, or is my code slow?

Spans separate the reverse proxy hop from the origin response, so the flame graph tells you which side of the wire the time went, instead of you guessing from an aggregate number.

Install Ferron

Choose your platform and get Ferron up and running.

Using packages (recommended):

Using installer script:

sudo bash -c "$(curl -fsSL https://get.ferron.sh/v3)"

Join the Ferron community

Ferron is an open-source project built by developers like you. Whether you contribute or run Ferron, you can join its community.

2K+

Stars on GitHub

20+

Contributors on GitHub

50K+

Docker Hub pulls

Contribute on GitHub

Improve Ferron by reporting issues, suggesting features, or submitting code.

Join Matrix community

Join our community on Matrix to chat about setups, configs, and debugging with others who run Ferron.

What users say about Ferron

Hear from people running Ferron, from homelabs to production.

You may want to check out what Ferron is doing. I've been using it for a few months. Highly recommend. (...) Significantly easier to set up than nginx, and by far the most effortless auto TLS integration. (...) Highly recommend using the v2 docker images though. It now uses KDL for configuration, which is much cleaner than YAML. The syntax is versatile enough that you can create a custom DSL of sorts. Ferron uses it to replicate if statements, and uses them to filter access by IP or headers.

Source

Michael Murphy

Engineer at System76 and Pop!_OS maintainer

I just switched to @ferronweb on my pi to serve services at home. Imho ferron is just way easier to configure than anything else.

Source

Andreas Wachter

just tried it for serving a fastapi. It's fantastic. Instant TLS via Let's Encrypt. There may be other webservers that are equally easy, but this one is certainly easier than Apache or ngninx, which I used so far. Love it.

Source

Thomas Walther

Founded and sold an AI startup to Spotify

Ready to try Ferron?

Install on your platform, configure with clear files, and debug with trace IDs — from first setup to production.