ASP.NET Core applications have a built-in webserver called Kestrel. This internal webserver is not intended to serve requests directly. It must be placed behind a production quality webserver such as NGINX, IIS, etc. We chose NGINX because we have experience with it and it runs on Linux. Ansible does all the needed configuration and keeps our servers consistent and predictable.

Configure NGINX with Ansible

Everything we need can be accomplished from a single playbook. This playbook installs NGINX, configures it, copies SSL keys and enables the ASP.NET Core site:

---
- hosts: nginxHosts
  
  tasks:
    # Install NGINX
    - name: ensure NGINX is installed
      apt: pkg=nginx state=present


    # Configure NGINX
    - name: copy NGINX site config
      copy: 
        src: files/nginx/aspnetCoreApp.site
        dest: /etc/nginx/sites-available/aspnetCoreApp
        owner: root
        group: root
        mode: 0644
      notify: restart nginx

    - name: Enable ASP.NET Core site
      file: 
        src: /etc/nginx/sites-available/aspnetCoreApp
        dest: /etc/nginx/sites-enabled/aspnetCoreApp
        state: link
      notify: restart nginx

    - name: remove default website from nginx
      file: path=/etc/nginx/sites-enabled/default state=absent


    # Copy SSL Certificate
    - name: Copy SSL cert
      copy: src=files/ssl/sslcert.pem dest=/etc/nginx/sslcert.pem
      notify: restart nginx

    - name: Copy SSL private key
      copy: src=files/ssl/sslcert.key dest=/etc/nginx/sslcert.key
      notify: restart nginx


    # Punch out http/https ports in firewall (If you use UFW)
    - name: Allow 80 through firewall
      ufw: rule=allow direction=in proto=tcp port=80

    - name: Allow 443 through firewall
      ufw: rule=allow direction=in proto=tcp port=443 


  handlers:
    - name: restart nginx
      service: name=nginx state=restarted
nginx-playbook.yml

ASP.NET Core NGINX Site Configuration

Each site has its own configuration file. NGINX has documentation on configuring NGINX and Kestrel and our site config does not stray far from their example:

server {
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    server_name app.mydomain.com;

    ssl_certificate /etc/nginx/sslcert.pem;
    ssl_certificate_key /etc/nginx/sslcert.key;

    location / {
        proxy_pass http://dotnet;
        proxy_set_header Host $host;
    }
}

upstream dotnet {
    zone dotnet 64k;
    server 127.0.0.1:5000;
}
files/nginx/aspnetCoreApp.site --> /etc/nginx/sites-available/aspnetCoreApp

That’s it! NGINX can now serve production traffic and reverse proxy to our ASP.NET Core application. The ASP.NET Core application is run manually from an SSH session to check that NGINX is working. Next we’ll remove this manual step by using systemd to run our ASP.NET Core application automatically.