By James Naylor
Published on 24 Mar 19
Share on
5 min read

Small Linux virtual private servers (VPS) are a super cheap option to host .NET Core apps.

I'm going to set up an app on a brand new VPS from INIZ - a simple single CPU server with 512MB RAM, 40GB of storage and 1TB bandwidth is more than enough for most simple apps and only costs £15 a year!

You can pick which linux distribution to run - I like Ubuntu - so these instructions are for Ubuntu 16.04 LTS.

Lets run through the steps:

  1. Disable root access
  2. Install .NET SDK
  3. Publish app to the Server
  4. Setup reverse proxy
  5. Create service
  6. Add an SSL certificate with Certbot

Disable root access

First thing is to disable root access. There are many articles online on how to do this - but while developing I tend to just create a new user and give it sudo privileges.

First log in to your server as root, create a new user, and give it a strong password

$ adduser james
$ usermod -aG sudo james

Install nano and then edit sshd_config

$ sudo nano /etc/ssh/ssdh_config

Change PermitRootLogin to no and add an AllowUsers entry

PermitRootLogin no
AllowUsers james

Finally restart the ssh service

$ sudo systemctl restart sshd

You can now reconnect to your machine with your new user name.

Install .NET SDK

Following the linux install instructions from the .NET website, install the .NET Core SDK

Firstly install the Microsoft package sources:

$ wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb
$ sudo dpkg -i packages-microsoft-prod.deb

And then install the .NET SDK

$ sudo apt-get install apt-transport-https
$ sudo apt-get update
$ sudo apt-get install dotnet-sdk-2.2

Make sure it's installed by running

$ dotnet --info
.NET Core SDK (reflecting any global.json):
 Version:   2.2.104
 Commit:    73f036d4ac

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

Host (useful for support):
  Version: 2.2.2
  Commit:  a4fd7b2c84

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

.NET Core runtimes installed:
  Microsoft.AspNetCore.All 2.2.2 [/usr/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.2.2 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.2.2 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
To install additional .NET Core runtimes or SDKs:
  https://aka.ms/dotnet-download                                 

Publish app to the Server

We are going to primarily be using the instructions from Microsoft Docs to Host ASP.NET Core on Linux to deploy our app.

We will deploy our app to the /var/www/ directory - so first we need to create a folder for our application and give access to both our user and the www-data user (which we will be using to run the app later)

$ sudo mkdir /var/www/<your app>
$ sudo chown -R james:www-root /var/www/<your app>

We then need to copy our application to the server - you could just copy it to the server using FTP or SCP - but there is an excellent tool available called dotnet-publish-ssh

To use it you simply add a tool reference to your project's csproj file:

<ItemGroup>
    <DotNetCliToolReference Include="DotnetPublishSsh" Version="0.1.0" />
</ItemGroup>

From your build machine, run

$ dotnet restore
$ dotnet publish-ssh --ssh-host <address of your server> --ssh-user <username> --ssh-password <your password> --ssh-path /var/www/<path to your site>

If everything worked correctly, your app is now on your server and ready to run.

Setup reverse proxy

A reverse proxy will forward requests made to our server to our app. We will use NGINX. Again, we will be following the directions on the Microsoft Docs site to Configure a reverse proxy server.

We follow the docs from NGINX (here) to install the Ubuntu release.

First we need to add the repository to our sources.list file. We will use nano again

$ sudo nano /etc/apt/sources.list

And add the following lines to the bottom of the file

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

Then simply run

$ sudo apt-get update
$ sudo apt-get install nginx

You can check that NGINX is running starting it with:

$ sudo service nginx start

If you navigate to your server's url, you should now see the default welcome page:


In my case, my server already had apache2 installed and running on port 80 - I had to disable this with:

$ sudo service stop apache2
$ sudo update-rc.d apache2 disable

Next we need to configure NGINX to forward request to our app. You need to modify the /etc/nginx/sites-available/default file and replace the contents with:

server {
    listen        80;
    server_name   <your domain>;
    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;
    }
}

Your will then need to enable the site by linking it to etc/nginx/sites-enabled/default with

$ sudo sn -l /etc/nginx/sites-available/default /etc/nginx/sites-enabled/

Also ensure that your default site is included in the http section of the config file for NGINX at /etc/nginx/nginx.conf - there should be a line like:

http{
    ...

    include /etc/nginx/sites-available/default;
}

Once you have restarted the NGINX service, start your app with

$ dotnet <myapp>.dll

If you then visit your VM in the browser, you should see your wepapp running! 👏

Create service

The next task is to set up our webapp 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 (remender the name of the file as this is what you will reference to control it):

$ sudo nano /etc/systemd/system/<myapp>.service

Enter your service information

[Unit]
Description=My application service

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

[Install]
WantedBy=multi-user.target

You can then start the service with

$ sudo service <myapp> start

You can check if it is running with

$ sudo systemctl | grep <myapp>
<myapp>.service                         loaded active     running   My application service description

Add an SSL certificate with Certbot

The final step is to secure our website with an SSL certificate from Let's Encrypt by using certbot. This is essential these days as all major browsers will flag if a website is not secure. Fortunately it's incredibly simple these days to set up an SSL certificate.

Add the Certbot PPA and install with

$ 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 

Then simply run

$ sudo certbot --nginx

And follow the prompts. If you have entered your domain in the NGINX site configuration, certbot will ask you which domain you would like to create a certificate for and ask you if you want to redirect traffic to HTTPS.

If everything goes to plan when you visit your site you will have a nice green padlock in the address bar!


Congratulations! You have you app up and running on your VM! 🎉