I'd always wished I could spin up a low cost linux server and throw a website out on it. I'd been secretly jealous of python and node for years. It is also a big reason I'd gotten interested in .NET Core a long time ago. In this article I'll show you how to set up a new Linux server, configure it for running an ASP.NET Core Web Application or API, monitor it and more.

There are a lot of options in cheap / low cost hosting. Big names like Azure & AWS have offerings as do some smaller comapnies like Digital Ocean or Linode. I've used all of the aforementioned providers but ultimately decided to go with Digital Ocean. Their pricing is straight forward, they have a good community, collection articles, and seem like a company I'd like to support. A number of the resources I mention below for further learning are even from their community articles.

Creating A Digital Ocean Account

When I signed up to Digital Ocean the process was pretty straightforward. I got access to my dashboard within a few hours (after they verified I wasn't a spammer or a scammer) and was able to get going pretty quickly.

If you'd like to Sign up for your own Digital Ocean account use this link and you'll get a $10 credit to your account, which is enough to pay for a small server for two months and try this out for yourself!

After signing up for your account I'd recommend enabling Two Factor Authentication as well as adding a Public Key to your account to help increase the security of your account and any servers you spin up in the future.

Create Droplet (Server)

When you create your first Droplet you'll be given a few choices for operating systems (including Ubuntu, CentOS, CoreOS, and if you're feeling really crazy FreeBSD 😁). For the purposes of this article I've used Ubuntu 16.04 x64.

Distro List

Next you'll have to choose a size, for this article I've picked the Standard $5 server. If you don't know which to pick I'd try the cheapest one and then see how it works. You can always scale it up later if you encounter performance issues. Finally you'll need to choose a datacenter region. I recommend whichever is closest to you if you're just learning, or the users of your application if this is for production purposes.

If you didn't add an SSH key to your account, I recommend adding one to this new server while you're setting it up as SSH keys are much more secure than a password. To find out more about setting up your own SSH key check out this article written by the Digital Ocean community.

Connecting to your Droplet

After you've created your Droplet you will be given the IP Address in the list of Droplets. You'll need to use that IP and your password or SSH key to connect to your new server.

Droplet List

On my Windows 10 machines I like to use the WSL command line to SSH in:

ssh -i ~/.ssh/my-key user@ip-address

If this isn't really your style you can also use something like Putty or whatever other SSH client you like.

Setting up your new Droplet

Your new server should be secure from the start, but there are a few things that you can do to increase the security such as creating a new non-root user, adding an SSH key (if you didn't during setup), and setting up a basic firewall. This Digital Ocean article will give you a good start at locking down your new server to make it even more secure before you start putting code on it.

Install .NET Core Hosting Package

If you've made it this far you're doing great! By now you're probably wondering when you're going to run some code on your new server... Well not just yet, first we need to setup the .NET Core runtime. Notice I said runtime, not the SDK. We want this server to be a server, not a development environment and as such we'll be installing the run time.

Let's get that runtime installed! I'll save you some time, the first time I tried to set up the runtime on my server I went to https://dot.net, and followed along with their instructions for setting up the .NET Core runtime on Ubuntu 16.04. Then I happily deployed my code to the server and started it up to this glorious error:

Error:
An assembly specified in the application dependencies manifest (xxx.deps.json) was not found:
package: 'Microsoft.ApplicationInsights.AspNetCore', version: '2.1.1'
path: 'lib/netstandard1.6/Microsoft.ApplicationInsights.AspNetCore.dll'
This assembly was expected to be in the local runtime store as the application was published using the following target manifest
files:
aspnetcore-store-2.0.0-linux-x64.xml;aspnetcore-store-2.0.0-osx-x64.xml;aspnetcore-store-2.0.0-win7-x64.xml;aspnetcore-store-2.0.0-win7-x86.xml

I had to Google around for this one, but eventually found out through the dotnet cli github issue tracker that the runtime also requires the aspnetcore store package as well, which could be installed via apt get but this was not the preferred mechanism. This is when I was introduced to the dotnet-hosting-2.0.0 package which includes the runtime and store packaged for Linux servers.

Before installing the hosting package you'll need to install the "dotnet product feed". You can find it here - https://www.microsoft.com/net/core#linuxubuntu or for our new Ubuntu 16.04 server you can run this (that I pulled from the previous URL):

sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > /etc/apt/sources.list.d/dotnetdev.list'

Make sure you update your apt-get or you wont be able to install any of the .net core packages, then install the hosting package:

sudo apt-get update  # update the packages
sudo apt-get install dotnet-hosting-2.0.0 # install the Linux Server Hosting runtime & store

You should now have everything you need installed to run your .NET Core application. The package will install the runtime files to /usr/share/dotnet/. You can run a .NET Core application using a command such as /usr/share/dotnet/dotnet YourCode.dll.

In the second article in this series I'll cover Deploying ASP.NET Core To Linux. For now you can use your favorite SFTP or SCP tool to transfer your files over.

Setting Up Nginx on Your Droplet

Nginx is a handy tool and while it isn't required, I recommend it because it will give you some flexibilty both now and in the future. For now we'll just use it as a reverse proxy to forward requests to our applicatoin running with Kestrel.

First install Nginx with apt-get and start it up:

sudo apt-get install nginx  # install Nginx
sudo service nginx start    # start it for the first time

Configure Your ASP.NET Core Site With Nginx

Nginx stores its server block configurations in /etc/nginx/sites-available, this is where we'll need to setup a new site and where we will supply the configuration settings. Let's create our new server block and make it point to our web app that is running:

sudo nano /etc/nginx/sites-available/my-new-site.com

When nano is loaded add the following to the configuration:

server {
    listen 80;
    location /my-new-site {
        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;
    }
}

This configuration assumes that your .NET Core application is running on port 5000, if you have it running on another port update the proxy_pass line to use the port it is running on. After you've completed your edits of the Nginx config you will need to make a symbolic link to the config in the /etc/nginx/sites-enabled/ directory:

sudo ln -s /etc/nginx/sites-available/my-new-site.com /etc/nginx/sites-enabled/

After you're done making changes you can run sudo nginx -t to test your configuration files and make sure everything is good. When the test is successful restart Nginx by running sudo systemctl restart nginx.

Now to test your site is working properly you can run curl localhost:80/my-new-site to test out your site from the command line, or go to a browser window and try the address http://YOUR-IP/my-new-site` where "YOUR-IP" is the IP for your server.

To learn about a better way to set up Nginx and your sites take a look at this Digital Ocean community article.

Setting Up HTTPS With Let's Encrypt and Certbot

HTTPS is essentially required these days. If you want your site to rank in search results or you just want to protect your site's data you'll need to set up HTTPS. Luckily you can now set it up fairly easily and for free thanks to Let's Encrypt.

Since we have shell access to our new server we'll set up Certbot to handle certificate issuing and automate renewal as well. Head over to Certbot's "Nginx on Ubuntu 16.04 setup instructions" which will get you set up with a certificate in no time.

Certbot Logo

Once you've got your SSL set up, head over to SSL Labs and test out your server. It will take a couple minutes to analyze your setup, but will eventually give you a grade on your setup and some tips on how to make it better (more secure).

Keep Your ASP.NET Core Site Up with Systemd

Now that your site is running and is pretty secure, how do you make sure it stays running and starts up after reboots? The answer is systemd, which is a system init and management process on our new server.

To get started you first need to create a new service definition:

sudo nano /etc/systemd/system/kestrel-mynewsite.service

I like to preface the service name with "kestrel" as this will be managing a kestrel instance that runs the "my-new-site" application. Next we'll need to set up the service file:

[Unit]
Description=My new ASP.NET Core Application

[Service]
WorkingDirectory=/var/www/my-new-site
ExecStart=/usr/share/dotnet/dotnet /var/www/my-new-site/mynewsite.dll
Restart=always
RestartSec=10
SyslogIdentifier=my-new-site
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production

[Install]
WantedBy=multi-user.target

Save and exit nano, then enable the service and start it:

sudo systemctl enable kestrel-mynewsite.service  # enable the service so we can monitor it, etc
sudo systemctl start kestrel-mynewsite.service   # start the service

Now that we've told the service to start we can check the status of it to verify it is running:

sudo systemctl status kestrel-mynewsite.service

We can also make the site unavailable by stopping the service:

sudo systemctl stop kestrel-mynewsite.service

Finally you can restart your service like so:

sudo systemctl restart kestrel-mynewsite.service

For more information on managing systemd services check out this Digital Ocean article.

Dealing With Logs on Linux For ASP.NET Core

One "freebie" that comes along with managing your site through systemd is better log management. Systemd provides centralized log management for the processes it manages. The logs are collected and managed by "the journal" also known as "journald".

To view logs from your system you could run sudo journalctl but that would show you ALL THE LOGS. Instead you'd probably like to see only the logs for your application:

me@my-awesome-droplet:/etc/systemd/system$ sudo journalctl -fu kestrel-mynewsite.service
[sudo] password for me:
-- Logs begin at Thu 2017-10-26 07:33:40 UTC. --
Oct 26 20:19:22 my-awesome-droplet my-new-site[1290]: [20:19:22 INF] Request starting HTTP/1.1 GET http://localhost:5000/
Oct 26 20:19:22 my-awesome-droplet my-new-site[1290]: [20:19:22 INF] Request finished in 61.6359ms 404

What we've asked journalctl to do is show us only logs from our service "kestrel-mynewsite.service", and then to "follow" the logs so we'll see new log items come in as they happen on the system and are entered into the journal. You'll notice that the logged items displaying include "my-awesome-droplet my-new-site" which is the name of the system followed by the SyslogIdentifier we set up in the systemd service definition.

The journal allows you to filter messages even further. We can view logs from today only:

sudo journalctl -u kestrel-mynewsite.service --since today

We can even filter messages to see only specific log levels:

sudo journalctl -u kestrel-mynewsite.service -p 0

The above command will show us only errors from our systemd service. With the -p (or --priority) argument you can enter a value between 0-7 (errors to debug respectively) to see more logs which are less severe, you're "infos" and "debugs" are less severe right?

For more information on using journald & journalctl check out this Digital Ocean article.

Conclusion

If you've been following along with this post you should now have your application running on you new server. If not you should have a good idea of what needs to be done and some additional resources to check out to get a deeper understanding of running your ASP.NET Core application (or API) on Linux.

As I mentioned earlier, in the second article in this series we'll be Deploying ASP.NET Core To Linux. Check it out to learn how to more easily and consistently deploy your code to your Linux server.