The Death of the Nginx Config: zeroserve and the Future of Web Server Configuration

The Death of the Nginx Config: zeroserve and the Future of Web Server Configuration

Jun 06, 2026 web server ebpf infrastructure devops tls nginx alternative deployment open source scripting

Let's be honest: configuring nginx is nobody's favorite part of deployment. You spend hours crafting location blocks, wrestling with rewrite rules, and hunting through documentation when something doesn't work as expected. Then, when declarative config reaches its limits, you bolt on Lua scripts that run somewhere in the request lifecycle—it's config all the way down, and nobody really knows what happens when.

Enter zeroserve: configuration as code, literally.

The brainchild of developer su3.io, zeroserve is a tiny, fast HTTPS server that throws out the config file entirely. You hand it a tarball of your website and it serves it over HTTP/2 and TLS 1.3 with hot reload and minimal resource footprint. No nginx.conf. No Caddyfile. No YAML. No problem.

But here's where it gets interesting: you can drop eBPF programs into that tarball, and they'll run on every single request as sandboxed middleware. Think of it as writing middleware logic that's also your server configuration—fully programmable, JIT-compiled to native code, and running in userspace without touching the kernel's BPF subsystem.

Wait, eBPF in Userspace? That Seems Wild

Here's the clever part: zeroserve uses async-ebpf, a userspace eBPF runtime. Your scripts get compiled to eBPF bytecode at pack time using clang and llc, then loaded into zeroserve's own process space where they're JIT-compiled to native x86-64 machine code. No CAP_BPF required. No root privileges. Just an ordinary unprivileged process running your "configuration."

To keep things safe, a pointer cage does what the kernel BPF verifier would normally do—every memory access is masked into the script's own arena. A stray pointer stays confined. The runtime is also fully preemptible, so a slow script won't freeze your entire event loop. Timers can interrupt JIT-compiled code mid-execution and hand control back to the event loop. Elegant, right?

The Programming Model: A Chain of Scripts

Your scripts run in sorted filename order, sharing a per-request metadata map. Drop scripts under .zeroserve/scripts/ in your tarball and they're automatically compiled and executed. Here's the beautiful simplicity:

#include <zeroserve.h>

ZS_ENTRY
zs_u64 entry(void) {
  char peer[64];
  if (zs_req_peer(peer, sizeof(peer)) <= 0) zs_strcpy(peer, "unknown");

  // publish values for the HTML template pass
  zs_meta_set(ZS_STR("visitor"), ZS_STR(peer));
  // attach a header to every response
  zs_meta_set(ZS_STR("zs.response.header.x-served-by"), ZS_STR("zeroserve-ebpf"));
  return 0;
}

This script enriches every request—setting a visitor variable and adding a response header. If a script calls zs_respond or zs_reverse_proxy, the chain short-circuits and handles the request directly. You get routing, authentication, rate limiting, and reverse proxying all in one readable program you can follow top to bottom.

Modern TLS Without the Headache

zeroserve ships with modern TLS by default: TLS 1.3, HTTP/2, Encrypted Client Hello, SNI certificate selection, and JA4 fingerprinting. Just drop your certificates in the tarball and the server handles everything. The whole request path—from TLS negotiation through middleware to response—is one cohesive system you control with code.

One Tarball to Rule Them All

Here's the deployment dream: package your entire site as a single tar file. zeroserve indexes it on load, building a path-to-byte-range map, then serves files directly from the tarball without ever unpacking to disk. No document root for a stray location rule to expose. No temp directories. Just one atomic file swap for deployments.

zeroserve --pack ./public > site.tar
zeroserve --addr 0.0.0.0:8080 site.tar

Updating is equally clean:

killall -SIGHUP zeroserve

The reload swaps the site, the scripts, and the TLS material atomically—same process, no dropped connections.

Is This the Future?

zeroserve is experimental, but the design philosophy is compelling. Traditional web servers layer declarative config with bolted-on scripting—configuration that quietly grows its own control flow, scripts that run somewhere you have to remember. zeroserve collapses this into one coherent model: a single program that sees every request and decides what happens.

For developers tired of wrestling with config languages, startups needing simple but powerful deployments, and tech entrepreneurs who want their infrastructure to be as readable as their application code, this approach deserves attention.

The code is available and the idea is out there. Whether zeroserve itself becomes the next nginx or Caddy—or simply inspires the next generation of web servers—the concept of "configuration as code" taken this literally is worth exploring.

What do you think? Is the traditional config file finally ready for retirement?

Read in other languages: