I recently moved my website to a Linux host. Since .NET Core is cross-platform, this was a natural choice - and the main motivation was cost. You can find many affordable VPS providers on the internet. For instance, OVH offers solid VPS plans for around 3€ per month (I'm not affiliated with them, but I've been using their services for a few years without any issues).
Hosting a site on Linux requires a bit more setup than on Windows, mostly because I don't use Linux on a daily basis.
Here are the steps I followed to deploy my website on Ubuntu 16.04 and set up 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 command lines.
#Step 1 - Connect to the VPS using ssh
Once you have your VPS, you should receive an IP address and the root user password. Use these to connect to the machine via SSH. If you are running Windows 10, you can enable the Windows Subsystem for Linux (WSL) feature and 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
By default, all ports are open. For a web server, you only need ports 80 and 443. Make sure to keep port 22 open, or you will lose SSH access.
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 capable web server. However, Microsoft recommends not exposing it directly to the internet. Instead, 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 purposes, 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 live on port 80. Feel free to leave a comment if I missed anything. As noted, I'm not a Linux expert 😃
The next post covers securing the website with a free SSL certificate from Let's Encrypt.
Do you have a question or a suggestion about this post? Contact me!