Hosting ASP.NET Core on Linux using Nginx
ASP.NET Core is a fully open source, high-performance, and cross-platform framework. ASP.NET Core runs anywhere you need it to (Windows, Mac, Linux). If you compare hosting apps on Windows vs Linux, Linux hosting is usually cheaper. At the time of writing this post, you can find a cheap Linux VPS for as little as $3.5 a month.
In this article, we will be using Linux VPS, having CentOS 7 installed, ASP.Net Core 2.0 application and Nginx as the reverse proxy. I will try to cover most of the details for basic web hosting including some safety measures, this post might get a little long, bear with me, please. The hosting process is broken into following steps:
- Get Linux VPS Setup Linux Host
- Install .NET Core
- Deploying ASP.Net Core application
- Configure Nginx as the reverse proxy
Step 1. Setup Linux Host
You can pick any VPS provider of your choice and any distribution of Linux, in this post I am using a $3.5 CentOS 7 64-bit VPS with 1 CPU core and 1 GB Ram from RamNode(affiliate link). Why CentOS and why not any other distribution? CentOS is a free clone of Red Hat Enterprise Linux. It is considered more stable, secure and supports most of the control panels (including the most popular one - cPanel) so it is preferred distribution for businesses and in the hosting industry.
Once you get VPS, you will receive an IP and root password which you will use to connect to the VPS. You need an SSH client to connect to Linux VPS. There are free SSH clients available, SmartTTY and Putty are very common ones. I will be using SmartTTY for this demo.
Install and open SmartTTY and enter the IP, port, username, and password.
Click connect, it should open the terminal window:
Now that we have connected to the VPS via SSH, next we will configure the Linux host.
We could simply install .NET Core, Nginx and run the application, but it is strongly recommended to first follow some basic common practices of initial server setup to cover our bases. I will cover the bare minimum steps which you should do for each of the Linux servers. This will apply for some basic security protection on the server. For example, change the default root login, change default SSH port etc. If you are hosting your app just for fun, you can skip the rest of the configuration and jump directly to step 2 Install .NET Core.
Change the default password for root. Use passwd command to change the default password provided by the VPS provider.
passwd
You will be asked to enter the password twice.
Create a new "Sudo" user. We will use this new user to login to the server from next time onwards, and disable root login because root is standard username hackers can easily guess.
- Use the adduser command to add a new user, replace username with the user you want to create:
adduser username
- Use the passwd command to change the password for the user you created:
passwd username
You will be prompted for a new password and confirm the password.
- Add user to wheel group by using the usermod command:
usermod -aG wheel username
In CentOS, by default members of wheel group have sudo privileges.
- Verify the new user has sudo access:
Switch user by using "su" command
su - username
List the contents of /root directory, which is only accessible to root user.
sudo ls -la /root
You will be prompted to enter the account password, once you enter that, the command should run with root privileges.
Now we can use this new user to perform all tasks we could with root user. Just remember to add sudo to commands.
Change default SSH port, disable root login and allow the new user to login via SSH. SSH default port number is 22 and everybody knows it, including the hackers, it is not safe. Changing the default SSH port number is the basic step towards security, for production servers, in my opinion, the best way to protect SSH server is to implement password-less login using certificates and encryption. You can find many articles on how to implement password-less login into SSH server, I am going to focus on just changing the default port 22 to something else in this post. To change the SSH default port, we need to edit "sshd_config" file. You can use any editor of your choice, I am going to use Nano editor:
Install nano:
sudo yum install nano
Eidt "sshd_config" file:
sudo nano /etc/ssh/sshd_config
Find the following line:
#port 22
Remove # symbol and change the default port 22 to something else, 20020 for example:
port 22000
Now find:
#PermitRootLogin yes
Remove the # symbol and change yes to no:
PermitRootLogin no
At the end of the file, add this line, obviously, replace the username with the user you created:
AllowUsers username
Save and close the file, do not exit the session yet, allow port 20020 on firewall first, otherwise, you will not be able to login into the VM.
Restart SSH service:
sudo service sshd restart
OK, so
Allow port 20020 on the firewall:
sudo firewall-cmd --permanent --zone=public --add-port=20020/tcp
If you get "firewall-cmd: command not found" error, install and enable firewalld and run the command again, here are the commands to just do that:
sudo yum install firewalld
sudo systemctl start firewalld
sudo systemctl enable firewalld
sudo systemctl status firewalld
Reload firewall config:
sudo firewall-cmd --reload
Now you should be able to login into the VM using the new SSH port with the new user, and login for root user is disabled via SSH.
Step 2. Install .NET Core
Run following commands to install .NET Core in CentOS
Register the Microsoft signature key:
sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
Add the dotnet product feed:
sudo sh -c 'echo -e "[packages-microsoft-com-prod]\nname=packages-microsoft-com-prod \nbaseurl=https://packages.microsoft.com/yumrepos/microsoft-rhel7.3-prod\nenabled=1\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/dotnetdev.repo'
Install the .NET Core SDK and add dotnet to PATH:
sudo yum update
sudo yum install libunwind libicu
sudo yum install dotnet-sdk-2.1.4
export PATH=$PATH:$HOME/dotnet
Verify installation by running:
dotnet --version
Step 3. Deploying ASP.NET Core application
I am going to use an existing application, publish it and copy that over to VPS. Publish the application by using the following command:
dotnet publish -c Release
Copy the output contents over to the VPS using any SFTP or FTP tool. I am using WinSCP to copy the published code. You can run the application by using the dotnet command on the command prompt, you need a monitor to run it and keep it running. Let's create a service for that:
Create the service definition file:
sudo nano /etc/systemd/system/demoProject.service
Add following content to the service file:
[Unit]
Description=Demo ASP.Net Project
[Service]
WorkingDirectory=/var/www/ASP.NETDemo
ExecStart=/usr/bin/dotnet /var/www/ASP.NETDemo/WebApplication.dll
Restart=always
RestartSec=10
SyslogIdentifier=DemoProject
User=demouser
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
[Install]
WantedBy=multi-user.target
Now you need to enable the service and run it:
sudo systemctl enable demoProject.service
sudo systemctl start demoProject.service
sudo systemctl status demoProject.service
The status command should show the service as running if the configuration was correct. Now, our web application is running, kestrel by default listens on port 5000, so our application is available on http://localhost:5000.
Kestrel is good for serving dynamic content, but it is not a fully featured web-server. A reverse proxy server allows you to offload work like serving static content, cashing requests, compressing requests, and SSL termination from the HTTP server. In the next step, we will configure Nginx as the reverse proxy.
Step 4. Configure Nginx as Reverse Proxy
Almost all major Linux distro comes with Apache by default, since we are going to use Nginx only and Apache configuration might cause issues when Nginx is installed, we will turn Apache off. This will stop all the existing sites hosted in Apache. If you have any sites hosted in Apache. Since we do not have any site installed on Apache, we will stop and disable the Apache. Stop command will stop the Apache and disable command will make sure Apache does not start on next reboot:
service httpd stop
sudo systemctl disable httpd
Add Nginx repository, install Nginx, Start and Enable:
sudo yum install epel-release
sudo yum install nginx
sudo systemctl start nginx
sudo systemctl enable nginx
Enabling Nginx will make sure it is started on every reboot.
Check the status of Nginx service:
sudo systemctl status nginx.service
If you are running a firewall, run following commands to allow HTTP and HTTPS traffic:
sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload
You can verify right away that Nginx installed by browsing your server's public IP address in any browser. E.g.
http://domain-name-OR-server-IP/
You should see a default Nginx page saying "Welcome to nginx". If you see this page, nginx is installed correctly.
I am changing the nginx config file directly, ideally, for production, you should create a separate config file. Open nginx config file:
sudo nano /etc/nginx/nginx.conf
Update the config file:
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 $http_host;
proxy_cache_bypass $http_upgrade;
}
}
Verify and reload the config:
sudo nginx -t
sudo nginx -s reload
All set, now your website should be available when you type the IP of the server:
Have any questions, suggestions or feedback? Please leave a comment below.