How to Build Secure Web Applications with the ASP.NET Marketplace App

Updated on January 3, 2023
How to Build Secure Web Applications with the ASP.NET Marketplace App header image

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.

  1. Log in as root.

     $ ssh root@asp.example.com
  2. 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
  3. Add the new user to the sudo group.

     # adduser app_user sudo
  4. Exit the server as root.

     # exit

2. Install dependencies

  1. Log in to the server with a non-root sudo user via SSH.

     $ ssh app_user@asp.example.com
  2. Uninstall dotnet.

     $ sudo apt remove dotnet* aspnet* netstandard*
  3. 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
  4. Edit the file and write the following inside the file.

     Package: *
     Pin: origin "packages.microsoft.com"
     Pin-Priority: 1001
  5. Save and close the file.

  6. Update and upgrade the server.

     $ sudo apt update && sudo apt upgrade
  7. Install the dotnet sdk.

     sudo apt install dotnet-sdk-6.0
  8. Install UFW, Vim, and Nginx with the apt package manager.

     $ sudo apt -y install ufw nginx
  9. Allow all outbound traffic from the server.

     $ sudo ufw default allow outgoing
  10. 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
  11. Enable and reload the UFW firewall.

    $ sudo ufw enable
    $ sudo ufw reload
  12. 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.

  1. 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
  2. Configure the application to handle reverse proxy. Edit the Program.cs file with Vim.

     $ vim Program.cs
  3. Disable Hsts. Look for the line containing app.UseHsts() and comment it out.

     // app.UseHsts();
  4. Disable HTTPS redirection. Look for the line containing app.UseRedirection() and comment it out.

     // app.UseHttpsRedirection();
  5. Configure Forwarded Headers middleware and import Microsoft.AspNetCore.HttpOverrides at the top of the file.

     using Microsoft.AspNetCore.HttpOverrides;
  6. Configure the middleware before other middlewares, add it just after var app = builder.Build();.

     app.UseForwardedHeaders( new ForwardedHeadersOptions {
         ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
     });
  7. Save and close the Program.cs file.

  8. 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/
  9. Press Ctrl+C to stop it.

  10. Publish the application for release in a new folder called server.

    $ dotnet publish -c Release -o server
  11. 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/
  12. Ctrl+C to stop it.

  13. 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.

  1. Log in to the server

     $ ssh app_user@asp.example.com
  2. Create a directory to hold the application files.

     $ mkdir ~/webapp
  3. Exit the server.

     $ exit
  4. Copy all files in the server folder to the webapp folder in the Vultr server.

     $ scp -r server/* app_user@asp.example.com:~/webapp
  5. 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.

  1. Create an webapp.service file inside /etc/systemd/system directory.

     $ sudo vim /etc/systemd/system/webapp.service
  2. 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.
  3. Save and close the file.

  4. Enable the service to run at boot.

     $ sudo systemctl enable webapp
  5. 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.

  1. Create a new site in Nginx by creating a file webapp in /etc/nginx/sites-available.

     $ sudo vim /etc/nginx/sites-available/webapp
  2. 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/;
         }
     }
  3. Save and close the file.

  4. Create a soft link for webapp to Ngnix's sites-enabled.

     $ sudo ln -s /etc/nginx/sites-available/webapp /etc/nginx/sites-enabled
  5. Check the Nginx configuration for any errors.

     $ sudo nginx -t
  6. Restart the Nginx server.

     $ sudo systemctl reload nginx
  7. 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.

  1. Install Certbot with the Nginx plugin.

     $ sudo apt install certbot python3-certbot-nginx
  2. 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
  3. Restart Nginx.

     $ sudo systemctl reload nginx
  4. 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.