In this post we will see how to host and publish a blazor server web app on Ubuntu and apache. Therefore just a few steps are necessary to get your app up and running on Ubuntu and apache.



Install the .NET SDK or .NET Runtime on Ubuntu

First we need to install the .NET SDK or .NET Runtime on Ubuntu. About how to install them you can read in my following post. I will install here just the .NET Runtime.




Publish and Copy over the App

You can publish your web app either platform-specific and framework-dependent or platform-specific and self-contained.

framework-dependent produces an web app that includes only your application itself and its dependencies. You have to separately install the .NET runtime.

self-contained produces an web app that includes the .NET runtime and libraries, and your app and its dependencies. You can run it on a machine that doesn’t have the .NET runtime installed.


I will now publish the blazor server app platform-specific and framework-dependent by executing the following command. At the end of this post, you will also see how to publish the app platform-specific and self-contained.

dotnet publish -r linux-x64 --self-contained false


You can publish a framework-dependent app that’s platform-specific by passing the -r <RID> –self-contained false parameters to the dotnet publish command. Publishing in this way is the same as publish framework-dependent, except that platform-specific dependencies are handled differently. If the app uses a NuGet package that has platform-specific implementations, only the targeted platform’s dependencies are copied. These dependencies are copied directly to the publish folder.

While technically the binary produced is cross-platform, by targeting a specific platform, your app isn’t guaranteed to run cross-platform. You can run dotnet <filename.dll>, but the app may crash when it tries to access platform-specific dependencies that are missing.

For more information about RIDs, see .NET RID Catalog.

Source: https://learn.microsoft.com/en-us/dotnet/core/deploying/#platform-specific-and-framework-dependent



In order to execute the above command, I will open a Visual Studio Developer Command Prompt as shown below.

Tools –> Command Line –> Developer Command Prompt


Here I will publish the app platform-specific and framework-dependent.

dotnet publish -r linux-x64 --self-contained false


As mentioned further above, when publishing platform-specific, the dependencies like NuGet packages will be copied directly to the folder named publish.

Therefore we copy the blazor server app files from the publish folder to our Ubuntu web root folder.



Now we can first test if the app is running locally on the Kestrel web server.

Kestrel is a cross-platform web server for ASP.NET Core. Kestrel is the web server that’s included and enabled by default in ASP.NET Core project templates.

Source: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-7.0


You can start the blazor server web app by executing the following command.

dotnet <your web app *.dll file>

In my case
dotnet ‘BlazorApp on Linux.dll’


Looks good!


We can also test by using the curl command if the web app is returning a page.

Looks also good!



Publish the App by using Apache

To publish a Blazor app on apache, we need to configure ProxyPass for HTTP and WebSocket traffic.

So far the web app is running on the Kestrel server and listens for traffic on port 5000.


Therefore we first need to enable the following apache modules and restart or just reload apache afterwards.

$ sudo a2enmod proxy
$ sudo a2enmod proxy_wstunnel
$ sudo a2enmod proxy_http
$ sudo systemctl restart apache2


Now we also need to add the following apache directives in our virtual host apache file.

ProxyRequests       On
ProxyPreserveHost   On
ProxyPassMatch      ^/_blazor/(.*) http://localhost:5000/_blazor/$1
ProxyPass           /_blazor ws://localhost:5000/_blazor
ProxyPass           / http://localhost:5000/
ProxyPassReverse    / http://localhost:5000/



Also reload or restart apache again.

Now after the web app is called through apache, you should also see established connections between apache and Kestrel (the web server that’s included and enabled by default in ASP.NET Core project templates).


Source: https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/server?view=aspnetcore-3.1#linux-with-apache


Finally you should be able to open the blazor server web app in a browser from external and will be served by apache.



Enable and start the Web App by default and on OS boot using Systemd

So far we need to start the web app by hand executing the following command which will bootstrap the app on Kestrel.

dotnet <your web app *.dll file>
dotnet ‘BlazorApp on Linux.dll


In case the server is rebooted, our web app won’t start automatically on OS boot and apache isn’t set up to manage the Kestrel process.

In order to start the web app during OS boot, we can use systemd and create a new service file to start and monitor the underlying web app

systemd is an init system that provides many powerful features for starting, stopping, and managing processes.


Create a new service file by executing the following command.

$ sudo nano /etc/systemd/system/kestrel-BlazorApp.service


An example service file for the app:

[Unit]
Description=Example .NET Web API App running on CentOS 7

[Service]
WorkingDirectory=/var/www/helloapp
ExecStart=/usr/local/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=apache
Environment=ASPNETCORE_ENVIRONMENT=Production 

[Install]
WantedBy=multi-user.target


In the preceding example, the user that manages the service is specified by the User option. The user (apache) must exist and have proper ownership of the app’s files.

Use TimeoutStopSec to configure the duration of time to wait for the app to shut down after it receives the initial interrupt signal. If the app doesn’t shut down in this period, SIGKILL is issued to terminate the app. Provide the value as unitless seconds (for example, 150), a time span value (for example, 2min 30s), or infinity to disable the timeout. TimeoutStopSec defaults to the value of DefaultTimeoutStopSec in the manager configuration file (systemd-system.conf, system.conf.d, systemd-user.conf, user.conf.d). The default timeout for most distributions is 90 seconds.

Source: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-apache?view=aspnetcore-3.1#monitor-the-app


In my case the service file will looks like the following.

Please note that on Ubuntu the path for the .NET Core runtime is /usr/bin/dotnet which you need to enter under ExecStart= below. The path to the executable Blazor Server DLL I entered within quotes because of the blanks in the name of the DLL.

[Unit]
Description=My Blazor Web App running on Ubuntu

[Service]
WorkingDirectory=/var/www/intelli/html
ExecStart=/usr/bin/dotnet "/var/www/intelli/html/BlazorApp on Linux.dll"
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-BlazorServerApp
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production 

[Install]
WantedBy=multi-user.target


By default systemd uses the root user for running system services, because I will use here the www-data user to run the blazor server app, I will also set the following permissions and ownership to the web root folder.

$ chown -R www-data:www-data /var/www
$ sudo chmod 0755 -R /var/www
$ sudo chmod g+s -R /var/www


The command chmod g+s will ensure here that new files and folders created in /var/www will inherit its group ID (setgid), rather than the primary group ID of the user who created the file, and therefore will set as owner the www-data user and for the group www-data.


Save the file and enable the service:

$ sudo systemctl enable kestrel-BlazorApp.service


Start the service and verify that it’s running:

$ sudo systemctl start kestrel-BlazorApp.service
$ sudo systemctl status kestrel-BlazorApp.service


From now on the web app will be managed by systemd and will be automatically started during OS boot.


Source: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-apache?view=aspnetcore-3.1#monitor-the-app


Publish the App as Platform-Specific and Self-Contained

Publishing your blazor server web app as self-contained, produces an app that includes the .NET runtime, libraries and your app and its dependencies. You can run your web app on a machine that doesn’t have the .NET runtime installed.

In order to publish the app as platform-specific for Linux and self-contained, run the following command in the Developer Command prompt as shown previously for the framework-dependent web app.

dotnet publish -r linux-x64 --self-contained true


As you can see, this will produce a lot more files as previously for the framework-dependent deployment.

Be careful to copy the files from the publish folder to your Ubuntu machine and web root folder. The linux-x64 folder before will also include all files except the wwwroot folder with all images and style sheets.


In order to run the blazor server web app without the .NET framework installed on the system, this time we need to execute not the DLL file by using the dotnet command which is then not available, but directly the executable file named ‘BlazorApp on Linux’ in my case and like shown below.

./’BlazorApp on Linux’


Finally we also need to adjust the systemd service file and here the path from the ExecStart directive which now should point to our executable file instead the DLL file.

[Unit]
Description=My Blazor Web App running on Ubuntu

[Service]
WorkingDirectory=/var/www/intelli/html
ExecStart="/var/www/intelli/html/BlazorApp on Linux"
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-BlazorServerApp
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production 

[Install]
WantedBy=multi-user.target



Links

Host and deploy Blazor Server | Linux with Apache
https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/server?view=aspnetcore-7.0#linux-with-apache

.NET application publishing overview
https://learn.microsoft.com/en-us/dotnet/core/deploying/#framework-dependent-deployments-fdd

Kestrel web server in ASP.NET Core
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-7.0