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.

Shell
bash
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:

Shell
passwd

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:

Shell
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:

Shell
ssh myuser@ip

#Step 4 - Update the server

Before doing anything, you should install updates:

Shell
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:

Shell
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.

Shell
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:

Shell
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:

Shell
# 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).

Shell
# If not Ubuntu 16.04, read the doc https://www.microsoft.com/net/core#linuxubuntu
sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ xenial main" > /etc/apt/sources.list.d/dotnetdev.list'
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 417A0893
sudo apt-get update

# Replace 1.1.1 by the version your application need
sudo apt-get install dotnet-sharedframework-microsoft.netcore.app-1.1.1

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.

Shell
sudo vim /etc/systemd/system/kestrel-mysite.service
[Unit]
    Description=MySite

    [Service]
    WorkingDirectory=/var/www/mysite
    ExecStart=/usr/bin/dotnet /var/www/mysite/mysite.dll
    Restart=always
    RestartSec=10    # Restart service after 10 seconds if dotnet service crashes
    SyslogIdentifier=dotnet-mysite
    User=www-data
    Environment=ASPNETCORE_ENVIRONMENT=Production

    [Install]
    WantedBy=multi-user.target
Shell
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:

Shell
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.

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

Replace everything with:

nginx
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:

Shell
sudo nginx -t

And reload the configuration:

Shell
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:

Shell
sudo journalctl -fu kestrel-mysite.service

#Conclusion

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: