JOSHUA AQUINO

Home   Blog   |    

GUIDE: Blazor Server on Remote Machine

Lessons you've learned.

This article outlines the initial preparation and deployment of this blog. Use it if ever you need to create something similar and forget the necessary steps and resources. Joshua, if you get confused, look at the definitions and related links. Don't strain yourself.

Definitions

Blazor Server
web framework for building dynamic UI components. One of the hosting models available, along with Blazor WebAssembly and Hybrid models.
Systemd
suite of system and service management components for Linux.
SCP
= secure copy protocol; supports securely transferring files between local and remote hosts. Based on the Secure Shell ssh protocol.
UFW
= uncomplicated firewall; a frontend for iptables
NGINX
web server and reverse proxy server software. Offers load balancing, HTTP caching, and various security features among other things.
Certbot
tool for obtaining web certifications from Let's Encrypt.
reverse proxy
type of proxy server that directs client requests to backend servers.

Setup

(Remote) Setup NGINX

Install NGINX using the package manager (assuming Debian).

apt-get install nginx

Enable and start NGINX (assuming Systemd).

systemctl start nginx
systemctl enable nginx

If not allowed already, allow NGINX in firewall settings (assuming UFW).

ufw allow 'Nginx Full'

Create the following configuration file in /etc/nginx/sites-available/default (source).

/etc/nginx/sites-available/default
http { map $http_connection $connection_upgrade { "~*Upgrade" $http_connection; default keep-alive; } server { listen 80; server_name example.com *.example.com; # Configure the SignalR Endpoint location /hubroute { # App server url proxy_pass http://localhost:5000; # Configuration for WebSockets proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_cache off; # WebSockets were implemented after http/1.0 proxy_http_version 1.1; # Configuration for ServerSentEvents proxy_buffering off; # Configuration for LongPolling or if your KeepAliveInterval is longer than 60 seconds proxy_read_timeout 100s; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } }

This article outlines a few changes necessary to the sites-available/default file when running Blazor apps with NGINX:

  1. change the location path from /hubroute to the root path /.
  2. remove the configuration for proxy buffering proxy_buffering off;.

Append a default server to the sites-available/default file.

sites-available/default
server { listen 80 default_server; # listen [::]:80 default_server deferred; return 444; }

Check if NGINX accepts the new configurations.

nginx -t

(Local) Publish the web app

Enable reverse proxy function by adding the forwarded headers middleware to your project; likely managed in the Program.cs file; add the highlighted lines to your relevant file:

Program.cs
using Microsoft.AspNetCore.HttpOverrides; var builder = WebApplication.CreateBuilder(args); builder.Services.AddRazorPages(); builder.Services.Configure(options => { options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; }); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); app.UseForwardedHeaders(); app.UseHsts(); } else { app.UseDeveloperExceptionPage(); app.UseForwardedHeaders(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseAuthorization(); app.MapRazorPages(); app.Run();

Publish your app configured for framework dependent deployment.

dotnet publish

Transfer the published project to the destination directory on the remote server (assuming destination of /var/www/project and using scp).

scp -r /home/localuser/project remoteuser@website.com:/var/www/project

(Remote) Test if the site is can run properly

Allow port 80 in the firewall.

ufw allow 80

Run the project .dll file.

dotnet projectname.dll

The setup is configured correctly if the site is accessible via browser; if not, God help you.

(Remote) Creating the application service file

Create the file /etc/systemd/system/[servicename].service with the following contents:

/etc/systemd/system/[servicename].service
[Unit] Description=Example .NET Web API App running on Linux [Service] WorkingDirectory=/var/www/helloapp ExecStart=/usr/bin/dotnet /var/www/helloapp/helloapp.dll Restart=always # Restart service after 10 seconds if the dotnet service crashes: RestartSec=10 KillSignal=SIGINT SyslogIdentifier=dotnet-example User=www-data Environment=ASPNETCORE_ENVIRONMENT=Production Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false [Install] WantedBy=multi-user.target

Create the user www-data if they don't already exist.

useradd www-data
passwd www-data

To check if www-data exists.

id -u www-data

(Remote) Setup HTTPS

Install Certbot and related utilities.

apt-get install certbot
apt-get install python3-certbot-nginx

Allow port 443 in the firewall.

ufw allow 443

Obtain SSL/TLS certificate.

certbot --nginx -d servername.com

Create config file etc/nginx/proxy.conf:

etc/nginx/proxy.conf
proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 90; proxy_send_timeout 90; proxy_read_timeout 90; proxy_buffers 32 4k;