Self-host your apps, without the operational clutter

Ferron is a single binary that lets you configure proxying, TLS, and observability in one place, with readable configuration and predictable behavior.

Self-hosting shouldn't become an overhead

Running a few services at home shouldn't require scattered configs, extra tooling, and constant debugging.

Config file complexity

Even a simple reverse proxy can grow into dozens of directives, nested blocks, and hidden interactions. Small changes start to feel risky.

TLS is a part-time job

Certbot, cron jobs, manual renewals. One expired certificate and your whole stack goes dark. Again.

Debugging is guesswork

A service is down. Is it the proxy? The firewall? Port forwarding? DNS? The actual problem is rarely obvious.

Configuration without the sprawl

Clear defaults and minimal directives, with predictable behavior even as your setup grows.

Popular web server (NGINX host configuration)

# Configuration example derived from https://docs.ntfy.sh/config/#__tabbed_16_2
server {
    listen 80;
    listen 443 ssl http2;
    server_name ntfy.sh;

    # See https://ssl-config.mozilla.org/#server=nginx&version=1.18.0&config=intermediate&openssl=1.1.1k&hsts=false&ocsp=false&guideline=5.6
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
    ssl_session_tickets off;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    ssl_certificate /etc/letsencrypt/live/ntfy.sh/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ntfy.sh/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:2586;
        proxy_http_version 1.1;

        proxy_set_header Host $http_host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_connect_timeout 3m;
        proxy_send_timeout 3m;
        proxy_read_timeout 3m;

        client_max_body_size 0; # Stream request body to backend
    }
}

Ferron 3

# Configuration example derived from https://docs.ntfy.sh/config/#__tabbed_16_2
# and translated from Ferron 2 ferron.kdl to Ferron 3 ferron.conf

# Note: Ferron automatically handles both HTTP and WebSockets with proxy

ntfy.sh {
    proxy http://127.0.0.1:2586

    # Redirect HTTP to HTTPS, but only for GET topic addresses, since we want
    # it to work with curl without the annoying https:// prefix

    https_redirect false

    match is_get_topic {
        request.method == "GET"
        request.uri.path ~ "^/([-_a-z0-9]{0,64}$|docs/|static/)"
    }

    if is_get_topic {
        https_redirect
    }
}

TLS without extra tooling

Ferron issues and renews TLS certificates automatically, without requiring separate renewal tooling or manual certificate management.

$ curl https://example.com
    
<!DOCTYPE html>

<html lang="en">

<head>

<title>Test page</title>

</head>

<body>

<h1>Ferron automatic TLS works!</h1>

</body>

</html>

Watch Ferron quickly serve a website with automatic TLS setup.

Know what's going on in your homelab

When your self-hosted services break at 2 AM, you need more than a vague error. Ferron gives you the clues you need, with no extra setup.

[2026-05-02 13:17:57.619 INFO] HTTP server listening on [::]:80
[2026-05-02 13:17:57.619 INFO] HTTPS server listening on [::]:443
[2026-05-02 13:17:57.620 INFO] HTTP/3 server listening on [::]:443
[2026-05-02 13:17:57.620 INFO] ACME background task started with 1 configuration(s) for domains: wrong.ferron.sh
[2026-05-02 13:17:57.625 INFO] OCSP background task started
[2026-05-02 13:17:57.671 WARN] ACME account not found on server for https://127.0.0.1:14000/dir, recreating
[2026-05-02 13:17:57.714 INFO] ACME account created for directory https://127.0.0.1:14000/dir, contact: none
[2026-05-02 13:18:01.760 ERROR] Failed to finalize ACME order for wrong.ferron.sh: DNS NXDOMAIN
  Full error: API error: Get "http://wrong.ferron.sh:5002/.well-known/acme-challenge/yJ8RWozJiZAnPXI0vY0ubg3uVcQXX...

Real logs emitted by the Ferron web server.

Errors you can actually understand

No more Googling cryptic log messages. Ferron explains what went wrong with your TLS setup, proxy config, or anything else, in plain language.

See your traffic without extra setup

A built-in Prometheus endpoint gives you request counts, latency, and system metrics. No extra plugins, no extra containers to manage.

Works with what you already have

Export logs, metrics, and traces via OpenTelemetry to Grafana, Loki, and other observability backends you already use.

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

A calmer way to run self-hosted services

Ferron keeps reverse proxy configuration, TLS, and observability understandable as your setup grows.