Deployment

A Blazor Web App using AdminLTE is a standard ASP.NET Core app. Publish it like any other .NET 10 site — the catch with the InteractiveServer render mode is that you must run behind a reverse proxy that supports WebSockets, because each user holds a persistent Blazor Server circuit.

Publish

For a portable, dependency-free deployment, publish self-contained for your target runtime:

dotnet publish -c Release -r linux-x64 --self-contained -o ./publish

Drop -r / --self-contained if the target host already has the .NET 10 runtime installed (a framework-dependent publish is smaller).

Publish to a clean directory (or delete the output folder first). Stale fingerprinted static assets from a previous publish can linger and be served instead of the current ones — the RCL's AdminLTE/Bootstrap files are versioned static web assets, so an old copy left behind causes hard-to-debug CSS/JS mismatches. Use a fresh -o folder each time.

Reverse proxy with WebSocket support

InteractiveServer keeps a SignalR/WebSocket connection open per user (the Blazor "circuit"). The reverse proxy in front of Kestrel must forward and upgrade WebSocket connections, or the UI will fail to go interactive and fall back / disconnect.

nginx

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass         http://127.0.0.1:5000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection "upgrade";
        proxy_set_header   Host $host;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
        proxy_read_timeout 100s;
    }
}

Pair this with app.UseForwardedHeaders(...) in Program.cs so the app sees the original scheme/host behind the proxy.

Run as a systemd service

Keep the app running and restart it on failure with a unit file:

# /etc/systemd/system/adminlte-app.service
[Unit]
Description=AdminLTE ASP.NET Core app
After=network.target

[Service]
WorkingDirectory=/var/www/adminlte-app
ExecStart=/var/www/adminlte-app/MyApp
Restart=always
RestartSec=5
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=ASPNETCORE_URLS=http://127.0.0.1:5000

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now adminlte-app
sudo systemctl status adminlte-app

Checklist

  • Publish to a clean output directory to avoid stale static assets.
  • Enable WebSocket upgrade in the reverse proxy (Blazor Server circuit).
  • Forward X-Forwarded-Proto / X-Forwarded-For and call UseForwardedHeaders.
  • Terminate TLS at the proxy and keep UseHttpsRedirection aware of the forwarded scheme.
  • Confirm MapStaticAssets() is serving /_content/ColorlibHQ.AdminLTE.AspNetCore/ after deploy.

If you scale to more than one instance, Blazor Server requires sticky sessions (or a backplane) so a user's circuit always reaches the same server. A single instance behind one proxy needs no extra configuration.


AdminLTE 4 · ASP.NET port Edit on GitHub