Deploying .Net Core on Ubuntu 16.04

This article details how to build and deploy .Net Core applications onto a virtual server running Ubuntu 16.04. In this example, we will be using an Elastic Cloud Service provided by Alibaba Cloud. The application we are hosting is a web server listening on port http://localhost:5000, the application will be run as a Linux systemd process serving web traffic from Nginx.

Part-1: Installing .Net Core On Linux Operating Systems

‘Prerequisites for .NET Core on Linux’ (source) contains detailed documentation on how to install .Net Core on various operating systems. For the purpose of this article, I will show a step-by-step guide on how to install .Net Core on a new machine Instance running Ubuntu 16.4.

Connect to your machine instance using any SSH compatible tool(s). Use a user that has sudo privileges to avoid permission issues. Assuming that your instance is new, you will need to download additional tools and update some configuration.

To Avoid encountering ‘sudo: unable to resolve host‘, check the hostname file (/etc/hostname) only contains an entry for the name of the machine:

sudo vi /etc/hostname

Also check that the machine host file (/etc/host), for the following :

127.0.0.1 localhost.localdomain localhost
127.0.1.1 my-machine

You may also need to install apt-get command if not already installed:

sudo apt-get install software-properties-common

Now you are ready to download and install .Net Core:

curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg
sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg

# Set up the desired version host package feed.
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'
sudo apt-get update

sudo apt-get install dotnet-sdk-2.1.3

# Verify that .Net Core is installed
dotnet --version

Part-2: Building .Net Core Projects for Linux

.Net Core application can be built in two ways for deployment. One way is called Framework Dependent Deployment – such deployments assume the target machine has all require .Net Core libraries other than the application and any third-party dependencies.

Another way is to build .Net Core applications in a self-contained deployment. Such deployments do not depend on any shared libraries pre-existing on the target machine
See link for more details regarding .Net Core builds (source).

# Framework dependent deployment
dotnet build --configuration Release --runtime ubuntu.16.04-x64

# Self dependent deployment
dotnet publish --configuration Release --runtime ubuntu.16.04-x64

Part-3: Deploying application files

When you are ready to deploy your application. You’ll need a way to transfer your published files onto an instance. This can be achieved using SSH (e.g.: WinSCP) /FTPS protocols to connect and upload files onto a Linux environment. In this article, we will host our applications as a daemon service using NGIX as a reverse-proxy web server.

Follow the article if you haven’t already set up an Nginx server and user (source).

Below we will assume you have a pre-configured Nginx, the next part will demonstrate how to host your .Net Core application on a Linux daemon service. First, we will need to create the daemon service by creating a new service file under systemd.

# Using a linux file editor like vi or nano (may need to install if you haven't already)
sudo nano /etc/systemd/system/kestrel-name_of_the_service.service

It is best practice to not run the service under root account. Create a user if necessary and grant the right file permissions (source). The content of the service file should look similar to the following:

# Place the following into the new service file 
# assuming that /home/user_name/directory_containing_application is where the application is running from
# user_name should have the required permissions
[Unit]
Description=name_of_the_service on Ubuntu

[Service]
WorkingDirectory=/home/user_name/directory_containing_application
ExecStart=/usr/bin/dotnet /home/user_name/directory_containing_application/dotnet_core_application.dll
Restart=always
RestartSec=10
SyslogIdentifier=dotnet-name_of_the_service 
User=user_name_other_than_root

[Install]
WantedBy=multi-user.target

Once you have configured the service, start the service and check its status. Note that whenever you change the service file settings, you will need to restart the daemon service (stop/start) and restart Nginx server. Assuming your application is listening on port 5000, the service is now ready to serve the request on that port.

# Enable the service
# systemctl disable kestrel-name_of_the_service .service
systemctl enable kestrel-name_of_the_service .service

#Start service
systemctl start kestrel-name_of_the_service .service
# systemctl stop kestrel-name_of_the_service .service

# Check status
systemctl status kestrel-name_of_the_service .service
# Checking service logs
sudo journalctl -fu kestrel-name_of_the_service .service

# restart Nginx
sudo nginx -s reload

Part-4: Redirect request to .Net application

After setting up your .Net application to run as a systemd service, continue to configure update Nginx server block to redirect requests to the service. Below is an example of a reverse proxy setup for a .Net Core service running on Kestrel on port 5000.

server {
    listen 80;
    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 $http_host;
        proxy_cache_bypass $http_upgrade;
    }
}

The next step is to set up SSL for your Nginx server.