Featured image of post ASP.NET Core with Nginx as reverse proxy on Linux

ASP.NET Core with Nginx as reverse proxy on Linux

On Linux, ASP.NET Core runs on Kestrel, the new web server based on libuv. We are going to use Nginx as a reverse proxy to improve performances.

This post was originally published in 2016 and may contain outdated information.

Being able to run ASP.NET web applications or web sites on Linux operating systems now is very¬†cool. Before that, we had to¬†use Mono, but it does’t support the full .NET framework or .NET technologies such as MVC or async support. Now, we have¬†the .NET Core 5.0 (dnxcore50), and we can run our cross-platform ASP.NET Core web apps with the same new web server, Kestrel. Kestrel is a web server based on libuv and works nicely. Therefore, there are a few things that discourage me using it in production as the main web server. I prefer to use a more popular web server, Nginx. I really like Nginx, it is the third most popular web server in the world, and it is often used as a reverse proxy, and this is exactly how I am going to use it with Kestrel.

# Why not using ASP.NET Core default web server, Kestrel?

Managing ASP.NET Core web applications with Kestrel isn’t easy, or isn’t as easy as managing virtual hosts like Apache or Nginx. Each web application must be running on one process of the Kestrel web server. It means that we can’t run two web applications on the same port. Also, unlike Apache or Nginx, we cannot declare our web applications in configuration files, and launch them all with a single command. We have to run¬†“dnx web” in a terminal for every web application! What about HTTPS? Well, I’ve saw a Nuget package for a HTTPS Kestrel version, but it doesn’t look like as easy to configure as the other popular web servers.

Like I said before, I really like Nginx. Nginx is very good for serving static files and passing other requests to other web servers (reverse proxying), and in our case, Kestrel.

# Installation

I’m assuming that you already have a .NET environment installed on your Linux distribution. If not, follow the official documentation to install it: DNVM, the .NET version manager, and the .NET Core DNX runtime. At this time, the RC2 of .NET Core isn’t working for me, so I’m using the RC1.

# Nginx configuration

Now let’s create a nginx configuration for our web application. We are going to proxy every request to the Kestrel web server except the assets such as Javascript, CSS, images and other static files. Nginx is the best for serving static content. We are going to add a HTTP header to be sur that it’s Nginx that served our static content and not Kestrel.

server {
    # Port and domain
    listen 80;
    server_name aspnet.local;
    # Path to the wwwroot folder
    root /home/developer/projects/WebApplicationBasic/wwwroot;

    # Static content
    location ~ \.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|html|htm|woff2|svg)$ {
        expires 1d;
        access_log off;
        add_header X-Static-File true;

    # Pass requests to Kestrel
    location / {
        proxy_set_header Connection "";
        proxy_http_version 1.1;

The 19th and 20th lines are very important. It covers a bug found in the RC1 version of Kestrel. If you don’t add them, your browser will wait for an answer forever even if the server has sent the response. Have a look here to find more information about this bug.

Our configuration is efficient because Kestrel is now free to process dynamic data. Let’s try this out on our browser. It works! Don’t forget to add your local domain to the hosts file.

Licensed under CC BY 4.0
Ko-fi donations Buy me a coffee