I (and maybe some other contributors?) have optimized the web server performance, especially for static file serving and reverse proxying (the last use case I optimized for very recently).
I also picked a different configuration format and specification, what I believe is easier to write.
Automatic TLS is also enabled by default out of the box, you don't need to even enable it manually, like it was in the original server I was building.
Yesterday, I released the first release candidate of my web server's rewrite. I'm so excited for this. I have even seen some serving websites with the rewritten web server, even if the rewrite was in beta.
Any feedback is welcome!
Installation via package managers (Debian/Ubuntu), using repo provided by ferron
https://ferron.sh/docs/installation/debian
Installation as a Docker container
https://ferron.sh/docs/installation/docker
And more.
But this is overblown. What’s your threat model here, you’re downloading a random thing from the internet and executing it. 99% of people are on single user machines, so root access doesn’t help, you’re screwed just by executing the thing if it’s malicious. Doing this is no worse than installing and running a random deb, or running npm install
"Download ffmpeg here: sudo bash -c ..."
And then the installation script from our malicious site installs ffmpeg just fine, plus some stuff you have no idea about. And you never know that you've just been hacked.
> Install with sudo curl bash
Read https://www.joelonsoftware.com/2006/12/09/simplicity/ and ask yourself if you are truly solving anyone's problem or if you are just looking for a way to rationalize the amount of time you are spending on a hobby.
The complete opposite. It's OP that's trying to "optimize the web server for reverse proxying and static file serving", when what we have out there is more than enough.
> or you're wasting time
"Wasting time" is not a problem. If OP is doing working on things because it brings them pleasure and they are hoping to learn from it, more power for them. What bugs me about these types of posts is when people are set on the "build a better mouse trap" mentality and want others to validate them.
It may sound "harsh" to you, but if I came up asking for "any type of feedback" when I'm trying to figure out if the idea is worth persuing, I'd be pretty upset if I kept chasing an invisible dragon because the community was more concerned about "hurting my feelings" instead of being upfront and give some warning like this might be interesting to you but it's not solving any real pain point. Keep that in mind when deciding if work on this will be worthwhile.
The problem space of "web servers to serve static files and reverse proxy" is fairly small, how many differing solutions and designs would be required to satisfy your idea of "as many as possible"?
At what cost? For what benefit?
Again: if OP wants to work on this because they take joy in it, fine. But be honest about it (to themselves and to others) instead of coming up with all sorts of ratioinalizations and biased comparisons when talking about the alternatives.
Each of the 4 charts have data for Ferron and Caddy, but then include data for lighttpd, apache, nginx and traefik selectively for each chart, such that each chart has exactly four selected servers.
That doesn't inspire confidence.
The problems start even higher on the page in "The problem with popular web servers" section that doesn't inspire confidence either.
From "nginx configs can become verbose" (because nginx is not "just" a web server [1]) to non-sequiturs like "Many popular web servers (including Apache and NGINX) are written in programming languages and use libraries that aren't designed for memory safety. This caused many issues, such as Heartbleed in OpenSSL"
[1] Sidetrack: https://x.com/isamlambert/status/1979337340096262619
Until ~2015, GitHub Pages hosted over 2 million websites on 2 servers with a multi-million-line nginx.conf, edited and reloaded per deploy. This worked incredibly well, with github.io ranking as the 140th most visited domain on the web at the time.
Nginx performance is fine (and probably that's why it's not included in the static page "benchmark")
if this is a sense of the logic put into the application, no memory safe language will save it from the terrible bugs!
--
Reach out to the guys at Kamal. They wrote their own reverse proxy because they thought Traefik was too complex, but they might be super happy about yours if Ferron is more powerful yet easy to configure because it might solve more of Kamal’s problems.
Not affiliated with Kamal at all, just an idea.
I previously founded and sold an AI startup to Spotify; that doesn't actually make me smarter than the average HN user (mostly just more lucky) but it probably looks nice on a social proof section.
I did the reverse proxy benchmarks for NGINX, when someone opened a GitHub issue about missing NGINX benchmarks, and asked about benchmark comparisons. It turned out that yeah, Ferron is close to NGINX's reverse proxy performance.
Depending of course from the type of the backend (is it limited by other I/O and Caddy bottleneck does not matter)
So, I guess, performance + easy of use. Obviously, caddy is much more mature though.
Summary
Status: 200
Source: Network
Request
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en;q=0.9
Priority: u=0, i
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.6 Safari/605.1.15
Response
Accept-Ranges: bytes
Cache-Control: public, max-age=900
Content-Encoding: br
Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'none'; img-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://analytics.ferron.sh; connect-src 'self' https://analytics.ferron.sh
Content-Type: text/html
Date: Tue, 21 Oct 2025 10:07:46 GMT
ETag: W/"ba17d6fadf70c9f0f3b08511cd897f939b6130afbed2906b841119cd7fe17a39-br"
Server: Ferron
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Vary: Accept-Encoding, If-Match, If-None-Match, Range
X-Content-Type-Options: nosniff
x-ferron-cache: HIT
X-Frame-Options: deny
"Point a subdomain named ferrondemo of your domain name (for example, ferrondemo.example.com) to either: CNAME demo.ferron.sh or A 194.110.4.223"
This is really strange and make my Spidey sense tingle. If the goal is to just point your domain to this server it should not require DNS auth. Just HTTP is fine. DNS sure if you want optimize reverse proxy, because that would be also possible to do via http auth for every subdomain separately. If you just need some www server quickly pointing your domain to some other dude domain is not the way to go.
This feels weird.
"It's written in Rust so it's memory safe!"
By the way the rewrite is still in Rust.
I really like the spirit and simplicity of Ferron, will try it out when I have a chance. Been waiting for gradually throw out nginx for a while now, nothing clicked all the checkboxes.
Here are my learnings:
* TLS (HTTPS) can be easily enabled by default, but it requires certificates. This requires a learning curve for the application developer but can be automated away from the user.
* The TLS certs will not be trusted by default until they are added to the OS and browser trust stores. In most cases this can be fully automated. This is most simple in Windows, but Firefox still makes use of its own trust store. Linux requires use of a package to add certs to each browser trust store and sudo to add to the OS. Self signed certs cannot be trusted in OSX with automation and requires the user to manually add the certs to the keychain.
* Everything executes faster when WebSockets are preferred over HTTP. An HTTP server is not required to run a WebSocket server allowing them to run in parallel. If the server is listening for the WebSocket handshake message and determines the connection to instead be HTTP it can allow both WebSocket and HTTP support from the same port.
* Complete user configuration and preferences for an HTTP or WebSocket server can be a tiny JSON object, including proxy and redirection support by a variety of addressable criteria. Traffic redirection should be identical for WebSocks and HTTP both from the users perspective as well as the internal execution.
* The server application can come online in a fraction of a second. New servers coming online will also take just milliseconds if not from certificate creation.
> TLS (HTTPS) can be easily enabled by default, but it requires certificates. This requires a learning curve for the application developer but can be automated away from the user.
Yeah, these certificates can be obtained from Let's Encrypt automatically.
> Everything executes faster when WebSockets are preferred over HTTP. An HTTP server is not required to run a WebSocket server allowing them to run in parallel. If the server is listening for the WebSocket handshake message and determines the connection to instead be HTTP it can allow both WebSocket and HTTP support from the same port.
Oh, seems like an interesting observation!
I’m working on an open-source project myself (AI-focused), and I’ve been exploring efficient ways to serve streaming responses — so I’d love to hear more about how your server handles concurrency or large responses.
> Did you benchmark against other Go web servers like Caddy or fasthttp?
I have already benchmarked Ferron against Caddy! :)
> so I’d love to hear more about how your server handles concurrency or large responses.
Under the hood, Ferron uses Monoio asynchronous runtime.
From Monoio's GitHub repository (https://github.com/bytedance/monoio):
> Moreover, Monoio is designed with a thread-per-core model in mind. Users do not need to worry about tasks being Send or Sync, as thread local storage can be used safely. In other words, the data does not escape the thread on await points, unlike on work-stealing runtimes such as Tokio. > For example, if we were to write a load balancer like NGINX, we would write it in a thread-per-core way. The thread local data does not need to be shared between threads, so the Sync and Send do not need to be implemented in the first place.
Ferron uses an event-driven concurrency model (provided by Monoio), with multiple threads being spread across CPU cores.
This is great, I started working on a similar project but never had the discipline to sit through all the edge cases.
Maybe I'll start building it on top of ferron!
I would love to have a minimalistic DIY serverless platform where I can compile rust functions (or anything else, as long as it matches the type signature) to a .so, dynamically load the .so and run the code when a certain path is hit.
You could even add JS support relatively easily with v8 isolates.
Lots of potential!
Wishing the best for your concept too!
Good luck.
Maybe just write an nginx config generator instead?
It's also interesting that the actual config looks quite a lot like nginx config.
Which seems like interesting UX.