I was pleasantly surprised by how easy it was to setup and install ASP.NET Core 2.1 on Linux. I did it for the first time in 15 minutes with no previous experience with .NET Core on Linux. I did it the second time, in production, in 5 minutes by following these instructions.

In this article, I show you how to install the .NET Core runtime on CentOS, how to get a sample ASP.NET Core project running on Kestrel as a service for reliability, and how to configure both the code and the firewall to enable remote access. Finally, I discuss what I would do differently for actual production usage.

Step 1 - Install Runtime

To run ASP.NET Core on Linux, you'll need to start by installing the runtime.

On CentOS 7, I had to add an RPM package containing the yum references, update yum, and then install the .NET Core runtime:

sudo rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm
sudo yum update
sudo yum install aspnetcore-runtime-2.1

Microsoft provides similar instructions for different Linux Distributions including RHEL, Ubuntu, Debian, Fedora, CentOS, openSUSE, and SLES.

If you want to compile and do development as well, you'll want to install the SDK instead of the runtime. On CentOS, I would install the SDK using:

sudo yum install dotnet-sdk-2.1

Step 2 - Publish and Deploy

The next step is to publish and deploy your project.

Create a Sample Project

To get started quickly, I created a new demo ASP.NET Core 2.1 project, by running this command:

dotnet new razor -o CoreTest

For this command to work, you'll need to have installed the SDK and not just the runtime. I simply ran this on my local development machine as I only installed the runtime on the Linux server.

Optionally add support for Remote Access

By default, the ASP.NET Core 2.1 project will run on the Kestrel web server on localhost.

If you want to be able to access the website remotely from other computers, you'll need to bind it differently.

To do this, I went into the newly created project files and opened Program.cs. In here I added a call to the UseUrls method as follows:

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>

This binds the ASP.NET Core website to all IPs on the server, instead of just localhost, which is the default.

Compile and Deploy

To compile the project, I simply ran:

dotnet publish --configuration Release

This builds and puts all the files required for deployment into the bin/Release/netcoreapp2.1/publish folder by default.

To deploy, I simply copied all the files and directories from the publish folder into /home/coretest on the Linux server.

I copied the files using SmarTTY, but you could easily use FTP or any other method to move the files.

Step 3 - Run the Web Application

Now that .NET Core is installed, and the project is deployed, we want to run it.

Run Directly

The simplest method is to go into the website directory, /home/coretest, and execute:

/usr/bin/dotnet CoreTest.dll

This runs the application immediately but is susceptible to crashes and needs to be manually started after any server restarts.

Run as a Service

It is much better to run the website as a service, so that it is run automatically at start-up after restarts and is restarted automatically if it crashes.

Service Definition

To run the website as a service, you'll need to create a service definition file. I called mine kestrel-coretest and created it in this location:


In this file, I added the following contents:

Description=.NET Core Test App

ExecStart=/usr/bin/dotnet /home/coretest/CoreTest.dll


You'll need to change the User variable to something appropriate for your server and make sure the deployment files have appropriate permissions.

Start the Service

After saving the service definition file, enable the service using:

sudo systemctl enable kestrel-coretest.service

You can then start the service using:

sudo systemctl start kestrel-coretest.service

And check the status of the service using:

sudo systemctl status kestrel-coretest.service

You can also check which web applications are running using:

ps -A all | grep dotnet

This is particularly useful when running multiple websites on different ports as it will list all those that are running.

Step 4 - Test on Localhost

You can now test the website by trying to access it via localhost. From your SSH connection, use wget as follows:

wget http://localhost:5000

This should download the home page and store it in a file named index.html in the current directory. If you haven't got wget, you can install it using:

sudo yum install wget

Step 5 - Optionally Open Firewall and Test Remotely

If you enabled remote access in step 2, you can now open port 5000 in the firewall and try connecting from a remote computer.

You can open port 5000 using Firewalld:

sudo firewall-cmd --add-port=5000/tcp --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

If this worked, you should see 5000/tcp in the ports section after running the last command. It should look something like this:

public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  services: ssh dhcpv6-client
  ports: 5000/tcp
  masquerade: no
  rich rules:

You can now try accessing the website remotely from a browser. If the IP address of your Linux server is, go to in your browser to access it and you'll see the demo site:

ASP.NET Core 2.1 Demo Site

Bonus Tip - Uninstalling the SDK or Runtime

If you install the SDK and then decide you only need the runtime or you simply want to remove .NET Core.

On CentOS, you can remove the SDK using:

sudo yum remove dotnet-sdk-2.1

Similarly, you can remove the Runtime using:

sudo yum remove aspnetcore-runtime-2.1

You may then also want to remove any unused dependencies that came along with the SDK or Runtime using:

sudo yum autoremove

Changes for a Production Setup

This tutorial has shown how to install .NET Core and get an ASP.NET Core website working quickly.

But I wouldn't actually run it like this in production as Kestrel is a rather basic web server.

You'll want to put a more fully-featured web server such as IIS, Nginx, or Apache in front of Kestrel.

My Linux Deployment

On my Linux deployment, I'm going to disable remote access by removing UseUrls from step 2 and undoing step 5. I'm then going to run Apache in front of Kestrel, which will act as a reverse proxy to Kestrel on localhost.

In my case, this is going to let me slowly migrate some existing websites from PHP to C# and .NET Core. I plan to reverse proxy some URLs to .NET Core, while continuing to serve other URLs using PHP. This will allow me to migrate these websites over time.