Announcing YARP 1.0 Release

Sam

Today we announce the release of YARP 1.0, which can be downloaded from NuGet. YARP (Yet Another Reverse Proxy) is a highly customizable reverse proxy built using .NET. The biggest differentiator between YARP and other reverse proxies is how it is built and packaged – YARP is supplied as a library and samples showing how to create a proxy that is customized to the needs of your specific scenarios.

What is a reverse proxy?

Reverse proxies are used to listen to incoming HTTP requests and to forward the requests to appropriate servers based on the contents of the request. Unlike a typical firewall/router which acts at layer 4 (TCP/IP), reverse proxies typically work at layer 7 so they understand http and work based on http fields.

When YARP proxies a request, it handles the HTTP connection from the client, and then creates its own connections to the destination server, and both sides can benefit from connection pooling.

Illustration of the role of a reverse proxy

Using a reverse proxy has a number of advantages:

  • It acts as the public endpoint for a site or set of services, enabling the url-space exposed to be independent from the actual implementation
  • Forwards calls to backend servers to perform real work, balancing load between them
  • Can offload work from backend servers such as TLS Encryption, Auth2, Compression, Caching

Introducing YARP

YARP is a project to deliver an open-source reverse proxy server based on .NET. It started almost two years ago when we noticed a pattern of questions from teams at Microsoft who were either building a reverse proxy for their service or had been asking about APIs and technology for building one. We decided to get them all together to work on a common solution, which became YARP.

YARP is a reverse proxy toolkit for building fast proxy servers in .NET using the infrastructure from ASP.NET and .NET. The key differentiator for YARP is that it is being designed to be easily customized and tweaked to match the specific needs of each deployment scenario.

The thing we found from talking with teams creating Microsoft services is that each service is slightly off the beaten path, and they had all been building their own solutions, or trying to customize a 3rd party proxy. While they had solutions for HTTP/1.1, they needed HTTP/2 – commonly for gRPC, and HTTP/2 uses a binary framing format which is much more complicated to implement. YARP enables developers to have full control while leveraging the proven feature set of ASP.NET Core and .NET, with the productivity of C# (or other .NET languages).

YARP plugs into ASP.NET as middleware for handling incoming requests, and YARP offers two main paths for use & customization:

  • As a full featured proxy – YARP uses configuration to define a set of routes based on URL patterns, these routes map to clusters of destination servers, each destination in a cluster should be able to handle requests for the routes the cluster is mapped to. The destination list is filtered based on session affinity, and server health, then uses a load balancing algorithm to choose between the remaining destinations.Each part of this can be customized through configuration and customers can add additional modules, or replace stock modules as needed. The configuration system is extensible so for example route and destination information can be pulled from a source such as Service Fabric.
  • Alternatively, for highly custom environments the YARP request forwarder can be called directly, bypassing the routing, load-balancing modules etc. For example, this is how YARP is being used by Azure App Service for routing requests to specific instances, where the instances are spun up on demand.

These can even be used together in the same process, switching between them based on the route.

Getting started

Unlike other proxies that are supplied as an executable that you can extend, YARP reverses the model. You create a proxy using a template that calls into YARP, this makes it much easier to add your own customization and features to YARP.

The following sample is based on the new simplified templates for .NET 6. Examples are available for .NET Core 3.1 and .NET 5.

  1. Install .NET 6 if not already installed from https://dotnet.microsoft.com/download
  2. Create a new web project using
dotnet new web --name MyYarpProxy
  1. Add a reference to the YARP nuget package:
dotnet add package MyYarpProxy Yarp.ReverseProxy 
  1. Replace the code in program.cs with:
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));

var app = builder.Build();

app.MapReverseProxy();

app.Run();
  1. Replace the configuration file in appsettings.json with:
{
    "Urls": "http://localhost:5000;https://localhost:5001",
    "Logging": {
        "LogLevel": {
            "Default": "Information",
            "Microsoft.AspNetCore": "Warning"
        }
    },
    "AllowedHosts": "*",
    "ReverseProxy": {
        "Routes": {
            "minimumroute": {
                "ClusterId": "minimumcluster",
                "Match": {
                    "Path": "{**catch-all}"
                }
            }
        },

        "Clusters": {
            "minimumcluster": {
                "Destinations": {
                    "httpbin.org": {
                        "Address": "https://httpbin.org/"
                    }
                }
            }
        }
    }
}

This will create a proxy that will listen to http://localhost:5000 and https://localhost:5001 and route any requests to https://httpbin.org (a useful site for http debugging.) Further details on what can be added through configuration.

What is in YARP 1.0

This 1.0 release of YARP includes the following features:

Configuration

Routing & inbound connections

Proxying & outbound connections

Diagnostics

  • Metrics for monitoring performance
  • Logging for detailed tracking of each request

General

Documentation

YARP documentation.

Performance

Performance of the proxy will depend on a number of factors:

  • Version of http used by clients to the proxy
  • Version of http used by the proxy to the destination
  • Whether TLS encryption is used
  • Size of request/response headers and content payloads

We have a set of benchmarks that get run daily against YARP and other proxy servers. This is measured in a lab using the “citrine” hardware definition created to measure the TechEmpower benchmarks. The results are presented using a PowerBI dashboard that can be used to compare against other proxies. For example, comparing YARP and Envoy for (incoming-outgoing protocol) http-http1.1 & https-https1.1 with results in October ’21 looks like:

Graph of performance over time

The dashboard can be found at https://aka.ms/aspnet/benchmarks. Once there, at the bottom of the page is a widget to select the page. Proxy results are on page 16.

Hint: Clicking the text “1 of 21” will bring up a menu of pages, where “Proxies” can be selected directly.

Open Source

YARP is being developed and delivered as an open source project. It is hosted on github at https://github.com/microsoft/reverse-proxy. We welcome contributions, issues and discussions at the repo.

Support

YARP support is provided by the product team – the engineers working on YARP – which is a combination of members from ASP.NET and the core libraries networking teams. We do not provide 24/7 support or ‘carry pagers’, but as we have team members located in Prague and Redmond we generally have good time zone coverage. Bugs should be reported in github using the issue templates and will typically be responded to within 24hrs. If you find a security issue we ask you to report it via the Microsoft Security Response Center (MSRC).

We will service 1.0 for security or other significant issues. New features will be considered for future versions. We expect to start releasing preview builds of the next version in the next couple of months.

Thank you to contributors

In addition to the contributions from Microsoft employees, we are very grateful to have received a number of PRs and issues from the community. Thank you to those who contributed PRs to make this release happen – @amweiss, @anorborg, @BennyM, @dpbevin, @danirzv, @epignosisx, @ericwj, @ganesanarun, @gustavopaes, @hughesjon, @ihvo, @Insomniak47, @isaacabraham, @jboelter, @jmezach, @jrunyen, @jtkech, @Marusyk, @MeladKamari, @MoienTajik, @NoahStahl, @rwkarg, @sharkAndshark, @sleemer, @stefanolsenn, @Tornhoof, @vdjuric, @WeihanLi, @William-Yeh.

I want to make a special call out to @Kahbazi who made an amazing 86 commits and was a more prolific contributor than many of the people assigned to the project.

What’s next

Work on the reverse proxy will continue. Items we have on our list to work on for the next version include:

  • Support for HTTP/3 – initial testing shows that it mostly works, but we want to have a solid implementation in YARP #1208
  • More performance optimization – We will have another push on performance, and use YARP to drive additional performance features into .NET
  • Use LLHTTP to provide more control over outbound connections and more efficient processing of headers. LLHTTP is an experiment to develop a lower level HTTP API than HttpClient to enable much more control over how HTTP requests are made and handled.
  • Support for Service Fabric – Early previews of YARP included a module for Service Fabric integration. That was insufficient for large scale site deployments typical of sites using Service Fabric. We are working with SF team members to implement a more robust and scalable solution for dynamically configuring the proxy based on SF data #257
  • @jkotalik wrote a prototype implementation for integration with Kubernetes. The Microsoft team members working on YARP are not experts in k8s deployments, so we are working with community members to further develop this integration. #200

23 comments

Leave a comment

  • ericmutta

    I have been following this closely, it’s great to see version 1 finally out, kudos to the team!

    One challenge I am still facing when considering YARP is making the proxy machines highly available. Cloud providers of cheap VMs (e.g. Linode) offer “load balancing as a service” where the load balancers are highly available but can’t route based on URLs/headers like YARP. When you choose YARP so you can get better routing, you now have to worry about high availability yourself. It would be great to get some guidance on how the teams at Microsoft handle this (especially any that may be deploying in Linux environments).

  • Mark Radcliffe

    Is it possible to have YARP and a web API be the same application?

    One example I have for this is we develop a multi tenanted SaaS application and we use lets encrypt for the SSL certificates, but lets encrypt with Http challenge is not stateless. So we’d want to proxy the lets encrypt requests to a singleton backend service to complete the handshake.

    So basically a rev proxy that is part of the pipeline but if there are no routes it falls back to the API or vice versa (i.e. you might want to check the proxy first if there is only one rule but many controllers, or check the proxy last if there are many rules and few controllers.)

    • Sam SpencerMicrosoft employee

      Yes. The route table from YARPs config gets merged with any routes that you define through ASP.NET, so you can have endpoints served via WebAPI/MVC etc and YARP in the same ASP.NET process, listening to the same ports/hosts etc.

      • Mark Radcliffe

        Hi Sam,

        Great that’s perfect, it’ll help us remove some infrastructure setup that wasn’t that simple to manage 🙂

    • Sam SpencerMicrosoft employee

      A Reverse Proxy and an API gateway can often mean the same thing. To me the distinction is that a reverse proxy, including YARP, is transparent to the body of the request/response. YARP will route and transform the request URL and headers, but does not attempt to understand or modify the body of the request/response. API gateways can do conversion like XML JSON or merge multiple responses together.

      YARP can be modified to do these kinds of things, but its not built-in. Doing this will affect performance as the bodies typically need to be buffered if any modification is to occur.

      • Sam Anthwal

        Hi Sam,
        Though it is trade off between performance vs use case ,but is there a way to route messages based on RequestBody content (for example json message) ?

        Also when reading body inside AddTransforms().builderContext.AddRequestTransform() in proxy and then forwarding request to Https endpoint it throws with HTTP/2 stream ID 1 error (PROTOCOL_ERROR): Less data received than specified in the Content-Length header but it works with Http downstream service.

        • Karel ZikmundMicrosoft employee

          Routing based on body content is possible via direct forwarding — check out docs for Direct Forwarding

          The specific issue you ran into looks like you received malformed request – Content-Length does not match the data sent by the client, which HTTP/2 is sensitive to. If you have more detail and repro, please file the issue on GitHub for deeper technical discussion: https://github.com/microsoft/reverse-proxy/issues

          • Sam Anthwal

            Thanks Karel.

            That direct forwarding works but then we are loosing what YARP is offering out of the box feature like Load Balancing , retries etc.

            Also is it advisable to have mix of both for example GET endpoints coming from “ReverseProxy” config and POST endpoints are getting configured dynamically using Forwarder ?

            I tried that , and it works but not sure about the implication of this because that does not look good.

            Won’t it be better if it can let user inject “Destination” uri as early as possible or after ConfigProvider load by parsing Body ?

    • Sam SpencerMicrosoft employee

      Provided the WCF service is using SOAP or other protocols over HTTP, and is not doing NTLM or other connection-based authentication to the back end, then yes.

      NTLM & Kerberos are not suitable for being proxied through YARP as they authenticate at the connection level rather than the request. As YARP will multiplex requests over the same connection, the authentication will not flow correctly. If the authentication is done by the proxy, and then a claim is added to the ongoing request, that can be made to work securely.

  • Richard Gavel

    Is there a reason this is referred to as a reverse proxy? Given it’s capabilities, couldn’t it be just as viable to use YARP for defining a forward proxy? Granted, forward proxies aren’t nearly as common as reverse proxies, so calling it a reverse makes it more clear that it’s viable for the most common use case. But just wondering if I’m missing something.

    • Sam SpencerMicrosoft employee

      The role of a reverse proxy and forward proxy are quite different and use different headers to accomplish their goals.

      A reverse proxy is used for inbound calls to services. The caller is typically unaware when a reverse proxy is used – they think that the reverse proxy is the actual destination.

      A forward proxy is used to break out of a network such as a workplace or school. The httpClient/browser has to be configured with the proxy address so that it knows to connect to the proxy. With HTTPS traffic the client needs to connect to the proxy and then ask to create a TCP connection to the destination over which the TLS connection can occur.

      The configuration and requirements for these types of proxy are quite different. YARP was specifically created as just a reverse proxy.

      • Sam Anthwal

        Hi Sam,

        If proxy is running with process ID A , Backend service running with ID B then how to send default credential of proxy to Service In Windows or kerberos authentication?

        Specially when downstream service only supports windows or kerberos authentication?

        In normal process to process scenarios setting UseDefaultCredentials of HttpClientHandler property to true works but not sure how to do it with Proxy as we don’t have any control over HttpClientHandler.

        One solution is to use Forwarder then we loose the benefits of YARP.

  • Andrei Gavra

    In a Kubernetes cluster for example, how is this different from Nginx used as a reverse proxy for backend API services?
    Does this have better performance?

    • Sam SpencerMicrosoft employee

      Out of the box, YARP will have similar characteristics to NGINX. The biggest difference is customization – YARP has been designed to make it very easy to extend with additional functionality.

  • Виталий Бондарчук

    hi
    Does YARP supports streaming for a chunked response? Because, as an example of a similar project, Ocelot doesn’t.

  • Rajasekar S

    Hi Sam, It’s great to see the infrastructure being reused. Quick queries –

    1. Are there migration guides for NGINX/HA proxy/… available, assuming these are the most used?

    2. Are there any YARP project templates/wizards available or planned, that would set up a .NET based webapi/microservice with required settings? Ideally, there are a few settings that are very commonly used – webapi/https/static site routes/,… etc. During project creation, if an equivalent YARP project can be created, It could enhance adoption/usage?

  • James

    I’d be interested in guidance for running this on Azure App Service or possibly even Azure Functions (consumption plan!).