Author: Michael Jalloh
Last Updated: Tue, Jan 3, 2023ASP.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.
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.
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
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
, and Nginx
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
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 with Vim
.
$ vim Program.cs
Disable Hsts
. Look for the line containing app.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 ..
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 the webapp
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
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, and Group=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
and RestartSec=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
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 file webapp
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's sites-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
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 the Nginx
plugin.
$ sudo apt install certbot python3-certbot-nginx
Configure Certbot
with Nginx
$ 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 configure Nginx
and redirect all HTTP
requests to HTTPS
by configuring the server block, hence why HTTPS
is disabled in the Program.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.