In the last couple of weeks, I have been busy setting up a CI/CD pipeline for one of my side projects and getting it to run on Linux. I'll try to write about what I have learned in the process.
This will be a series of blog posts because I don't want it to become too long. This is the first part. We will create a new ASP.NET Core application and manually run it on Linux and configure Nginx and systemd.
Before anything lets create a new ASP.NET Core Razor Pages web application by running:
dotnet new webapp
Good, now add it to a git repository and upload it to GitHub, it will be useful for us in the next part of the series.
Setting up VSCode
VSCode is great for accessing remote Linux servers. It allows you to open multiple terminals and edit files and allows you to download and upload them too. Follow these steps to set it up:
Install the Remote - SSH extension to be able to login into the server and be able to run commands and edit files.
In Remote Explorer tab add a new SSH Target for your server and inter username and IP address and follow the instructions. After you added the server to Remote Explorer connect to it and in Explorer tab open the
/
directory.Download and install the ASP.NET Core runtime on the server. You can find instructions here.
Publishing the website
Before doing anything we have to publish the website first. We will automate this process later but for now, we will do it manually.
dotnet publish -c Release
Note: This will publish the web app in Framework dependent (Meaning that ASP.NET Core runtime has to be installed on the server) and cross-platform (Meaning that it can work on any operating system) mode. You might need to publish it for a specific platform if you're using native libraries or one of your Nuget packages uses them by using the
--runtime
switch.
Compress the contents of bin\Release\netcoreapp3.1\publish\
folder (and rename it to publish.zip) and upload it to /home/www/sample
folder by dragging it into Explorer tab of VSCode.
Run these commands to unzip and delete the zip file:
cd /home/www/sample
unzip publish.zip
rm publish.zip
Okay, now that all of the necessary files are on the server, you can now test if the app actually works:
dotnet AspNetOnLinux.dll --urls=http://localhost:9999
If everything is set up correctly and port 9999
is not being used by any other processes, kestrel must be up and running now.
- If there were an exception like
System.IO.IOException: Failed to bind to address http://127.0.0.1:9999: address already in use.
Then change the port to something else. - If There was an error like
Command 'dotnet' not found
Then it means that ASP.NET Core runtime has not been installed properly. Install them and try again.
Now that we have confirmed that everything works press next we need to configure Nginx as a reverse proxy, i.e. it listens for an external port on an IP address or domain name and re-routes it to kestrel.
Configuring Nginx
Keep kestrel running and open a new terminal in VSCode and run:
code /etc/nginx/sites-available/default
This will open Nginx default configurations in VSCode.
server {
listen IP_ADDRESS;
server_name HOST_NAME;
location / {
proxy_pass KESTREL_URL;
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;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Copy the above snippet to the configuration file and make these adjustments:
- Instead of
IP_ADDRESS
write the external ip address to which you want Nginx to listen. Example:8080
. IfHOST_NAME
is a domain name you might want to use port80
. - Instead of
HOST_NAME
write the domain name or IP address you want Nginx to listen to. If you've rented a VM they usually give you a static public IP that you can use for this. or if you want to use a domain name, you need to configure its DNS settings so that it points to your server's public IP address. - Instead of
KESTREL_URL
write the URL you have kestrel listening to. Example:http://localhost:9999
Save the file and run this command for Nginx to reload the configuration file:
# Validate configuration file
nginx -t
# Reload configuration file
nginx -s reload
Now in a browser go to http://HOST_NAME:IP_ADDRESS/
and it should show our web app running 😊
For more information on configuration Nginx go to Microsoft docs.
Setting up systemd
Everything seems to be working now. But if you close the ssh session our website will no longer be running and Nginx will return ERROR 502: Bad Gateway
if you visited the website. To make sure the website will always be running and will be restarted if it crashes we can use systemd
.
Go back to the terminal that's running kestrel and press CTRL+C to stop it. And then run these commands:
code /etc/systemd/system/sample.service
This will open up a blank file in VSCode. Write this configuration in the file:
[Unit]
Description=Sample ASP.NET Core application
[Service]
WorkingDirectory=/home/www/sample
ExecStart=/usr/bin/dotnet /home/www/sample/sample.dll --urls=http://localhost:9999
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-ec
User=root
# You can put your environment variables here:
Environment=ASPNETCORE_ENVIRONMENT=Production
[Install]
WantedBy=multi-user.target
Save it and then run these commands:
# Reload systemd configuration
systemctl daemon-reload
systemctl enable sample
systemctl start sample
You can verify that our application is up and running by running this command:
systemctl status sample
It should not show any errors if everything has gone according to our plan. Press CTRL+C to stop showing status.
Now our sample web application will be running reliably and will be restarted if it crashed. You can close VSCode and visit http://HOST_NAME:IP_ADDRESS/
and it should be serving requests.
In the next post, we will talk about setting up a CI/CD pipeline using GitHub actions.
The code is available on GitHub.
comments powered by Disqus