Linux VPS hosting with deployment pipeline

🟥 Not applicable to Blazor WebAssembly

Using a Linux VPS is an effective and cost-efficient way to host a live website, although it may seem complicated at first. In this tutorial, we will guide you through the following steps:

  • Required tools
  • Publishing a Blazor Server website
  • Setting up a Linux VPS
  • Speeding up your Blazor Server website
  • Configuring a GitHub action
  • Common mistakes

We would like to extend our gratitude to Grimston#0001, a Discord user from NPipes who sponsored a VPS machine for creating this tutorial. You too can contribute to the community.


Required tools

In order to manage your Linux VPS, you will need two tools: one for executing commands and one for transferring files between your computer and the VPS machine. We recommend using Bitvise SSH Client, which is an all-in-one tool for these tasks.


Publishing a Blazor Server website

Before deploying your website to a Linux VPS, you will need to publish it to a folder. This will allow us to make the website functional and then set up a GitHub action for automated deployment later. To publish your website to a folder, follow these steps:

  1. Right-click on your Blazor Server project and select Publish...

publishing-blazor-server-1.png

  1. In the next step, select Folder.

publishing-blazor-server-2.png

  1. Choose the folder location where you want to publish the website.

publishing-blazor-server-3.png

  1. To view publishing options, click on Show all settings. In the next section, we will discuss these options in more detail.

publishing-blazor-server-4.png

  1. Click Publish to start the publishing process.

publishing-blazor-server-5.png

Once the website is published to the folder, you can test it out locally to ensure it is working as intended. If any changes are needed, make them and republish the website to the folder until you are satisfied with the results.


Compare between deployment modes

There are two deployment modes available for Blazor Server, and in addition, there are several publishing options to choose from. For the purposes of this section, we will be using the FormDemonstrate project as our benchmark. The table below reflects measurements taken using only the selected deployment mode, without any additional publishing options.

Framework-dependent Self-contained
Does it have a portable option? (Allowing it to be built once and run on any operating system) Yes No
Size (Can impact deployment speed, but does not affect website loading speed) 269 KB (275,557 bytes) 86.4 MB (90,657,332 bytes)
Build time 02.745 seconds 03.946 seconds

The following table provides a comparison between publishing options and the absence of publishing options.

Self-contained Ready to Run Trim unused code Produce single file
Size 86.5 MB (90,737,716 bytes) 32.8 MB (34,470,279 bytes) 81.8 MB (85,804,094 bytes)
Build time 03.341 seconds 33.619 seconds 03.454 seconds
Framework-dependent Ready to Run (not available for Portable build) Trim unused code Produce single file (not available for Portable build)
Size 312 KB (320,151 bytes) Not available 234 KB (240,008 bytes)
Build time 02.301 seconds Not available 01.998 seconds

Setting up a Linux VPS

After purchasing a Linux VPS service, you will receive an IP address, username, and password to access the VPS. To connect to the VPS machine, follow these steps using Bitvise SSH Client:

  1. Launch Bitvise SSH Client and connect to the VPS machine.

set-up-linux-vps-1.png

  1. Click New terminal console to open a terminal console.

set-up-linux-vps-2.png

  1. Install the .NET runtime by running the following command in the terminal console: sudo apt-get update && sudo apt-get install -y aspnetcore-runtime-7.0.

set-up-linux-vps-3.png

  1. Switch back to the Bitvise SSH Client and click New SFTP window.

set-up-linux-vps-4.png

  1. Copy the wwwroot folder from the published folder to the VPS machine. We recommend placing it in the directory /home/<your_website>.

set-up-linux-vps-5.png

  1. Install NGINX by running the following command in the terminal console: sudo apt install nginx.

set-up-linux-vps-6.png

  1. Set NGINX to start automatically by running the command sudo systemctl enable nginx.

set-up-linux-vps-7.png

  1. Open the folder /etc/systemd/system and create a new file named YOUR_SERVICE.service.
[Unit]
Description=Blazor School Demonstrate

[Service]
Type=simple
User=root
WorkingDirectory=/home/TourOfHeroes
ExecStart=/usr/bin/dotnet TourOfHeroes.dll --urls=http://localhost:2023/
Restart=always
SyslogIdentifier=Tour Of Heroes
KillMode=process
StandardOutput=file:/home/log/log.log
StandardError=file:/home/log/error.log

[Install]
WantedBy=multi-user.target

Note that the WorkingDirectory should be set to the folder location of your website (refer to step 5). Also, the StandardOutput and StandardError parameters indicate the location of your log files on the VPS. Any errors encountered by your website will be stored there.

Finally, remember to include the --urls parameter at the end of ExecStart to set up NGINX later.

  1. To ensure that the service starts automatically, run the command sudo systemctl enable YOUR_SERVICE.

set-up-linux-vps-8.png

  1. Start the service for the first time with sudo systemctl start YOUR_SERVICE.

set-up-linux-vps-9.png

  1. In the SFTP window, rename the file /etc/nginx/sites-enabled/default and update its contents.
map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
	}

server {
	listen 443 ssl http2;
	listen [::]:443 ssl http2;
	server_name _;
	ssl_certificate <your_path_to_pem_file>;
        ssl_certificate_key <your_path_to_pem_file>;
	
	location / {
            proxy_pass http://localhost:2023;
	    proxy_redirect   off;
	    proxy_set_header Host $host;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
        }
}

server {
	listen 80;
	listen [::]:80;
	server_name _;
	
	return 301 https://$host$request_uri;
}

You can obtain ssl_certificate, ssl_certificate_key, and server_name from a service provider such as NPipes.

For server_name, enter your domain separated by a comma (,). For example: blazorschool.com, mywebsite.blazorschool.com.

In step 8, the --urls parameter is used as a value for proxy_pass.

  1. Whenever you change the configuration settings, reload NGINX to apply the changes. To do this, run the command sudo systemctl reload nginx in the terminal console.

set-up-linux-vps-10.png


Speeding up your Blazor Server website

Here are some suggestions to speed up your website hosting:

  • Redirect HTTP traffic to HTTPS and ensure that your SSL certificate is properly installed and configured.
  • Verify that MIME types are being handled correctly.
  • Activate gzip compression to reduce the size of your web pages and accelerate their loading time.

Redirect HTTP to HTTPS

To enable HTTP to HTTPS redirection, simply follow the tutorial provided. In the example, the second server block performs the redirection automatically, so there's no need to worry about it.

Verify that MIME types are being handled correctly

Handling MIME types is a matter of assigning file extensions to their respective categories. For instance, files ending with .css should be identified as text/css. Since there are numerous MIME types available, they must be recognized accurately. A comprehensive list of MIME types is available on IANA Media Types.

To ensure that all of your files are being processed appropriately, navigate to the /etc/nginx/mime.types file on your VPS server. If a particular MIME type is not listed, you must add it manually and reload the NGINX server.

Activate gzip compression

Enabling gzip compression can significantly improve your website's loading speed by reducing its weight. When you activate gzip, NGINX uses some CPU power to compress your website before sending it to the browser. The browser then decompresses the website for display. Since compressing and decompressing are less expensive than transportation costs, this technique can boost loading speed.

However, gzip can be tricky to use if you are unfamiliar with it. To apply it correctly, you must determine when to compress and when not to. Gzip is already enabled in NGINX by default settings. You can find these settings in /etc/nginx/nginx.conf by looking for the # Gzip Settings. To activate advanced settings, uncomment all other settings. Your Gzip settings should resemble the following:

gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types
    text/plain
    text/css
    application/json
    application/javascript
    text/xml
    application/xml
    application/xml+rss
    text/javascript;

The gzip_types list specifies which MIME types to compress for a smaller size, and you can add more to it.

The gzip_comp_level determines the level of compression, ranging from 1 to 9, with 1 being the least compressed and 9 being the most compressed. Higher compression levels compensate for more CPU usage, but sometimes the output size can be bigger than the original.

As mentioned earlier, some files may become larger after being compressed. You can add gzip_min_length X to tell NGINX not to compress files smaller than X. There is no ideal number for this setting, so you must monitor your website and make informed decisions.

To see gzip's effectiveness, open your website, turn on the Web Developer Tools by pressing F12, and open the Network tab. Check the Disable Cache option and reload the website.

speed-up-blazor.png

If the size before compression is larger than the size after compression, then you should compress the file. Otherwise, you should not compress it (either remove the gzip_types or increase the gzip_min_length X).


Configuring a GitHub action

Congratulations on having a healthy website up and running! To simplify the process of deploying website updates, the next step is to set up a deployment pipeline. GitHub is a great tool to help you do this.

To get started, follow these steps:

  1. In your GitHub repository, go to Settings > Secrets > Actions and click New repository secret.

set-up-github-action-1.png

  1. Create 3 secret keys for the host address, username, and password to log into your VPS machine.

set-up-github-action-2.png

  1. Switch to the Actions tab and click New workflow.

set-up-github-action-3.png

  1. Search for the ASP.NET workflow and select .NET by GitHub Actions.

set-up-github-action-4.png

  1. Update the YAML file with your information. Here's an example file:
name: Deploy to VPS
on:
  push:
    branches:
    - master
env:
  CONFIGURATION: Release
  DOTNET_CORE_VERSION: 7.x.x
  WORKING_DIRECTORY: <your_project_name>
  WORKING_OUTPUT_DIRECTORY: deploy
  VPS_WEB_DIRECTORY: <your_folder_location_in_vps>
  VPS_SERVICE_NAME: <your_service>
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Setup .NET Core
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: ${{ env.DOTNET_CORE_VERSION }}
    - name: Restore web
      run: dotnet restore "${{ env.WORKING_DIRECTORY }}"
    - name: Build web
      run: dotnet build "${{ env.WORKING_DIRECTORY }}" --configuration ${{ env.CONFIGURATION }} --no-restore
    - name: Test web
      run: dotnet test "${{ env.WORKING_DIRECTORY }}" --no-build
    - name: Publish web
      run: dotnet publish "${{ env.WORKING_DIRECTORY }}" --configuration ${{ env.CONFIGURATION }} --no-build --output "${{ env.WORKING_OUTPUT_DIRECTORY }}"

    - name: Copy web via ssh
      uses: garygrossgarten/github-action-scp@master
      with:
        local: ${{ env.WORKING_OUTPUT_DIRECTORY }}
        remote: ${{ env.VPS_WEB_DIRECTORY }}
        host: ${{ secrets.HOST }}
        username: ${{ secrets.USERNAME }}
        password: ${{ secrets.PASSWORD }}

    - name: Restart service
      uses: garygrossgarten/github-action-ssh@master
      with:
        host: ${{ secrets.HOST }}
        command: |
                systemctl daemon-reload
                systemctl restart ${{ env.VPS_SERVICE_NAME}}
        username: ${{ secrets.USERNAME }}
        password: ${{ secrets.PASSWORD }}

When using the example provided, make sure to update the following variables to reflect your own folder names: GITHUB_OUTPUT_DIRECTORY and VPS_WEB_DIRECTORY. The GITHUB_OUTPUT_DIRECTORY can be any valid directory name, but VPS_WEB_DIRECTORY must already exist before running this workflow. Also, change VPS_SERVICE_NAME to match the name of your service on the VPS.

The on key determines when the website will be deployed. In this example, it will be deployed whenever a push is made to the master branch.

Additionally, remember to update the secret keys in the Copy web via ssh job as well.


Common mistakes

In this section, we have compiled a list of common mistakes reported by the Blazor School Discord Community.

Mistake #1: Deploying to the wrong folder.

When publishing your project, you will see two folders: bin\Release\net7.0\ and bin\Release\net7.0\publish. It is important to note that you should never use bin\Release\net7.0\ to deploy. Instead, use bin\Release\net7.0\publish.

common-mistake-1.png

If you deploy to bin\Release\net7.0, some files will not be served because there is no wwwroot folder in that directory.

Mistake #2: Case sensitivity with files

By default, NGINX is case-sensitive when searching for files. So if you're trying to access a file named wwwroot/Logo.png but you type <your_website>.com/logo.png, you'll get a 404 error because the file name should be wwwroot/Logo.png.

BLAZOR SCHOOL
Designed and built with care by our dedicated team, with contributions from a supportive community. We strive to provide the best learning experience for our users.
Docs licensed CC-BY-SA-4.0
Copyright © 2021-2024 Blazor School
An unhandled error has occurred. Reload 🗙