Pre-RFC: Universal Reverse Proxy interface

This RFC proposes a universal interface (using NixOS options) to configure reverse proxies. Think of this as Kubernetes Ingress for NixOS.
This can also be compared to virtualisation.oci-containers but for reverse proxies.

I have not written the core design yet. I wanted to gauge interest in the community for something like this. You can read the current draft here:

Summary

Implement a set of NixOS options to offer a universal interface to configure reverse proxies.
These options can be used by applications to expose themselves independent of the administrator’s preferred reverse proxy.

4 Likes

I find this very interesting but as a power user of NGINX, I cannot help myself asking the same question as for the portable service abstraction, how do you plan to handle the divergence in the feature set?

7 Likes

I, too, find this to be an interesting proposal. But the question of how to use, let’s say NGINX, HAProxy, Traefik through a unified interface is a good one indeed. Maybe we can have some discussion on that? I’d love to see that.

1 Like

My first idea was to allow implementations to define their own options within this interface.

Then a module could define something like this:

{
  reverse-proxy.services.<name> = {
    upstreams = [...];
    # make expose an attrset to allow multiple hostnames?
    expose = {
      name = "example.tld";
      # ["/"] could be the default?
      paths = ["/"];
    };
    # alias to services.nginx.virtualHosts.<name> 
    nginx.basicAuth = { foo = "bar"; };
    # alias to services.caddy.virtualHosts.<name>
    caddy.extraConfig = ''
      basicauth / {
        foo $2a...
      }
    '';
    traefik = {
      # creates new middleware named `<name>-auth` in dynamic Traefik config
      middlewares.auth.basicAuth.users = [
        "foo:$2a..."
      ];
      # alias to services.traefik.dynamicConfigOptions.http.routers.<name>
      router.middlewares = ["auth"];
      # alias to services.traefik.dynamicConfigOptions.http.services.<name>
      service...
    };
  };
}

Edit: Though, this should only be reserved for very niche use-cases. Common things like rewrites should be behind a universal option.