🟥 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:
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.
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.
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:
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.
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 |
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:
sudo apt-get update && sudo apt-get install -y aspnetcore-runtime-7.0
./home/<your_website>
.sudo apt install nginx
.sudo systemctl enable nginx
.[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.
sudo systemctl enable YOUR_SERVICE
.sudo systemctl start YOUR_SERVICE
./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
.
sudo systemctl reload nginx
in the terminal console.Here are some suggestions to speed up your website hosting:
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.
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.
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.
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
).
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:
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.
In this section, we have compiled a list of common mistakes reported by the Blazor School Discord Community.
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.
If you deploy to bin\Release\net7.0, some files will not be served because there is no wwwroot folder in that directory.
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.