Luna Tech

Tutorials For Dummies.

Deploy a Dotnet Web API on Ubuntu with Nginx Reserve Proxy

2022-04-09


0. Goal

Today I’d like to deploy a dotnet web api server on a Linux remote machine and access the api endpoint from my browser using the server’s public ip address.

  1. Web API (.net core 6.0)
  2. Remote Ubuntu server
  3. Enter public ip address in browser to access api endpoints

Reference

Host ASP.NET Core on Linux with Nginx - don’t blindly follow it, check this tutorial.

Resources

Github repo for this tutorial


1. Local Setup

a. Create a dotnet web api app

b. Run it on local debug mode

c. Stop the app

d. Publish the app

dotnet publish -r linux-x64 --self-contained false -o published

or use UI to publish, the only thing to note is don’t use “single file mode”, we need to have a dll for this tutorial to work.

e. Run app from the published folder

f. Check the api again


2. Ubuntu Env Setup - General

a. Create a Ubuntu Server on Cloud

Ubuntu version: 20.04 LTS

b. Connect with the VM


3. Ubuntu Setup - Dotnet WebApi

a. Install dotnet sdk and runtime

wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb

sudo apt update
sudo apt install -y apt-transport-https
sudo apt-get install -y dotnet-sdk-6.0
sudo apt install -y aspnetcore-runtime-6.0
sudo apt install -y dotnet-runtime-6.0
sudo apt update
sudo apt upgrade

Verify the installation

dotnet

b. Install Nginx Web Server

sudo apt-get install nginx
sudo systemctl status nginx

Optional: Check Firewall Rules

How to Check Firewall Status in Ubuntu Firewall (configserverfirewall.com)

sudo ufw status
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Create folder to hold the files

sudo unlink /etc/nginx/sites-enabled/default
cd /var/www
sudo mkdir dotnetwebapi
cd dotnetwebapi
sudo chmod 777 dotnetwebapi # this is bad, I'm only using it to write file with FileZilla, you can use git or other methods to transfer the files

c. Transfer Files - FileZilla (cross platform)

Connect with the server, drag and drop files into the folder we just created.

d. Run dotnet app from ubuntu server

cd /var/www/dotnetwebapi
dotnet dotnetwebapi.dll

e. Try to access the api from curl

We’ll use http in the config files (in later section)

# the http ones should work
curl -v http://localhost:5000/weatherforecast
curl -v http://127.0.0.1:5000/weatherforecast
# the https one are unlikely to work but it's fine
curl -v https://localhost:5001/weatherforecast
curl -v https://127.0.0.1:5001/weatherforecast


4. Configure Reverse Proxy

a. Install package - HttpOverrides

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();

var app = builder.Build();

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

app.MapControllers();

app.Run();

b. Repulish and copy to the ubuntu server

c. Update /etc/nginx/sites-available/default file

sudo nano /etc/nginx/sites-available/default

File content

server {
    listen        80;
    root /var/www/dotnetwebapi; # make sure to match this with your folder name
    location / {
        proxy_pass         http://127.0.0.1:5000;
        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;
    }
}

Enable the site

ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/

Reload & Restart (Reload is sufficient)

sudo nginx -t # check syntax
sudo nginx -s reload # reload
sudo systemctl restart nginx # restart

Test with ip address

curl -v http://ipaddress/weatherforecast


5. Troubleshooting

If the local address in the server is working but the ip address one is not working, check your network status and make sure nginx is listening on the right port

sudo apt install net-tools
sudo netstat -pantu


6. Run API server with pm2

a. Install npm and pm2

sudo api install npm
sudo npm install -g pm2

b. run dotnet app with pm2

cd /var/www/dotnetwebapi
pm2 start "dotnet dotnetwebapi.dll" --name dotnetwebapi

c. use curl to double check if the app is still running

curl http://localhost:5000/weatherforecast

d. pm2 useful commands

pm2 start "<command>" --name <name>
pm2 stop <name>
pm2 list
pm2 logs <name>
pm2 info <name>
pm2 monit <name>

7. Summary

  1. Create a dotnet webapi app
  2. Create a Ubuntu server
  3. Install nginx web server
  4. Copy the published files into the Ubuntu server
  5. Configure the site config (you can use the default one or a different one)
  6. Reload nginx and verify
  7. Use pm2 to run the api server in background

Bonus - What is reverse proxy?

Nginx and other web servers allow us to host multiple apps on the same machine and each of them can be mapped to a different server name, e.g., api.lunawen.com, project.lunawen.com.

We use Nginx config files to do the mapping.

Bonus - Why not HTTPs?

Since you are likely to have a domain name instead of the ip address for your application, usually the CDN (e.g., cloudflare) will already have https enabled, so you don’t have to use https in your nginx config.