.NET Core with NGINX on Linux

Having .NET Core with NGINX on Linux is easier that you might imagine. In this article I will talk about my experience related to NGINX and what it takes to configure it for the first time. If you come from an IIS/Windows world like me, where you know everything by heart, the declarative approach in NGINX might be a bit odd.

I already have Kestrel, why do I need something else? #

Kestrel is the default server implementation for ASP.NET Core, and it is super fast, cross-platform, customizable and it can run on its own. It looks like it is the perfect server, but it was lacking a lot of features related to security. Another thing about Kestrel is that "used as an edge server without a reverse proxy server doesn't support sharing the same IP and port among multiple processes".

Although is not required, it is recommend to have a reverse proxy in front of Kestrel because it will give you an extra layer of configuration and defense and integrates smoothly with the existing infrastructure.

A proxy server is a go‑between or intermediary server that forwards requests for content from multiple clients to different servers across the Internet. A reverse proxy server is a type of proxy server that typically sits behind the firewall in a private network and directs client requests to the appropriate backend server. A reverse proxy provides an additional level of abstraction and control to ensure the smooth flow of network traffic between clients and servers.

https://www.nginx.com/resources/glossary/reverse-proxy-server/

What is NGINX? #

NGINX is an open source software for web serving, load balancing, media streaming, that also has reverse proxy capabilities. One of the goals behind NGINX was to create the fastest web server out there. Now, is one of the most popular servers out there.

Installing NGINX on Linux #

Depending on your Linux distribution the package manager might differ. I had Red Hat sudo yum install nginx did the trick. After a successful installation you will find the files and folders for NGINX under /etc/nginx path on the server looking pretty much like this( without the highlighted folders)

nginx structure

nginx structure

One of the most important files out there is the nginx.conf file that will contain or reference other configurations for your web apps. Bear in mind that, in order to be able to start NGINX server this configuration will have to be valid.

Configuring NGINX for all your apps #

Now, I’ve cleaned up a bit the default nginx.conf and it looks like this:

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
    worker_connections 1024;
}

http {
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"';
    access_log /var/log/nginx/access.log main;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;

}

For easier formatting, I used Visual Studio Code with 2 extensions: Nginx configuration and Nginx Formatter.
At line 28, I’ve added an include statement because I want to place all my configurations for different website in separate files, in sites_enabled folder.

After that, I’ve created the sites_enabled folder, and the certs folder (that will contain certificates). In the sites_enabled folder, I’ve created a file named myapi.conf and inside it, I’ve added this:

server {
    server_name myserver;
    root /var/opt/myapps/ui;

    index index.html index.htm index.nginx-debian.html;

    location / {
        try_files $uri $uri/ /index.html;
        proxy_read_timeout 300s;
        proxy_connect_timeout 75s;
    }

    location /api {
        proxy_pass http://localhost:4906;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection keep-alive;
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 300s;
        proxy_connect_timeout 75s;
    }
}

In the configuration file I have 2 'location' sections, one for an UI app, and one for the API. The two apps I want to be served from the same 'domain' but on a different path:

  • the ui app from the root like /myapp
  • the api from something deeper in the hierarchy like: /myapp/api

Once this is done, you can test the nginx configuration by running nginx -t -c /etc/nginx/nginx.conf in the terminal. If that is successful, you can go ahead, start NGINX server

Useful NGINX commands #

sudo nginx service start

sudo nginx service restart

sudo nginx service status

In summary #

We looked at how to configure .NET Core with NGINX on Linux, but the same configs will work on Windows also. The only thing you need to do besides configure NGINX is to run the API as a Linux Service, and to make sure is up.

In a following post we will add https in front of our API, because we need to care about security. :)