GenHTTP Gateway

The fastest entry point to every app on your home server.

GenHTTP Gateway is a lightweight, self-hosted reverse proxy built on ioxide, the engine behind the fastest HTTP/1.1 web server in the HTTP Arena benchmark. Deployed in front of a homelab, NAS or VPS, it routes domains and paths to Docker containers, devices, static files and redirects from a single YAML file, with Let’s Encrypt certificates, HTTP/2 and HTTP/3.

#1HTTP/1.1 web server in HTTP Arena 3.41Mrequests per second, plain HTTP/1.1 ¼ coreat a steady 10,000 requests per second 2.7 coresfor 8 Gbit/s of TLS traffic
gateway.yaml
engine: ioxide
 
hosts:
  domain1.com:
    default:
      destination: http://10.0.0.2:8080
    routes:
      admin:
        routes:
          portainer:
            destination: http://10.0.0.2:9000
          pi-hole:
            destination: http://10.0.0.3/admin/
      files:
        listing: /data/files/
    security:
      certificate:
        pem: live/domain1.com/fullchain.pem
        key: live/domain1.com/privkey.pem

GET https://domain1.com/admin/portainer/

How the gateway routes requests Requests for domain1.com arrive at the gateway on port 443. It sends / to an app at 10.0.0.2:8080, /admin/portainer/ to Portainer, /admin/pi-hole/ to Pi-hole and /files/ to a file listing. A plain HTTP request is redirected to HTTPS. internet gateway :80 :443 ioxide TLS your app10.0.0.2:8080 Portainer10.0.0.2:9000 Pi-hole10.0.0.3/admin/ file listing/data/files/
Send a request:
An example gateway.yaml next to a diagram of the requests it routes.

Powered by the fastest engine available

The gateway runs on ioxide, an engine built on Linux’ io_uring that keeps every request on a single CPU core from start to finish. GenHTTP on ioxide is the fastest web server on HTTP/1.1 in the independent HTTP Arena benchmark, ahead of the leading servers written in Rust, Zig, Go and JavaScript; only experimental configurations tuned specifically for the benchmark score higher. ioxide is open source and available on GitHub.

Compared with established reverse proxies

HTTP Arena ranks infrastructure servers such as nginx, h2o and Caddy separately from web servers. The tests below are those both rankings share. Each ball represents the same number of requests, so a faster flow means higher throughput.

HTTP/1.1
HTTP/2
HTTP/3

Static files served over HTTPS, a core workload for a gateway in front of a website.

GenHTTP Gatewayioxide engine730k
nginx721k
h2ono result
Caddy159k

This is an indirect comparison: in these tests, each server answers requests itself; nginx, h2o and Caddy do so through a small module written for the benchmark. The figures do not include forwarding to an upstream application. Traefik, Apache and HAProxy are not part of HTTP Arena. Values are averages across all connection counts, measured on a 64-core AMD Threadripper in November 2026.

Full results
Average requests per second in HTTP Arena, per test and server. Higher is better; the bars compare the servers within each row.
Requests per secondGenHTTP Gateway (ioxide)nginxh2oCaddy
Static files over TLSHTTP/1.1730k721kno result159k
PlainHTTP/1.13.41M3.28M3.64M432k
Short-lived connectionsHTTP/1.12.61M2.63M2.65M238k
PipelinedHTTP/1.124.21M4.04M4.94M761k
JSON over TLSHTTP/1.11.03M1.31M1.23M322k
PlainHTTP/29.37M3.37M15.87M389k
Static filesHTTP/2552k799k353k115k
PlainHTTP/31.94M4.85Mno result361k
Static filesHTTP/3237k361kno result22k

Efficient CPU usage

Peak throughput is only part of the picture. HTTP Arena also runs tests at a fixed request rate and measures the resources required, which better reflects the load of a typical home server.

¼ core
of one CPU core at a steady 10,000 requests per second, with a mean latency of 75 µs. ioxide does not busy-poll, so CPU usage follows the load. Latency-10K test
2.7 cores
to echo 10 KB request bodies over TLS 50,000 times per second, roughly 8 Gbit/s of traffic. 8Gbit test
0.1 ms
mean response time at one million requests per second. Latency-1M test

A focused feature set for home servers

Each host is a block in gateway.yaml and each path a route. Changes take effect after restarting the container.

Virtual hosts
Serve any number of domains from a single IP address, for example several websites on one VPS. A host named any handles all remaining requests.
Nested routes
/admin/portainer/ is a route within a route, so services can be grouped in a clear hierarchy.
Reverse proxy
destination: forwards requests to any HTTP service on your network, such as Nextcloud, Jellyfin or Home Assistant in a container, a NAS or a router’s web interface.
Static websites
content: serves a directory as a website, with an optional index file.
File listings
listing: turns a directory into a browsable download page, for example to share files from a NAS.
Redirects
location: redirects a path to another URL, on your server or elsewhere on the web.
HTTPS by default
Once a host has a certificate, plain HTTP requests are redirected to HTTPS.
Let’s Encrypt
Reads certbot’s PEM files directly and serves the .well-known folder for webroot validation.
HTTP/1.1, HTTP/2, HTTP/3
Select the protocols for the secure port. HTTP/3 runs over QUIC on the same port via UDP.
Multi-platform images
Images for Linux x64, ARM64 and ARM32, including the Raspberry Pi, and for Windows x64.

Deliberately simpler than Traefik

Most reverse proxies are designed for clusters. The gateway is designed for a single machine: a home server, a NAS, a Raspberry Pi or a VPS hosting a few projects. The entire configuration can be read in a minute, and nothing changes unless you change it. Some features are therefore out of scope: container discovery via labels, middleware chains, load balancing and built-in certificate issuance. If you need them, Traefik, Caddy or nginx are a better fit.

Enable ioxide with a single line

The gateway runs on the engines of the GenHTTP web server, selected with engine: in gateway.yaml. Kestrel is the default because it is available in every image. On Linux x64 servers, switching to ioxide provides the fastest of the three, with 2.3 times Kestrel’s HTTP Arena score.

The three engines compared; HTTP Arena composite HTTP/1.1 score, higher is better
EngineHTTP Arena scoreBuilt onProtocolsRuns on
ioxide fastest7,117io_uring, one reactor per CPU coreHTTP/1.1, 2, 3Linux x64, kernel 6.1+
kestrel default3,090ASP.NET Core KestrelHTTP/1.1, 2, 3Every image, including ARM and Windows
internal4,538GenHTTP’s own engineHTTP/1.1Every image

Enabling ioxide

More about the engine is available on the ioxide website and in its GitHub repository. To use it with the gateway, run the linux-x64 image on a host with kernel 6.1 or newer. Docker’s default seccomp profile blocks the io_uring system calls, so pass the profile from the repository, which is Docker’s default profile with those calls allowed. For HTTP/3 on ioxide, provide certificates as PEM files.

# gateway.yaml
engine: ioxide

# docker run
docker run ... \
  --security-opt seccomp=/data/gateway/seccomp-ioxide.json \
  genhttp/gateway:linux-x64

From docker run to HTTPS in four steps

The image is available on Docker Hub as genhttp/gateway. On first start, it writes an example gateway.yaml to the configuration volume.

  1. Start the container

    docker run -d -p 80:80 -p 443:443 \
      -v /data/gateway/config:/app/config \
      -v /data/gateway/data:/app/data \
      -v /etc/letsencrypt:/app/certs:ro \
      --name gateway \
      genhttp/gateway
  2. Describe your hosts

    Edit /data/gateway/config/gateway.yaml: one entry per domain, a default for its root and routes for the paths below it. Then restart the container with docker restart gateway.

    hosts:
      home.example.com:
        default:
          destination: http://10.0.0.2:8080
        routes:
          cloud:
            destination: http://10.0.0.3:8080   # Nextcloud
          media:
            destination: http://10.0.0.4:8096   # Jellyfin
      home-assistant.example.com:
        default:
          destination: http://10.0.0.5:8123
  3. Get certificates

    Certbot validates your domain through the running gateway, which serves .well-known from the data volume. Reference the PEM files below live/ and let certbot restart the gateway after each renewal.

    certbot certonly --webroot \
      -w /data/gateway/data/ -d home.example.com
    certbot renew \
      --deploy-hook "docker restart gateway"
      home.example.com:
        security:
          certificate:
            pem: live/home.example.com/fullchain.pem
            key: live/home.example.com/privkey.pem
  4. Turn on HTTP/3 optional

    Add http3 to the protocols and publish the secure port for UDP as well: -p 443:443/udp.

    protocols:
      - http1
      - http2
      - http3

Images on Docker Hub

Tags of genhttp/gateway
TagFor
latestSelects the matching image for your platform: Linux x64, ARM32, ARM64 or Windows x64
linux-x64Linux x64; the only image that includes the ioxide engine
linux-arm64ARMv8 Linux, such as the Raspberry Pi 4 and 5
linux-arm32ARMv7 Linux, such as the Raspberry Pi 2 and 3
windows-x64Windows hosts, on Nano Server
Open genhttp/gateway on Docker Hub

Frequently asked questions

Is it an alternative to Traefik or nginx?

For home servers, yes. It routes domains and paths to your applications over HTTPS, configured in a single YAML file. It deliberately omits container discovery, middleware chains, load balancing and built-in certificate issuance. If you need those, Traefik, Caddy or nginx are a better fit.

Does the gateway request Let’s Encrypt certificates itself?

No. Certbot obtains them in webroot mode while the gateway is running: the gateway serves the .well-known folder from its data volume, including over plain HTTP when HTTPS is enforced. It then reads certbot’s PEM files directly, without conversion. Mount the entire /etc/letsencrypt directory, as the files in live/ are links into archive/.

What can I run behind the gateway?

Any service that speaks HTTP: self-hosted applications such as Nextcloud, Jellyfin, Home Assistant, Immich, Vaultwarden or Gitea, admin tools such as Portainer and Pi-hole, the web interface of a NAS or router, or your own websites. Typical setups are a homelab, a NAS or Raspberry Pi at home, a small VPS hosting several sites, or the development and staging servers of a small team.

Does it run on a Raspberry Pi?

Yes. genhttp/gateway is published for Linux ARM32 (Raspberry Pi 2 and later) and ARM64 (Raspberry Pi 4 and later), as well as Linux x64 and Windows x64.

Which engine should I choose?

On Linux x64 with kernel 6.1 or newer, ioxide: it is the fastest engine, built on io_uring, and supports HTTP/1.1, HTTP/2 and HTTP/3. Kestrel is the default because it runs in every image, including ARM and Windows. The internal GenHTTP engine is lightweight and supports HTTP/1.1 only.

How fast is it compared to nginx or Caddy?

Built on the ioxide engine, the gateway runs on the fastest HTTP/1.1 web server in the HTTP Arena benchmark. Compared with the reverse proxies HTTP Arena measures, it is on par with nginx and h2o for plain HTTP/1.1, short-lived connections and static files over TLS; several times faster for pipelined HTTP/1.1; faster than nginx for plain HTTP/2; behind nginx for JSON over TLS, static files over HTTP/2 and HTTP/3; and 3 to 32 times faster than Caddy in every test. These tests measure each server answering directly, not forwarding to an application. The comparison above covers every test.

How much CPU does it need?

In HTTP Arena's Latency-10K test, which holds the load at 10,000 requests per second, ioxide uses a quarter of one CPU core with a mean latency of 75 microseconds. It does not busy-poll, so CPU usage follows the load. In the 8Gbit test, it echoes 10 KB bodies over TLS 50,000 times per second using 2.7 cores.

Can I run it without Docker?

Yes. It is a .NET application: clone the repository and start it with dotnet run (requires the .NET SDK).

Questions or feedback? Join us on Discord.

The gateway is open source under the MIT license and part of the GenHTTP project. Questions, ideas and bug reports are welcome.