Publishing an ASP.NET Core website to a Linux host

  • Gérald Barré

I recently move my web site to a Linux host, remember, .NET Core is multi-platform 😃 This choice is mainly motivated by the price. Indeed, you can find many cheap VPS providers (Virtual Private Server) on the internet. For instance, you can choose OVH. They have great VPS for about 3€ per month (I'm not paid by them, but I've been using their services for a few years without any issue).

Hosting a site on Linux is not as easy as hosting on Windows, at least for me. I think this is mainly because I don't use Linux daily 😃

So, this is the steps I followed to deploy my websites on Ubuntu 16.04 and use Let's Encrypt for SSL.

I use vim to edit files. If you are not familiar with it, you may prefer nano. Just replace vim with nano in the commands lines.

#Step 1 - Connect to the VPS using ssh

Once you get your VPS, you should have an IP address and the password of the root user. This allows connecting to the machine using SSH. If you are running Windows 10, you can enable the Windows subsystem for Linux (WSL) feature. Then, you can use the native SSH command.

ssh root@ip

#Step 2 - Change the root password

For obvious security reasons, you must change the password of the root user using the passwd command:


Then, enter the new password.

#Step 3 - create a non-root user

Using the root user is not a good practice. Instead, you should create a new user:

adduser myuser          # you'll be prompt for the password
usermod -aG sudo myuser # Add the user to the sudo group to be able to use admin commands
exit                    # terminate the session

Then, reconnect to the server using the new user:

ssh myuser@ip

#Step 4 - Update the server

Before doing anything, you should install updates:

sudo apt-get update        # Fetches the list of available updates
sudo apt-get upgrade       # Strictly upgrades the current packages
sudo apt-get dist-upgrade  # Installs updates (new ones)
sudo reboot

If you prefer updates to be installed automatically, you can use unattended-upgrades:

sudo apt-get install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

#Step 5 - Configure the firewall

By default, all ports are opened. For a web server, you only need to open the ports 80 and 443. Don't forget to leave the port 22 opened, or you won't be able to use SSH anymore.

sudo ufw default deny           # deny all incoming connections
sudo ufw default allow outgoing # allow all outgoing connections
sudo ufw allow ssh              # allow the incoming ssh port
sudo ufw allow 80/tcp           # allow the incoming 80 port
sudo ufw allow 443/tcp          # allow the incoming 443 port

sudo ufw enable                # enable the firewall
sudo ufw status verbose        # check everything is ok

#Step 6 - Copy your site to the server

If you don't have an ASP.NET Core app yet, you can easily create one using only one command:

dotnet new mvc

You should use the Microsoft.AspNetCore.HttpOverrides package and app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.All }) to get the actual url instead of localhost:5000 in the application as the web site behind a reverse proxy.

Then, copy the publish output to /var/www/mysite using filezilla, scp or rsync:

# compile and generate the website files
dotnet restore
dotnet publish -c release

# Copy the files to the server (replace ip by the actual ip address)
scp -r ./bin/release/netcoreapp1.1/publish/* myuser@ip:/var/www/mysite

#Step 7 - Install .NET Core

To run the website, you must install the .NET Core shared runtime (unless you create a self-contained application).

# If not Ubuntu 16.04, read the doc
sudo sh -c 'echo "deb [arch=amd64] xenial main" > /etc/apt/sources.list.d/dotnetdev.list'
sudo apt-key adv --keyserver hkp:// --recv-keys 417A0893
sudo apt-get update

# Replace 1.1.1 by the version your application need
sudo apt-get install

info: At this step, you should be able to start the application on the server using /usr/bin/dotnet /var/www/mysite/mysite.dll. Once you have validated it works by checking the console output, stop the application using CTRL+C.

#Step 8 - Start the web site

You must configure systemd to start dotnet as a service.

sudo vim /etc/systemd/system/kestrel-mysite.service

    ExecStart=/usr/bin/dotnet /var/www/mysite/mysite.dll
    RestartSec=10    # Restart service after 10 seconds if dotnet service crashes

sudo systemctl enable kestrel-mysite.service # register the service
sudo systemctl start kestrel-mysite.service  # start the service
sudo systemctl status kestrel-mysite.service # check the service is running

Now you can access the website on the port 5000. You can test it using the wget command:

wget http://localhost:5000

#Step 9 - nginx

Kestrel is a good web server. However, Microsoft advice to not expose it directly to the internet. Instead, you should place it behind a reverse proxy such as nginx.

sudo apt-get install nginx
sudo vim /etc/nginx/sites-available/default

Replace everything with:

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 $host;
        proxy_cache_bypass $http_upgrade;

Test the configuration:

sudo nginx -t

And reload the configuration:

sudo nginx -s reload

Now, the website is visible on the internet. You can open your favorite web browser, and navigate to http://ip.

#Step 10 - Viewing logs

For debugging purpose, you can view the logs of the dotnet process using the following command:

sudo journalctl -fu kestrel-mysite.service


Your website is now online on the 80 port. Don't hesitate to leave a comment if I forgot something. Again, I'm not a Linux expert 😃

The next post is about securing the website using a free SSL certificate provided by Let's Encrypt.

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub