# Ferron: a Rust web server sold on debuggability rather than raw benchmarks

> A modern HTTP server with automatic TLS and request tracing, distributed as a single installer script or built from a Cargo workspace, aimed at operators who need to find out why a request failed.

**ferronweb/ferron** — A fast, modern web server built for production debugging.

- Repository: https://github.com/ferronweb/ferron
- Website: https://ferron.sh
- Stars: 2,157 · Forks: 95
- Language: Rust
- License: MIT
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/ferronweb-ferron

## One installer line, then a config file with two directives

The documented install path for Linux is a single command that pipes a remote script into a shell:

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

It is worth pausing on that form. It is convenient and it is also the pattern that has caused a lot of incidents, so if your organisation has a rule about remote script execution, this is the command the rule is about.

The configuration language is deliberately small, and the README's two examples are the whole introduction to its syntax:

```ferron
example.com {
    root "/var/www/html"

    # If uncommented, directory listing is enabled.
    #directory_listing
}
```

```ferron
api.example.com {
    proxy http://localhost:8080
}
```

That is a site block with a `root` for static files, and a site block with a `proxy` directive pointing at an upstream. Commented-out directives are the documentation convention here, which tells you the language expects you to read a directive's name and infer its options rather than looking them up in a wizard.

The full directive reference lives at ferron.sh/docs/configuration/fundamentals/syntax, so the README is showing you the shape and the docs are the manual.

## Building from source is a Cargo workspace with real submodules

Building from source is three commands, and the `-b develop-3.x` branch is the detail worth noticing:

```bash
git clone https://github.com/ferronweb/ferron -b develop-3.x
cd ferron
git submodule update --init --recursive
cargo build --workspace
```

The clone targets `develop-3.x` rather than the default branch, which tells you the 3.0 work lives on a development branch. That is consistent with the release tags being release candidates.

`Cargo.toml` shows how the codebase is factored. It is a workspace with members `bin`, `core`, `entrypoint`, and globs for `modules/*`, `types/*` and `utils/*`, excluding `doctest`, `e2e` and `fuzz`. The release profile sets `strip`, `lto`, `codegen-units = 1` and `panic = "abort"`, which is a sensible configuration for a server binary you ship rather than debug.

The repository tree tells you the rest. There are dashboards, which is the observability surface. There is a `configs/` directory and a `wwwroot/` directory for the default static assets. There are `e2e/`, `doctest/` and `fuzz/` directories for testing at three levels, a `packaging/` directory, a Nix flake, cross-build tooling, and an `installer/` directory that is presumably what the one-line install script serves.

## The CLI has a validate mode, which is the feature to notice

Running the server is a single invocation, and there is a verbose flag for debug logging:

```bash
cargo run -p ferron -- run -c ferron.conf
cargo run -p ferron -- run -c ferron.conf --verbose
```

The next two commands are the interesting ones. There is a `validate` subcommand that checks a configuration without starting anything, and an `adapt` subcommand that outputs the configuration as JSON:

```bash
cargo run -p ferron -- validate -c ferron.conf
cargo run -p ferron -- adapt -c ferron.conf
```

`validate` is the one that changes how you deploy. If your server startup is your config check, a bad edit takes the site down. With `validate` in a pipeline, it does not. That is a small feature with a disproportionate effect on incident rate, and it is the kind of thing a project built around debugging tends to get right.

`adapt` is more interesting still, and the README does not say what it is for. Emitting configuration as JSON suggests machine-readable output, which is what you would want for generating a config from a template, diffing two configs, or feeding configuration into another tool. If you are evaluating Ferron partly because of this command, read the configuration documentation to find out how complete the JSON is.

There is also a `daemon` subcommand with a `--pid-file` option for running as a Unix daemon, which covers the case where you are not using a service manager.

## Tests, packaging and the Docker build

The quality commands are the three you would expect from a Rust project, run across the whole workspace:

```bash
cargo test --workspace
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
```

The clippy invocation with `-D warnings` is the strict form, which means warnings are errors. That is a strong signal about how the project treats lint debt, and it is enforced in a workspace where `modules/*` can pull in a lot of third-party code.

Packaging is done with `just`, using a `Justfile` at the repository root, and the recipes cover the formats a server actually gets shipped in:

```bash
just package
just package-deb
just package-rpm
just package-windows
just installer
```

So archives for Windows and Unix, native Debian and RPM packages, a Windows installer, and the Linux installer script that the one-line install command fetches. `just cross-build` handles optimized binaries for other targets, and the README notes that step is Linux only and points at the `cross-build/` directory for its build files.

The Dockerfile is more elaborate than a typical single-stage build, which fits a server that wants to cross-compile to musl targets. It starts from the official Rust image, installs a toolchain including clang, lld, llvm, qemu-user-static and wrk for load generation, then picks a target triple per platform and maps each of the common Linux architectures to its musl equivalent, failing on an unsupported target. The presence of `qemu-user-static` and `wrk` in a build image is a good indication that this project benchmarks its own output.

## Observability and automatic TLS are the two selling points

The README's feature list has six items, and two of them are the reason to consider the project at all.

Automatic TLS issues and renews certificates without configuration, and the README emphasises that you get clear signals when it works or fails. That last clause is the interesting part. Certificate automation that fails silently is worse than none, so a server that tells you when renewal broke is solving the actual problem rather than the demo one.

Observability is described as seeing exactly what happened with any request, with traces covering every layer and linking directly to the relevant logs. The link between a trace and its logs is what makes this useful: the failure mode of request tracing without log correlation is that you can see a request was slow but not which log line explains it.

The rest of the list covers readable configuration, predictable performance with no runtime tuning required, memory safety as a consequence of being written in Rust, and handling messy real-world traffic including upstream failures and protocol edge cases. The stated design principles are ease of setup and ease of debugging, and the `dashboards/` directory in the tree is where the second one becomes visible.

The honest qualifier on all of this is that the README makes performance claims without numbers. There is no benchmark table here, unlike projects that lead with one. If throughput is your deciding criterion, you will have to run your own test, and the Dockerfile's inclusion of wrk suggests the project would not object to you doing that.

## How it compares with nginx, and what the 3.0 line means for you

nginx is the comparison that matters, because a fast modern web server with reverse proxying is exactly what nginx is. The differences come down to where the effort went.

nginx has decades of production hardening, an enormous module ecosystem, and a configuration syntax that existing infrastructure already speaks. Its reputation for readability is deserved and its memory footprint is famously small. Ferron offers none of that history, and offers instead automatic TLS, request traces, and a config validator.

The switch from one to the other is a rewrite, not a conversion. There is no configuration compatibility layer mentioned anywhere in the README, and the site-block-with-directives syntax resembles nginx without being nginx. So the question is not whether Ferron is better than nginx in the abstract, it is whether the debugging story is worth a config rewrite for the size of deployment you have.

For a handful of sites on one machine, that trade can be worth it. For a large estate with hundreds of vhosts and existing automation that generates nginx configuration, it almost certainly is not, and no observability feature closes that gap.

On maturity: the repository is not archived and the last push was on 2026-09-28, which is recent. But the newest releases are 3.0.0-rc.8 from 2026-09-28, rc.7 from 2026-09-24 and rc.6 from 2026-09-13. Release candidate tags in the 3.0 line mean the current major version is still settling, and the source branch you clone is `develop-3.x` rather than a stable tag. MIT licensed, with a CHANGELOG at the root and a Polish README alongside the English one.

## Conclusion

Ferron is a good fit when you run a small number of sites and reverse proxies and your normal failure mode is not knowing why one request behaved oddly, because observability and automatic TLS are the two things the project is actually built around. It is a poor fit as a drop-in nginx replacement in a large deployment, since there is no configuration compatibility layer and the 3.0 line is still at release candidate stage. It is MIT licensed, the last push was on 2026-09-28, and the newest tags are 3.0.0-rc.8 and rc.7 from the same week. Start with the one-line installer, then run `cargo run -p ferron -- validate -c ferron.conf` on your configuration before every deploy, since that command exists precisely to catch a bad config without starting the server.

## FAQ

### How do I install Ferron on Linux?

The documented method is the installer script, run as `sudo bash -c "$(curl -fsSL https://get.ferron.sh/v3)"`. The README links to the full Linux installation documentation on ferron.sh and also documents building from source with cargo, targeting the `develop-3.x` branch.

### What configuration file does Ferron use?

A `ferron.conf` passed with the `-c` flag. Site blocks contain directives such as `root` for static file serving and `proxy` for reverse proxying, with other directives left commented out in the examples. The full reference is at ferron.sh/docs/configuration/fundamentals/syntax.

### Can Ferron validate a configuration without starting?

Yes. The `validate` subcommand checks a configuration without starting the server, run as `cargo run -p ferron -- validate -c ferron.conf`. There is also an `adapt` subcommand that outputs the configuration as JSON.

### Does Ferron handle HTTPS certificates automatically?

The README lists automatic TLS as a feature: certificates are issued and renewed automatically, and it states you get clear signals when that works or does not. Reverse proxying a local upstream takes one `proxy` directive inside a site block.

### Is Ferron a replacement for nginx?

It is a different server rather than a drop-in substitute, and the README describes no configuration compatibility layer. Ferron is built around automatic TLS, request tracing that links to logs, and a config validator, while nginx brings a much longer production history and a far larger module ecosystem.

## Sources

- [ferronweb/ferron on GitHub](https://github.com/ferronweb/ferron)
- [License: MIT](https://github.com/ferronweb/ferron/blob/develop-3.x/LICENSE)
- [Project website](https://ferron.sh)
- [README](https://github.com/ferronweb/ferron/blob/develop-3.x/README.md)
- [Releases](https://github.com/ferronweb/ferron/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ferronweb-ferron
