Setting up .NET Core service/daemon on Debian Linux OS

How to run .NET Core application as daemon on Linux

I found a lot of articles out here on this subject, but non of them actually made the daemon work from the first time. There was always some catch I had to chase and found in some other article posted online.

In this article I will try to cover as much as possible how to setup .NET Core daemon working on a clean Debian 9 Linux machine. Let's start with the steps

I use Visual Studio 2017 and Windows as my development environment, so I will do the development and compilation on my Windows machine and just move binaries to a Linux machine where we are going to setup the service/daemon.

.NET Core project


Service implementation on Linux host has been updated for .NET Core 2.1. Please check this article for more details how to properly implement service for Linux environment with .NET Core 2.1 which handles SIGTERM for clean service stop

Unlike Windows, Linux does not have special concept and type of application as a service. Instead any console application can work as a service. Because of this, we are going to create a simple .NET Core console application.

It won't to any complex computation, we'll just save current date and time to a file on the filesystem every 5 seconds. Here is the sample code of Program.cs class

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;
namespace Service.Sample
class Program
static readonly CancellationTokenSource tokenSource = new CancellationTokenSource();
static readonly String outFolderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "output");
static readonly String outFilePath = Path.Combine(outFolderPath, $"{DateTime.Now.ToString("yyyy-MM-dd")}.txt");
static void Main(string[] args)
AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
            Console.WriteLine($"Output file: {outFilePath}");
            File.AppendAllLines(outFilePath, new List<String>() { "------------------- SERVICE START ------------------- " }, Encoding.UTF8);

            while (!tokenSource.Token.IsCancellationRequested)
                File.AppendAllLines(outFilePath, new List<String>() { DateTime.Now.ToString() }, Encoding.UTF8);

            File.AppendAllLines(outFilePath, new List<String>() { "------------------- SERVICE STOP ------------------- " }, Encoding.UTF8);
        private static void CurrentDomain_ProcessExit(object sender, EventArgs e)
            File.AppendAllLines(outFilePath, new List<String>() { "------------------- PROC EXIT SIGNAL ------------------- " }, Encoding.UTF8);


At the end of the article I will explain why I put two places for writing service stop event.

From Visual Studio publish your project and copy output folder to your Linux machine to /etc/SampleService folder via FTP. If you do not have permissions to copy to this folder via FTP, upload published folder to your home and then just simply copy it from the terminal on Debian host.

Setting up .NET Core

I already explained how to install .NET Core in article How to setup .NET Core 2 on Debian or Ubuntu Linux distro the easy way but I will make some small adjustments to the installation to make it more usable for running services, so I will shortly explain here how to setup .NET Core support.

Execute the following commands one by one in your terminal

mkdir $HOME/dotnet   
cd $HOME/dotnet   

tar zxf dotnet-sdk-2.0.3-linux-x64.tar.gz

sudo cp -r ./dotnet /bin

sudo apt-get install -y libunwind-dev

export PATH=$PATH:/bin/dotnet 

After this you will have .NET Core support installed on your machine. To double check execute the following command in terminal

/bin/dotnet/dotnet --version

You should get 2.0.3 as output

Service/Daemon setup

First thing is to check that we have systemd package installed

sudo apt-get install -y systemd

Second thing is to setup the user we are going to run our service under. I named it dotnetuser

useradd -m dotnetuser -p dotnetpass

Finally we can go and setup the service configuration. Navigate to systemd configuration folder 

cd /etc/systemd/system

Open nano, paste the following content and save as dotnet-sample-service.service

Description=Dotnet Core Demo service

ExecStart=/bin/dotnet/dotnet Service.Sample.dll


More about .service configuration files and options you can include in your service configuration files you can find at so I'll not go deeper into this.

Now we need to tell systemd to reload service configurations and create metalink for our service

systemctl daemon-reload
systemctl enable dotnet-sample-service.service

Our service is ready now for start

systemctl start dotnet-sample-service.service
systemctl status dotnet-sample-service.service

Start Net Svc

Since our code will try to write file to /etc/SampleService/output folder, our service start might fail because of insufcient permissions to perform writing to this location. It's not a big deal, just go create the folder and change the cmod

mkdir /etc/SampleService/output

chmod 777 mkdir /etc/SampleService/output

Another way to check if your service is up and running is to check it via top or my favorite htop package. The first one comes pre-installed but if you want to use htop you will have to install it

sudo apt-get install htop

Htop Net Svc

To stop the service, just call systemctl stop.

systemctl stop dotnet-sample-service.service

systemctl status dotnet-sample-service.service

Stop Net Svc 

Tracing service log

As in any .NET Core application, you can setup logging, but you can also just write everything to console. It is much easier for debugging and guess what, you can get all these values from the service run. 

All these values are traced and you can easily fetch them

journalctl --unit dotnet-sample-service --follow

Handling service stop in your code

Unlike windows service, .NET Core console is not aware of service stop request from the systemctl command, there for, if you check the output file of this sample service upon stop, you will not find the comment line which comes after while loop.

This is something that is missing in .NET Core so far, but considering the speed of framework evolving, I am sure it will be introduced in a future releases



Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.

About the author


Dejan is a passionate Software Architect/Developer. He is highly experienced in .NET programming platform including ASP.NET MVC and WebApi. He likes working on new technologies and exciting challenging projects

CONNECT WITH DEJAN  Loginlinkedin Logintwitter Logingoogleplus Logingoogleplus


read more


read more

Umbraco CMS

read more


read more

Comments for this article