How to Build Secure Web Applications with the ASP.NET Marketplace App
Introduction
ASP.NET is an open-source, cross-platform web framework used to build web applications with .NET and C#, which can be deployed on a Linux server. This article provides a step-by-step guide to deploying and securing an ASP.NET application on a Vultr server using the ASP.NET Marketplace app, UFW firewall, Nginx, and a free Let's Encrypt SSL certificate.
Prerequisites
- Deploy a new a ASP.NET app at Vultr.
- Point a domain name to the server. A domain name is required for Let's Encrypt TLS/SSL certificates. The guide uses the domain name
asp.example.com
.
The ASP.NET app at Vultr already has ASP.NET installed, but it needs to be uninstalled and reinstalled as there are two .NET packages, one from Microsoft and other from Ubuntu.
1. Create a Sudo User
A non-root sudo user is needed for security and safety reasons.
Log in as root.
$ ssh root@asp.example.com
Create a new user. For this guide, the example user will be created as
app_user
.# adduser app_user Adding user `app_user' ... Adding new group `app_user' (1001) ... Adding new user `app_user' (1001) with group `app_user' ... Creating home directory `/home/app_user' ... Copying files from `/etc/skel' ... New password: Retype new password: passwd: password updated successfully Changing the user information for app_user Enter the new value, or press ENTER for the default Full Name []: App User Room Number []: Work Phone []: Home Phone []: Other []: Is the information correct? [Y/n] y
Add the new user to the sudo group.
# adduser app_user sudo
Exit the server as root.
# exit
2. Install dependencies
Log in to the server with a non-root sudo user via SSH.
$ ssh app_user@asp.example.com
Uninstall
dotnet
.$ sudo apt remove dotnet* aspnet* netstandard*
Select Microsoft packages as a priority for installation by creating a file name
99microsoft.dotnet.repo.pref
in the/etc/apt/preferences.d
directory.$ sudo vim /etc/apt/preferences.d/99microsoft.dotnet.repo.pref
Edit the file and write the following inside the file.
Package: * Pin: origin "packages.microsoft.com" Pin-Priority: 1001
Save and close the file.
Update and upgrade the server.
$ sudo apt update && sudo apt upgrade
Install the
dotnet
sdk.sudo apt install dotnet-sdk-6.0
Install
UFW
,Vim
, andNginx
with the apt package manager.$ sudo apt -y install ufw nginx
Allow all outbound traffic from the server.
$ sudo ufw default allow outgoing
Block all inbound traffic except SSH (port 22), HTTP (port 80), and HTTPS (port 443).
$ sudo ufw default deny incoming $ sudo ufw allow ssh $ sudo ufw allow http $ sudo ufw allow https
Enable and reload the
UFW
firewall.$ sudo ufw enable $ sudo ufw reload
Exit the server.
$ exit
3. Configure the ASP.NET application
For deployment, Nginx will be used as a reverse proxy to handle all incoming traffic and TLS/SSL certificates, so some modifications need to be done to the application configuration on the local machine.
Create an ASP.NET web application if there isn't already an application to deploy and
cd
into the directory.$ dotnet new mvc -o webapp $ cd webapp
Configure the application to handle reverse proxy. Edit the
Program.cs
file withVim
.$ vim Program.cs
Disable
Hsts
. Look for the line containingapp.UseHsts()
and comment it out.// app.UseHsts();
Disable HTTPS redirection. Look for the line containing
app.UseRedirection()
and comment it out.// app.UseHttpsRedirection();
Configure Forwarded Headers middleware and import
Microsoft.AspNetCore.HttpOverrides
at the top of the file.using Microsoft.AspNetCore.HttpOverrides;
Configure the middleware before other middlewares, add it just after
var app = builder.Build();
.app.UseForwardedHeaders( new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto });
Save and close the
Program.cs
file.Test the application.
$ dotnet run Building... info: Microsoft.Hosting.Lifetime[14] Now listening on: https://localhost:7160 info: Microsoft.Hosting.Lifetime[14] Now listening on: http://localhost:5224 info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0] Hosting environment: Development info: Microsoft.Hosting.Lifetime[0] Content root path: /home/me/dotnet_apps/webapp/
Press Ctrl+C to stop it.
Publish the application for release in a new folder called
server
.$ dotnet publish -c Release -o server
Test the published application.
$ cd server $ dotnet webapp.dll info: Microsoft.Hosting.Lifetime[14] Now listening on: http://localhost:5000 info: Microsoft.Hosting.Lifetime[14] Now listening on: https://localhost:5001 info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0] Hosting environment: Production info: Microsoft.Hosting.Lifetime[0] Content root path: /home/me/dotnet_apps/webapp/test/
Ctrl+C to stop it.
cd
back to the main application directory.$ cd ..
4. Move files to the Server
To move the files from the local machine to the Vultr server, scp
will be used to move the files through an ssh tunnel.
Log in to the server
$ ssh app_user@asp.example.com
Create a directory to hold the application files.
$ mkdir ~/webapp
Exit the server.
$ exit
Copy all files in the
server
folder to thewebapp
folder in the Vultr server.$ scp -r server/* app_user@asp.example.com:~/webapp
Log in back to the server.
$ ssh app_user@asp.example.com
5. Create a Service for the application
A service file will be created to serve the project, and it will make it easy to run the application and help run the application on server restarts.
Create an
webapp.service
file inside/etc/systemd/system
directory.$ sudo vim /etc/systemd/system/webapp.service
Write the following into the file.
[Unit] Description=ASP.NET service for ASP.NET project After=network.target [Service] User=app_user Group=www-data WorkingDirectory=/home/app_user/webapp ExecStart=/usr/bin/dotnet webapp.dll Restart=always RestartSec=10 [Install] WantedBy=multi-user.target
* Under
[Service]
,USER=app_user
sets the user of the service, andGroup=www-data
sets the group of the service to the Nginx group.WorkingDirectory=/home/app_user/webapp
sets the service working directory to the projects folder.ExecStart=usr/bin/dotnet webapp.dll
runs the ASP.NET application on localhost with port 5000 and port 5001 by default. The Nginx server will proxy the request to those ports.Restart=always
andRestartSec=10
ensures that the application is always restarted after 10 seconds if the service crash.
Save and close the file.
Enable the service to run at boot.
$ sudo systemctl enable webapp
Start the service.
$ sudo systemctl start webapp
6. Configure Nginx as Reverse Proxy
The Nginx
server will be used as a proxy server to serve the ASP.NET application to handle SSL certificates rather than the Kestrel .NET server.
Create a new site in
Nginx
by creating a filewebapp
in/etc/nginx/sites-available
.$ sudo vim /etc/nginx/sites-available/webapp
Create a server block, and write the following into the file.
server { # listen to port 80 (HTTP) listen 80; # listen to the domain name server_name asp.example.com www.asp.example.com; location / { include proxy_params; # pass the request to the project service sock proxy_pass http://localhost:5000/; } }
Save and close the file.
Create a soft link for
webapp
to Ngnix'ssites-enabled
.$ sudo ln -s /etc/nginx/sites-available/webapp /etc/nginx/sites-enabled
Check the Nginx configuration for any errors.
$ sudo nginx -t
Restart the Nginx server.
$ sudo systemctl reload nginx
Test the application in the browser by visiting the domain
asp.example.com
7. Add HTTPS with Let's Encrypt
Let's Encrypt provides free SSL certificates that need to be renewed every three months; this will enable Nginx to secure the application with HTTPS.
Install
Certbot
with theNginx
plugin.$ sudo apt install certbot python3-certbot-nginx
Configure
Certbot
withNginx
$ sudo certbot --nginx -d asp.example.com -d www.asp.example.com
The first time
Certbot
is run, an admin email is requested for the certificates. This email will be notified when the certificates need to be renewed.Certbot
will also configureNginx
and redirect allHTTP
requests toHTTPS
by configuring the server block, hence whyHTTPS
is disabled in theProgram.cs
file of the application.Saving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator nginx, Installer nginx Enter email address (used for urgent renewal and security notices) (Enter 'c' to cancel): me@asp.example.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Please read the Terms of Service at https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf. You must agree in order to register with the ACME server. Do you agree? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: y - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Would you be willing, once your first certificate is successfully issued, to share your email address with the Electronic Frontier Foundation, a founding partner of the Let's Encrypt project and the non-profit organization that develops Certbot? We'd like to send you email about our work encrypting the web, EFF news, campaigns, and ways to support digital freedom. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: y Account registered. Requesting a certificate for asp.example.com and www.asp.example.com Performing the following challenges: http-01 challenge for asp.example.com http-01 challenge for www.asp.example.com Waiting for verification... Cleaning up challenges Deploying Certificate to VirtualHost /etc/nginx/sites-enabled/webapp Deploying Certificate to VirtualHost /etc/nginx/sites-enabled/webapp Redirecting all traffic on port 80 to ssl in /etc/nginx/sites-enabled/webapp Redirecting all traffic on port 80 to ssl in /etc/nginx/sites-enabled/webapp - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Congratulations! You have successfully enabled https://asp.example.com and https://www.asp.example.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Subscribe to the EFF mailing list (email: me@asp.example.com). IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/asp.example.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/asp.example.com/privkey.pem Your certificate will expire on 2023-02-15. To obtain a new or tweaked version of this certificate in the future, simply run certbot again with the "certonly" option. To non-interactively renew *all* of your certificates, run "certbot renew" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le
Restart
Nginx
.$ sudo systemctl reload nginx
Visit the domain of the server,
asp.example.com
, in your browser.
You now have a working ASP.NET application running on a ASP.NET app server at Vultr.