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.
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.
- Install .NET 6 if not already installed from https://dotnet.microsoft.com/download
- Create a new web project using
dotnet new web --name MyYarpProxy
- Add a reference to the YARP nuget package:
dotnet add package MyYarpProxy Yarp.ReverseProxy
- 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();
- 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
- YARP configuration defines the routes and destinations. It can be supplied via:
- Static config files, with file change detection for dynamic updates
- Programatic configuration extensibility to interface with other sources
- For hyper-scale hosting, routing can be fully dynamic and determined by app code and handled by YARP on a per-request basis
Routing & inbound connections
- YARP can front multiple sites and route based on SNI/Host
- Routing can be based on request URL & header values
- Active & passive health checks to confirm the availability of destinations, and filter out bad entries
- Session Affinity will route subsequent requests to the same destination if required
- Multiple algorithms for load balancing across destinations
- Authentication, authorization and CORS for specific routes
Proxying & outbound connections
- Incoming request Url can be transformed before passing to destination(s)
- Request and response headers can be transformed
- Http Methods can be transformed (eg POST to PUT)
- Outbound http connections to destinations are configurable
- Proxy adds standard headers related to request forwarding
- gRPC and web sockets traffic including streaming
Diagnostics
- Metrics for monitoring performance
- Logging for detailed tracking of each request
General
- Proxy has cloud scale performance
- Documentation
- Easy extensibility – Customers can add middleware to customize the proxy functionality such as routing, header manipulation
- Support for .NET Core 3.1, .NET 5 & .NET 6
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:
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
I’d be interested in guidance for running this on Azure App Service or possibly even Azure Functions (consumption plan!).
Hi Sam, It's great to see the infrastructure being reused. Quick queries -
hi
Does YARP supports streaming for a chunked response? Because, as an example of a similar project, Ocelot doesn’t.
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?
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.
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.
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...
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...
Hi,
Is it possible to run yarp in front of WCF service ?
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...
Hi Sam,
How is reverse proxy different than an API gateway functionality wise?
Regards,
Anantha
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...
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.
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
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...
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...
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.
Hi Sam,
Great that’s perfect, it’ll help us remove some infrastructure setup that wasn’t that simple to manage 🙂
Awesome work team, wonder if we can use YARP as a API Gateway?
You can use YARP to build an API gateway yes.
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...
We deploy multiple instances of YARP and have the layer 4 load balancer cycle between them. Typically for the large scale services they use dynamic configuration and each YARP instance talks to that to get its configuration.
I see, thanks for the guidance Sam!