How to deploy ASP.NET Core 3.1 app to Digital Ocean Linux droplet
Tags: aspnetcore, csharp, linux, ubuntu
Published: 2021-01-17 17:37:24

---
title: How to deploy ASP.NET Core 3.1 app to Digital Ocean Linux droplet
published: true
date: 2020-08-10 00:00:00 UTC
tags: aspnetcore,csharp,linux,ubuntu
canonical_url: https://driesdeboosere.dev/blog/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/
---

In this tutorial we will deploy and host a simple ASP.NET Core 3.1 demo app on Ubuntu 18.04 droplet in Digital Ocean.

You can download or clone the demo app from my [GitHub](https://github.com/Drieze/DriesDeboosere.Dev.Demo), or you can deploy your own ASP.NET Core 3.1 application. Just keep in my mind that this demo app **doesn't make use of a database**. So in this tutorial we don't setup a database. Maybe I'll write another tutorial about implementing an MySql server.

We will break this up in different steps:

[1. Create Digital Ocean Ubuntu droplet](#create-digital-ocean-ubuntu-droplet)

[2. Create a new user in Ubuntu](#create-a-new-user-in-ubuntu)

[3. Install .NET SDK in Ubuntu](#install.net-sdk-in-ubuntu)

[4. Deploy our ASP.NET Core 3.1 app to Ubuntu](#deploy-our-asp.net-core-3.1-app-to-ubuntu)

[5. Install and configure NGINX in Ubuntu](#install-and-configure-nginx-in-ubuntu)

## Create Digital Ocean Ubuntu droplet

### Create Digital Ocean account

First of all, you'll need a Digital Ocean account. If you haven't an DO account than you can create an account with this [referral link](https://m.do.co/c/1f04571a4bbe) and you'll get $100 credits to spend in the next 60 days.

### Create Digital Ocean project

Once you're logged in, create a new project by clicking on the **+ New Project** link:

![digital-ocean-create-project 01](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/digital-ocean-create-project-01.png)

In the next screen you'll need to enter an name, description and tell DO what want to do with the project.

![digital ocean create project 02](https://driesdeboosere.dev/blog//files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/digital-ocean-create-project-02.png)

When you're done, click on the **Create Project** button.

![digital ocean create project 03](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/digital-ocean-create-project-03.png)

On the next screen click on the **Skip for now** link below.

Now it's time to create our droplet.

![digital ocean create project 04](https://driesdeboosere.dev/blog//files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/digital-ocean-create-project-04.png)

Click on the **Get Started with a Droplet** button

### Create Digital Ocean droplet

Now it's time to create a droplet! First we have to choose an image distribution, in our case we choose **Ubuntu 18.04.3 (LTS) x64**:

![digital ocean create droplet 01](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/digital-ocean-create-droplet-01.png)

We choose the **Basic** plan for **$5/mo** (scroll to the left):

![digital ocean create droplet 02](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/digital-ocean-create-droplet-02.png) ![digital ocean create droplet 03](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/digital-ocean-create-droplet-03.png)

We **don't need block storage** , so we'll skip that.

Choose a data center region close to your hometown, in my case I'll choose **Amsterdam** :

![digital ocean create droplet 04](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/digital-ocean-create-droplet-04.png)

For the authentication, choose SSH Keys and click on the New SSH Key button:

![digital ocean create droplet 05](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/digital-ocean-create-droplet-05.png)

Then follow the steps described on the right:

![digital ocean create droplet 06](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/digital-ocean-create-droplet-06.png)

Now it's time to finalize and create our droplet. In my case I added **backups** , but for this demo purposes you don't have to.

![digital ocean create droplet 07](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/digital-ocean-create-droplet-07.png)

Now click on the **Create Droplet** button.

Now DO will create this droplet (give it some seconds). When everything is done you'll see the droplet and it's IP address. Something like this example:

![digital ocean create droplet 07](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/digital-ocean-create-droplet-08.png)

If you enter the IP address in your browser you'll get an error. This is normal, because we only have a droplet with Ubuntu. But we have to configure our Linux VPS. Let's do this next.

## Create a new user in Ubuntu

We need to login into our server. We'll do this through SSH. You can download [PUTTY](https://www.putty.org/) or download [PowerShell](https://github.com/PowerShell/PowerShell/releases) (Scroll down to assets to download). In my case I'll use PowerShell.

### Connect with SSH to the server

Open PowerShell and SSH into your droplet through this command to log in to your server as the root user:

```
ssh root@
```

The IP address from my droplet is 167.172.37.58. Change the IP address by your droplets IP address

```
ssh root@167.172.37.58
```

Type **yes** if you get this message:

```
The authenticity of host '167.172.37.58 (167.172.37.58)' can't be established.
ECDSA key fingerprint is SHA256:VodrbvWvtonPzxiFpRiuoq0tTrgZjow+YIGUOXukx7w.
Are you sure you want to continue connecting (yes/no)?
```

By typing yes the connection closes, so I'll need to login again:

```
ssh root@167.172.37.58
```

Now you're asked to enter your passphrase. Enter your passphrase (or paste it with the right mouse button) and hit enter:

```
Enter passphrase for key 'C:\Users\dries.deboosere/.ssh/id_rsa':
```

Now we're logged in to the server as the root user:

```
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-66-generic x86_64)Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-66-generic x86_64)

 * Documentation: https://help.ubuntu.com
 * Management: https://landscape.canonical.com
 * Support: https://ubuntu.com/advantage

  System information as of Sun Aug 9 15:24:27 UTC 2020

  System load: 0.0 Processes: 81
  Usage of /: 4.0% of 24.06GB Users logged in: 0
  Memory usage: 11% IP address for eth0: 167.172.37.58
  Swap usage: 0%

0 packages can be updated.
0 updates are security updates.

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

root@ubuntu-s-1vcpu-1gb-ams3-01:~#
```

### Create new user

First we'll create a new user on the server:

```
adduser USERNAME
```

A little explanation about these commands:

**adduser** : create a new user with the name of USERNAME

**USERNAME** : the username for the new user. In my case I'll use _ **dries** _ as the username

Now enter following commands in PowerShell with your username:

```
adduser dries
```

The user _ **dries** _ is now created:

```
root@ubuntu-s-1vcpu-1gb-ams3-01:~# adduser dries
Adding user `dries' ...
Adding new group `dries' (1000) ...
Adding new user `dries' (1000) with group `dries' ...
Creating home directory `/home/dries' ...
Copying files from `/etc/skel' ...
```

Now your asked to choose a password. Enter the password and confirm your password:

```
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
```

Now your asked about some information. You can fill this in or press ENTER for the default values. In my case I press ENTER and at the end I choose yes by typing **y** :

```
Changing the user information for dries
Enter the new value, or press ENTER for the default
        Full Name []:
        Room Number []:
        Work Phone []:
        Home Phone []:
        Other []:
Is the information correct? [Y/n] y
```

### Give administrator/sudo privileges to our new user

Now our new user needs to get administrator/sudo privileges. So let set this up. To do this we'll need following commands:

```
usermod -a -G sudo USERNAME
```

A little explanation about these commands:

**usermod** : calls the program

**-a** : to add the user to a group

**-G** : to specify the group

**sudo** : stands for **'super user do'**. This will execute root commands as an non-root user.

Now enter following commands in PowerShell with your username:

```
usermod -a -G sudo dries
```

Now I want the same ssh key for the root user and for the new created user (dries). We can copy this key by following commands (change **dries** by your username):

```
cp -r ~/.ssh /home/dries/
sudo chown -R dries:dries /home/dries/.ssh
```

Now restart the SSH service by following command:

```
sudo service ssh restart
```

Now exit the server by typing the exit command:

```
exit
```

Now it's time to login as the new created user:

```
ssh dries@167.172.37.58
```

You'll be asked for the passphrase. Because we copied over the ssh key from root user to dries we can now use the same passphrase from the root user. Enter the passphrase:

```
Enter passphrase for key 'C:\Users\dries.deboosere/.ssh/id_rsa':
```

Now you should see this in PowerShell:

```
dries@ubuntu-s-1vcpu-1gb-ams3-01:~$
```

This means we're now logged in as user **dries** in the server.

## Install .NET SDK in Ubuntu

Now it's time to install .NET on Ubuntu. We can go to the [Microsoft documentation website](https://docs.microsoft.com/en-us/dotnet/core/install/linux-ubuntu#1804-) to see which commands we need to install this on our Ubuntu 18.04 server.

First we install the Microsoft package sources:

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

Then we install the .NET 3.1 SDK:

```
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
```

Next we check if it's installed by running following command:

```
dotnet --info
```

You should see something similar like this:

```
.NET Core SDK (reflecting any global.json):
 Version: 3.1.302
 Commit: 41faccf259

Runtime Environment:
 OS Name: ubuntu
 OS Version: 18.04
 OS Platform: Linux
 RID: ubuntu.18.04-x64
 Base Path: /usr/share/dotnet/sdk/3.1.302/

Host (useful for support):
  Version: 3.1.6
  Commit: 3acd9b0cd1

.NET Core SDKs installed:
  3.1.302 [/usr/share/dotnet/sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.App 3.1.6 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 3.1.6 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

To install additional .NET Core runtimes or SDKs:
  https://aka.ms/dotnet-download
```

## Deploy our ASP.NET Core 3.1 app to Ubuntu

Now it's finally time to publish our ASP.NET Core app to the server. But first we need to make some arrangements. We'll going to be using the instructions from the [Microsoft documentation](https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-3.1) to host our ASP.NET Core app on Linux to deploy our app.

For this tutorial I'll use a simple demo ASP.NET Core 3.1 web application. You can use your own application or else you can clone/download my demo application from my [GitHub repository](https://github.com/Drieze/DriesDeboosere.Dev.Demo).

There are many ways to deploy the files to a server. In this case we will deploy our files through an FTP connection to our server. We can do this through the build in FTP client in Visual Studio or with an FTP client of choice ([FileZilla](https://filezilla-project.org/), ...)

### Create application folder on our server

We'll deploy our app to the **/var/www/** directory from our server. But this doesn't exist yet, so we have to create this folder. We also need to give access to our user we've created and to the **www-data** user. This www-data user will be used to run the app.

Type in following commands in PowerShell and replace **<your-app></your-app>** with the name u want to use for your app.

```
sudo mkdir /var/www/
sudo mkdir /var/www/
sudo chown -R dries:www-data /var/www/
```

### Install an FTP server on Ubuntu

We will install an FTP (File Transfer Protocol) server on Ubuntu so we can transfer our files to Ubuntu.

Make sure that our system packages are up to date by running following command:

```
sudo apt-get update
```

Now it's time to install an FTP server. We will using the common open-source FTP utility **vsftpd**. To install vsftpd enter the following command:

```
sudo apt install vsftpd
```

Enter **Y** to continue

Now start vsftpd by entering following command:

```
sudo systemctl start vsftpd
```

To make sure that vsftpd is launched and enabled at startup entering following command:

```
sudo systemctl enable vsftpd
```

Open your FTP client of choice (for me this is FileZilla) and make a connection by entering the IP address from your server and your credentials (in my case user **dries** ). Now check if you have access to the following path: **/var/www/<your-app></your-app>**.

![](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/filezilla-connection-01.png)

Now we need to config vsftpd so we can upload files. At this moment we can only read files from the server but not upload any file. Open the vsftpd configuration file through PowerShell:

```
sudo nano /etc/vsftpd.conf
```

Find the entry **write\_enable=YES** and uncomment this line. Don't forget to save this configuration.

![](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/vsftpd-write-enable-01.png)

Now restart the vsftpd service:

```
sudo systemctl restart vsftpd.service
```

### Publish our web application

Now open a new PowerShell window and navigate to your solution folder:

![](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/dotnet-publish-01.png)

Type in the following command:

```
dotnet publish
```

You should see something similar like this:

![](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/dotnet-publish-02.png)

Now open your Windows Explorer and navigate to the following folder: **<path to your project>\bin\Debug\netcoreapp3.1\publish</path>**. You'll see that this folder contains several files.

![](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/dotnet-publish-03.png)

These files and folders need to be uploaded to our server. Select all the files and folders and move/drag them to the **/var/www/<your-app></your-app>** folder on the server through an FTP-client.

![](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/dotnet-publish-04.png)

If everything worked correctly, our app is now ready to run. But if you enter the IP address of your server in a web browser, you will see that this is not working (yet!).

![](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/nginx-01.png)

We are almost there! We just need to install a web server on Ubuntu. Let's do that next.

## Install and configure NGINX in Ubuntu

Now it's time to install a NGINX webserver and setup a reverse proxy. A reverse proxy will forward requests made to our server to our app. As a webserver we will use [NGINX](https://www.nginx.com/) and for the configuration of our reverse proxy server we will follow the [Microsoft documentation](https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-3.1#configure-a-reverse-proxy-server).

### Install NGINX

We follow the [NGINX documentation](https://www.nginx.com/resources/wiki/start/topics/tutorials/install/#official-debian-ubuntu-packages) to install NGINX on our Ubuntu release.

We first need to add the repository to our **source.list** file:

```
sudo nano /etc/apt/sources.list
```

At the bottom of the file add following lines:

```
deb http://nginx.org/packages/ubuntu/ xenial nginx
deb-src http://nginx.org/packages/ubuntu/ xenial nginx
```

Exit and save the file. Then enter following commands:

```
sudo apt-get update
sudo apt-get install nginx
```

Run NGINX though following command:

```
sudo service nginx start
```

Enter the IP address from your server in your browser. You should see the default NGINX welcome page:

![](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/nginx-02.png)

### Add an SSL certificate with Certbot (if you have a domain name!)

When you have a domain name that you can redirect to your IP address then you can secure your website with an SSL certificate from [Let's Encrypt](https://letsencrypt.org/) by using [Certbot](https://certbot.eff.org/).

**If you haven't a domain name, then skip this step.**

Add the Certbot PPA and install with following commands:

```
sudo apt-get install software-properties-common
sudo add-apt-repository universe
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot python-certbot-nginx 
```

Next run the following command and enter your e-mail address when asked. Agree with the Terms of Service by typing **A** and add your domain name.

```
sudo certbot --nginx
```

## Forward requests to our app

Now it's time to forward the requests to our app instead of the NGINX welcome page.

Enter following command to configure this:

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

Replace the content of that file with following text:

```
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;
    }
}
```

Now we need to enable the site by linking it to **/etc/nginx/sites-enabled/default** with following command:

```
sudo ln -sf /etc/nginx/sites-available/default /etc/nginx/sites-enabled/
```

We now need to ensure that the default site is included in the http section of the NGINX config file. Edit the file with the following command:

```
sudo nano /etc/nginx/nginx.conf
```

And below, where you'll find

```
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
```

Add the following line below:

```
http{
    ...
    include /etc/nginx/sites-available/default;
}
```

Now restart NGINX:

```
sudo service nginx restart
```

Now start the app by the following command:

```
dotnet //.dll
```

In my case this command will be:

```
dotnet /var/www/driesdeboosere-dev-demo-web/DriesDeboosere.Dev.Demo.Web.dll
```

Type in your browser your IP address now and you should see your website:

![](https://driesdeboosere.dev/blog/files/how-to-deploy-aspnet-core-31-app-to-digital-ocean-linux-droplet/nginx-03.png)

### Create service

The next task is to set up our web application to run as a service, so you don't have to be logged in to your server for your application to run. Ubuntu uses **systemd** by default for managing services. So first we need to create a service file (remember the name of the file as this is what you will reference to control it) by entering following commands:

```
sudo nano /etc/systemd/system/.service
```

In my case:

```
sudo nano /etc/systemd/system/driesdeboosere-dev-demo-web.service
```

Enter the service information:

```
[Unit]
Description=My application service

[Service]
WorkingDirectory=/var/www/
ExecStart=/usr/bin/dotnet /var/www//.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target
```

In my case:

```
[Unit]
Description=My application service

[Service]
WorkingDirectory=/var/www/driesdeboosere-dev-demo-web
ExecStart=/usr/bin/dotnet /var/www/driesdeboosere-dev-demo-web/DriesDeboosere.Dev.Demo.Web.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=driesdeboosere-dev-demo-web
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target
```

Give read, write and execute rights to the folder:

```
sudo chown -R : /var/www/
sudo setfacl -R -d -m u::rwx,g::rwx,o::r /var/www/
```

In my case:

```
sudo chown -R dries:dries /var/www/
sudo setfacl -R -d -m u:dries:rwx,g:dries:rwx,o::r /var/www/
```

Then start the service with following command:

```
sudo service start
```

Or in my case:

```
sudo service driesdeboosere-dev-demo-web start
```

Check if it's running:

```
sudo systemctl | grep 
```

Or in my case:

```
sudo systemctl | grep driesdeboosere-dev-demo-web
```

That's it! Now your web server will keep running your ASP.NET Core app, even if you exit the server.