Deploy an ASP.NET Core Blazor Server Application to Linux with Nginx
- 10 minutes to read
This topic describes how to set up and publish an XAF Blazor Server UI application to Ubuntu, Red Hat Enterprise (RHEL), and SUSE Linux Enterprise Server machines with Nginx reverse proxy.
The Solution Wizard uses Microsoft SQL Server as the default database provider option. This examples changes that default option to PostgreSQL (simply as a customization example). For more information on how to switch database providers, refer to the following topic: Switch EF Core Connection from SQL Server to a Different Database Provider.
Prerequisites
- Access to Ubuntu. Use its standard user account with
sudo
privileges.
- The latest stable .NET runtime installed on the server.
- PostgreSQL database engine installed.
An XAF Blazor Server application. This topic is based on the
MainDemo Blazor Server
demo application that ships with XAF. You can find this demo in the following folder: %PUBLIC%\Documents\DevExpress Demos 24.1\Components\XAF\MainDemo.NET.EFCore\CS\MainDemo.Blazor.Server.In some cases, you may encounter build errors because file paths are too long. To solve this, we recommend that you copy the folder containing the demo application closer to the root of your drive.
If you do not have XAF installed, download our Universal Subscription installer from the Download Manager or start a 30-day trial now.
Deployment Instructions
Install Required Libraries and Packages
Install the following font libraries. These libraries allow the application to measure text to correctly render documents and export them to PDF.
sudo apt-get install -y libc6 libicu-dev libfontconfig1
Install the
ttf-mscorefonts-installer
package that adds MicrosoftTrueType
core fonts to your system. (Installed fonts include Arial, Times New Roman, Courier New, and others.)sudo apt-get install ttf-mscorefonts-installer
Install the package below to render JPEG images in PDF files (you can install any other package that implements
libjpeg
API v6.2 or v8.0.).sudo apt install -y libjpeg-turbo8
Make sure an appropriate drawing engine is available. If your project targets .NET 7+, add the following packages to your MainDemo.Blazor.Server project:
- DevExpress.Drawing
- DevExpress.Drawing.Skia – For more information on this package, refer to the following topic: DevExpress.Drawing Graphics Library.
Set Up Forwarded Header Middleware
Since requests are forwarded through a reverse proxy, use Forwarded Headers Middleware. It updates Request.Scheme
with the X-Forwarded-Proto
header so that redirect URIs and other security policies work correctly.
Forwarded Headers Middleware should run before any other middleware. This order ensures that other middleware can consume header values for processing. To run Forwarded Headers Middleware after diagnostic and error handling middleware, see Forwarded Headers Middleware order.
To set up this middleware, call the UseForwardedHeaders
method from your project’s Startup.cs file before calling any other middleware. Within this call, configure the middleware to forward X-Forwarded-For
and X-Forwarded-Proto
headers.
File: Startup.cs
//...
using Microsoft.AspNetCore.HttpOverrides;
namespace MainDemo.Blazor.Server;
public class Startup {
//...
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
//...
app.UseForwardedHeaders(new ForwardedHeadersOptions {
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
//...
}
}
Set Up the Database and Connection String
To use PostgreSQL database provider, follow the steps below:
Install the Npgsql.EntityFrameworkCore.PostgreSQL package to both MainDemo.Module and MainDemo.Blazor.Server projects. Make sure that this package’s version matches the version of the EntityFrameworkCore package you have installed.
Change the application connection string.
File: appsettings.json
"ConnectionStrings": { "ConnectionString": "Host=localhost;Database=maindemo;Username=testuser;Password=Qwerty1_", ... }, ...
If you use migrations, update the
MainDemoDesignTimeDbContextFactory.CreateDbContext
method in the following way:File: MainDemo.Module/BusinessObjects/MainDemoDbContext.cs
public class MainDemoDesignTimeDbContextFactory : IDesignTimeDbContextFactory<MainDemoDbContext> { public MainDemoDbContext CreateDbContext(string[] args) { var optionsBuilder = new DbContextOptionsBuilder<MainDemoDbContext>(); optionsBuilder.UseNpgsql(@"Host=localhost;Database=maindemo;Username=testuser;Password=Qwerty1_"); optionsBuilder.UseChangeTrackingProxies(); return new MainDemoDbContext(optionsBuilder.Options); } }
Change the
DbContextTypesInfoInitializerBase
descendant to use PostgreSQL.File: MainDemo.Module/BusinessObjects/MainDemoDbContext.cs
public class EFDemoDbContextInitializer : DbContextTypesInfoInitializerBase { protected override DbContext CreateDbContext() { var optionsBuilder = new DbContextOptionsBuilder<MainDemoDbContext>() .UseNpgsql(@";") .UseChangeTrackingProxies() .UseObjectSpaceLinkProxies(); return new MainDemoDbContext(optionsBuilder.Options); } }
Change the MainDemo.Blazor.Server/Startup.cs file as follows:
namespace MainDemo.Blazor.Server; public class Startup { //... public void ConfigureServices(IServiceCollection services) { //... builder.ObjectSpaceProviders .AddSecuredEFCore(o => o.PreFetchReferenceProperties()) .WithAuditedDbContext(contexts => { contexts.Configure<MainDemoDbContext, AuditingDbContext>( (serviceProvider, businessObjectDbContextOptions) => { string connectionString = GetConnectionString(Configuration); ArgumentNullException.ThrowIfNull(connectionString); // businessObjectDbContextOptions.UseSqlServer(connectionString); businessObjectDbContextOptions.UseNpgsql(connectionString); businessObjectDbContextOptions.UseLazyLoadingProxies(); businessObjectDbContextOptions.UseChangeTrackingProxies(); businessObjectDbContextOptions.UseObjectSpaceLinkProxies(); }); } } }
You may see an error message that says “Cannot write DateTime with Kind=Unspecified to PostgreSQL type ‘timestamp with time zone’“. If this happens, set
DateTimeKind
toUTC
for each DateTime property or add the following line to theProgram.Main()
method.File: YourSolutionName.Blazor.Server\Program.cs
namespace MainDemo.Blazor.Server; public class Program : IDesignTimeApplicationFactory { public static int Main(string[] args) { //... AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); //... } }
Refer the following topic for details: Date and Time Handling.
Publish and Copy the Application
Make sure that the DevExpress NuGet source URL is registered in your source list. Use the following link to locate this URL: Your DevExpress NuGet Feed URL. We also recommend that you use the NuGet v3 source URL.
The command below adds
DevExpressNuget
to your source list.dotnet nuget add source -n DevExpressNuget https://nuget.devexpress.com/{your-feed-authorization-key}/api/v3/index.json
Execute the dotnet publish command from the development environment to package an application into a directory that can be run on the server.
dotnet publish --configuration Release
Copy your application to the server using a tool that is integrated into the organization’s workflow (for example,
SCP
,SFTP
). It’s common to store web applications in thevar
directory (for example,var/www/MainDemo.Blazor.Server
).Check that the application works correctly. To do this, run the application from the command line.
dotnet MainDemo.Blazor.Server.dll.
Run the application locally under Linux. Open a browser and navigate to
http://<serveraddress>:<port>
. Check that the application works correctly.If the application database exists and doesn’t require any updates, your XAF Blazor application is ready to use.
If the database isn’t ready, you will see a database version mismatch error in the console. Such an error indicates that the database either doesn’t exist yet or needs to be updated (based on your latest changes to the data model and XAF modules). To resolve the error, start the application in database update mode.
dotnet MainDemo.Blazor.Server.dll --updateDatabase --forceUpdate –silent
Configure Nginx
Install Nginx. To do this, you can use the following instructions:
As Nginx has just been installed, explicitly start it.
sudo service nginx start
Configure Nginx as a reverse proxy to forward HTTP requests to your Blazor server application.
Open the following file: /etc/nginx/sites-available/default. For example, run the command below to open it in the nano text editor.
sudo nano /etc/nginx/sites-available/default
Replace the file’s content with the following code.
server { listen 80; server_name localhost; location / { return 301 https://$host$request_uri; proxy_pass http://localhost:5000; } } server { listen 443 ssl; server_name localhost; ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt; ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key; location / { proxy_pass http://localhost:5000; proxy_http_version 1.1; proxy_cache_bypass $http_upgrade; proxy_buffering off; proxy_read_timeout 100s; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Connection keep-alive; 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; proxy_set_header X-Forwarded-Host $server_name; } }
In the configuration snippet above, Nginx accepts public HTTPS traffic on ports
80
and443
and redirects unsecured HTTP traffic to an encrypted HTTPS connection. Nginx forwards matching requests to Kestrel athttp://127.0.0.1
.Specify the path to the certificate file and associated key. For example, you can generate a self-signed certificate file for testing purposes. For more information, refer to the following tutorial: How To Create a Self-Signed SSL Certificate for Nginx in Ubuntu 16.04.
Run the following command to check that configuration file syntax is correct.
sudo nginx –t
Run the command below to apply the new configuration to Nginx.
sudo nginx -s reload
Navigate to the application directory and run the application.
dotnet MainDemo.Blazor.Server.dll.
Navigate to
https://<your_host_name>
in a browser to check that Nginx is working correctly with the application.
Monitor the Application
Nginx cannot manage Kestrel application processes. You can use systemd to create a service file that starts and monitors the underlying web application.
Create a service definition file.
sudo nano /etc/systemd/system/kestrel-maindemo.service
Service file example below starts and monitors the
MainDemo.Blazor.Server
application.[Unit] Description=XAF Blazor App running on Linux [Service] WorkingDirectory=/var/www/MainDemo.Blazor.Server ExecStart=/usr/bin/dotnet /var/www/MainDemo.Blazor.Server/MainDemo.Blazor.Server.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=Development Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false [Install] WantedBy=multi-user.target
The example above uses the
/usr/bin/dotnet
command to start the application. You can change this option if thedotnet
runtime location is different, or if you have published your application with the--self-contained
argument. For example:ExecStart=/var/www/MainDemo.Blazor.Server/MainDemo.Blazor.Server
Make sure that the value of the
WorkingDirectory
option is correct. Otherwise, you may see the following error: “Could not find ‘xaf.focusViewItem’ (‘xaf’ was undefined)“.The
User
option specifies a user that manages the service. This user (www-data
in this example) must exist and have proper ownership of application files.Save the file and enable the service.
sudo systemctl enable kestrel-maindemo.service
Start the service.
sudo systemctl start kestrel-maindemo.service
Verify that the service is running.
sudo systemctl status kestrel-maindemo.service
Important Disclaimer
These deployment recommendations do not apply to all possible configurations and should not be considered comprehensive. We offer these instructions as a getting-started reference. Steps may vary depending on your operating system, installed software, and DevExpress versions. You, the developer, are responsible for the application, database, network, and other configurations based on your client, security, environment, and other requirements. We recommend that you review these settings with your database, network, and IT infrastructure administrators and consider their recommendations tailored to your case. We also recommend that you review Performance Optimization tips for deployed applications.
Troubleshooting
If you encounter problems, refer to the following topic: Deployment Troubleshooting Guide.
Additional Resources
Refer to the Microsoft documentation for more information about deploying ASP.NET Core and Blazor applications: