Running a .NET Core Web application in Linux

(Linux distribution and version: Ubuntu 16.04)

After deploying a .NET Core web application’s files, one can start the app by running:
user@machine-name:/$ dotnet TheApp.dll

This will result in Kestrel running the app under http://localhost:5000.

To make the app listening for requests on a different port, one can run the above as follows:

user@machine-name:/$ ASPNETCORE_URLS="http://127.0.0.1:5001" dotnet TheApp.dll

The above sets the environment variable ASPNETCORE_URLS for the current running context referring to port 5001.

When we exit the terminal or the ssh session (in which the app has been run) the app will terminate. That is not what we usually want. We want it to be running in the background – in Linux such app is referred to as daemon (Windows OS equivalent of Windows Service).

Setting up the web app to run independently in the background

In order to configure the app to run as a daemon here is what we need to do:
1. Create a systemd service definition file
2. Enable the service
3. Start the service
4. Check the status
5. Check the logs to verify that there have been no errors along the way

Step 1:
user@machine-name:/$ sudo nano /etc/systemd/system/kestrel-app2.service

Note that the below file contents is a specific example of a possible way of setting up a service running a released build of an application that got deployed from Visual Studio Team Services. OFF-TOPIC: In an ultimate solution, I think all the files should get copied into a fixed directory after every download through VSTS agent during the release process.

Add the following contents:

[Unit]
Description=DotNetCore app 'TheApp'

[Service]
WorkingDirectory=/home/myuser/vstsagent/_work/r1/a/DotNetCoreBuild-CI/drop/TheApp
ExecStart=/usr/bin/dotnet "/home/myuser/vstsagent/_work/r1/a/DotNetCoreBuild-CI/drop/TheApp/TheApp.dll"
Restart=always
RestartSec=100
SyslogIdentifier=dotnet-theapp
User=myuser
Group=www-data
Environment=ASPNETCORE_URLS=http://127.0.0.1:5001
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=PATH=/home/myuser/bin:/home/myuser/.local/bin:/home/myuser/.nvm/versions/node/v6.11.4/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

[Install]
WantedBy=multi-user.target

It is important to set the WorkingDirectory to the directory where the app resides, so that the app can find any requested resources.
We can use multiple Environment entries to provide any required Environmental Variable.

Step 2:
user@machine-name:/$ sudo systemctl enable kestrel-theapp.service

Step 3:
user@machine-name:/$ sudo systemctl start kestrel-theapp.service

Step 4:
user@machine-name:/$ sudo systemctl status kestrel-theapp.service

If all good then one could see something like below:
Loaded: loaded (/etc/systemd/system/kestrel-theapp.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2017-12-09 10:35:51 CET; 32min ago
Main PID: 19114 (dotnet)
Tasks: 17
Memory: 33.6M
CPU: 2.108s
CGroup: /system.slice/kestrel-theapp.service
└─19114 /usr/bin/dotnet /home/myuser/vstsagent/_work/r1/a/DotNetCoreBuild-CI/drop/TheApp/TheApp.dll

Otherwise, to troubleshoot, taking Step 5 should reveal more info on any problems.

Step 5:
sudo journalctl -fu kestrel-theapp.service --since today

The above will display all the logs related to the run as well as everything that the app output to the console. If any errors have occurred one should see them there.

Possible errors:
1. Permission to open files denied.
Solution:
Stop the service sudo systemctl stop kestrel-theapp.service
Go to the path where tha app is located and then execute (example path of the release location of the VSTS agent for a specific release definition):
~/vstsagent/_work/$ sudo chmod -R 755 r1/
The above will change the permissions recursively on all files in all subdirectories from the directory r1.
Start the service sudo systemctl start kestrel-theapp.service

2. Permission to write to files.
sudo chown www-data:www-data ./drop/
sudo chmod 775 ./drop/
should fix the issue, however I am not sure about the security of this approach – it gives write access to the whole group www-data and others can only read

After every update of the file kestrel-theapp.service, one will need to run:
user@machine-name:/$ sudo systemctl daemon-reload

That is all. With the above we can have our web application running in the background.

Now it will be good to keep the app behind an http server proxy such as nginx that can face the real world. Setting up nginx to act as a proxy for our app is a subject of another post.

Leave a Reply

Your email address will not be published.