Replacing Nginx with YARP Reverse Proxy
Yesterday, Microsoft announced the release of a new open-source project called YARP (Yet Another Reverse Proxy). YARP is a reverse proxy built using .NET and my initial thought was to try it to see how different it is from using Nginx.
I basically copy/pasted the code from the blog announcement, built the app using VS Code, and was able to run it as is. OK, but what if I wanted to replace Nginx in one of my course's labs? How easy it is to configure the routes compared to Nginx? What I wanted to achieve is something similar to this image they show in the blog post: a simple reverse proxy with 2 routes pointing to 2 containers.
Here's the Docker Compose file I was using:
version: "3.5"
services:
hello1:
depends_on:
- reverseproxy
image: "nginxdemos/hello"
restart: always
hello2:
depends_on:
- reverseproxy
image: "nginxdemos/hello"
restart: always
reverseproxy:
image: k8sacademy/reverseproxy
ports:
- "80:80"
restart: always
And the Nginx config file:
worker_processes 1;
events { worker_connections 1024; }
http {
sendfile on;
upstream docker-hello1 {
server hello1:80;
}
upstream docker-hello2 {
server hello2:80;
}
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
server {
listen 80;
server_name test.com;
location /hello/ {
proxy_pass http://docker-hello1;
proxy_redirect off;
}
location /bonjour/ {
proxy_pass http://docker-hello2;
proxy_redirect off;
}
}
}
Nothing fancy, typing localhost/hello will route the call to container hello1 and localhost/bonjour will route it to hello2. How hard it is to create these routes using YARP? Well, it turns out that the syntax is not that different from the Nginx syntax and I was able to find what I was looking for in the documentation. Instead of an upstream, you define a cluster. I even added a catch-all route, something I did not bother to do using Nginx.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ReverseProxy": {
"Routes": {
"catchallroute": {
"ClusterId": "rickrollcluster",
"Match": {
"Path": "{**catch-all}"
}
},
"helloroute": {
"ClusterId": "hellocluster",
"Match": {
"Path": "/hello/"
}
},
"bonjourroute": {
"ClusterId": "bonjourcluster",
"Match": {
"Path": "/bonjour/"
}
}
},
"Clusters": {
"hellocluster": {
"Destinations": {
"hello": {
"Address": "http://hello1"
}
}
},
"bonjourcluster": {
"Destinations": {
"bonjour": {
"Address": "http://hello2"
}
}
},
"rickrollcluster": {
"Destinations": {
"rickroll": {
"Address": "https://youtu.be/dQw4w9WgXcQ"
}
}
}
}
}
}
I then added a Dockerfile, built the container, edited the compose file to use the YARP image, and bang! It worked on 1st try. All of that in about 10 minutes!!! 😮
I then checked the size of the images using the proposed focal version and the alpine version of the aspnet 6 runtime:
mcr.microsoft.com/dotnet/aspnet:6.0-focal
mcr.microsoft.com/dotnet/aspnet:6.0-alpine
Turns out that the alpine version is 100MB while the alpine version of Nginx is about 23MB. Not too bad for .NET!
Granted, I only scratched the surface but turns out that replacing Nginx was super easy in this simple scenario. I'll keep an eye on this project for sure.