Deploying .NET Core API to Ubuntu 20.04 (NGINX)

I’m going through the process of deploying a .NET Core API to an Ubuntu 20.04 server, with NGINX and a MySQL database.

Configure MySQL

First, install MySQL using APT repository.

sudo apt update
sudo apt install mysql-server

enter password, security level, enter for everything else

Now, let’s make our installation more secure. Run the default security configuration:

sudo mysql_secure_installation

When asked for the validation component, press ‘Y’, choose level 2, enter your password. Confirm the password. Then, just press enter to use default for all other configurations.

By default, the ‘root’ user uses auth_socket to authenticate, making things harder to authenticate. To be able to authenticate using username and password let’s change to caching_sha2_password. Open MySQL and execute the ALTER USER query, with the password you provided on the previous step.

sudo mysql

ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'password';


(If ‘caching_sha2_password’ does not work for you, you may use: ‘mysql_native_password’).

Now, check if MySQL is running, with:

systemctl status mysql.service

If it’s not running, start the service with:

sudo systemctl start mysql

Install .NET Core

Install .NET Core Runtime Package (I’m going for 3.1.11) following this commands (check .NET Core Downloads page) :

wget -O packages-microsoft-prod.deb

sudo dpkg -i packages-microsoft-prod.deb

sudo apt-get update

sudo apt-get install -y apt-transport-https

sudo apt-get update

sudo apt-get install -y dotnet-sdk-3.1

If you’re going to use Entity Framework tools you should also install.

dotnet tool install --global dotnet-ef

export PATH=$PATH:$HOME/.dotnet/tools

Publish App

Checkout your GIT repository into /var/www/project_name. You can also just copy over the published files with FTP, per example, if you prefer not to use GIT.

If your project uses a database, do not forget to change your connection string and update your database, so all migrations are applied.

dotnet ef database update

Since we will be using a reverse proxy server, the following should be added on top of your Configure in Startup.cs.

using Microsoft.AspNetCore.HttpOverrides;


app.UseForwardedHeaders(new ForwardedHeadersOptions
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto


Now, make sure you’re inside your project folder and publish your app.

dotnet publish --configuration Release

Installing and Configure NGINX

Now for the final step we just have to install and configure NGINX.

sudo apt-get install nginx

sudo service nginx start

Check if your service is successfully running by visiting on your browser:


Configure your server on:

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

You can copy-paste the following configuration. If you don’t have a domain, you can just use ‘localhost’ as your server name. 😉

server {
    listen        80;
    server_name *;
    location / {
        proxy_pass         http://localhost: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;

Don’t forget to restart nginx:

sudo systemctl restart nginx

Finally, let’s create a service to run our app, as following:

sudo vim /etc/systemd/system/kestrel-your_app_name.service

You can use this configuration, just change the paths to match you application. Make sure you double check your path, since that may be an usual source of errors.

Description=Example .NET Web API App running on Ubuntu

ExecStart=/usr/bin/dotnet /var/www/yourapp/bin/Release/netcoreapp3.1/publish/yourapp.dll
# Restart service after 10 seconds if the dotnet service crashes:


And now, just start your service, and you should have everything set!

sudo systemctl start kestrel-your_app_name.service

If your service does not start correctly you may run this command and check the logs:

journalctl -u kestrel-you_app_name.service -n 100 --no-pager

Leave a Comment

Your email address will not be published. Required fields are marked *