You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派Nginx+Kestrel部署Blazor后无法访问wwwroot静态文件求助

Blazor静态资源加载问题(树莓派部署)

我是Blazor新手,在树莓派(Raspberry Pi OS Lite 64位)上搭建了基于.NET Core 8.0、Nginx+Kestrel的服务器,已成功部署可与Web API通信的BlazorWebApp前端,但wwwroot内的图片、JavaScript文件无法加载,仅根目录下的app.css能正常访问,浏览器调试显示这些资源报404错误。

这个问题困扰了我数周,试过调整Program.cs、Nginx、Kestrel的各类配置,修改wwwroot的权限和所有者(root、www-data),甚至尝试builder.WebHost.UseStaticWebAssets()和app.UseStaticFiles()的多种写法均无效。Nginx日志为空,NLog也未提供有效信息,网上找不到针对树莓派的解决方案,纠结是否要换成Apache。


当前配置片段

Nginx配置(默认配置片段)

#rasp Bank Statement (Frontend)
location /bank/ {
    root /var/www/app/BlazorBankStatement/wwwroot;
    proxy_pass         http://192.168.0.156:5023;
    include            proxy_params;
    access_log         /var/log/nginx/srv.local-bank-access.log;
    error_log          /var/log/nginx/srv.local-bank-error.log;
    proxy_set_header   Upgrade $http_upgrade;
    proxy_set_header   Connection keep-alive;
    proxy_set_header   Host $host;
    proxy_cache_bypass $http_upgrade;
    proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header   X-Forwarded-Proto $scheme;
    proxy_headers_hash_max_size 512;
    proxy_headers_hash_bucket_size 128; 
}

Kestrel服务文件

[Unit]
Description= FrontEnd BankStatement
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/app/BlazorBankStatement/
ExecStart=/usr/local/bin/dotnet /var/www/app/BlazorBankStatement/BlazorFront.dll
Restart=always
RestartSec=10
SyslogIdentifier=YourApp
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
Environment=ASPNETCORE_URLS=http://192.168.0.156:5023

[Install]
WantedBy=multi-user.target

Program.cs代码(已多次调整,略显混乱)

using BlazorFront.Components;
using BlazorFront.Service;
using BlazorFront.Service.Interface;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.StaticFiles;
using NLog.Extensions.Logging;
using System.Net;

var builder = WebApplication.CreateBuilder(args);

// Adding Nlog to the pipeline
builder.Logging.AddNLog();

// Configure Kestrel to listen on all network interfaces on port 5023

// Adds the UseStaticWebAssets middleware to serve static files, including CSS, in production
if (!builder.Environment.IsDevelopment())
{
    builder.WebHost.ConfigureKestrel(options =>
    {
        options.Listen(IPAddress.Parse("192.168.0.156"), 5023);
        
    });
    
    builder.WebHost.UseStaticWebAssets();
    //builder.Services.AddDirectoryBrowser();
}

// Add services to the container.
builder.Services.AddRazorComponents()
                .AddInteractiveServerComponents();

// WEB API ADDRESS (change according to your deployment)
builder.Services.AddScoped(sp =>
    new HttpClient
    {
        BaseAddress = new Uri("http://192.168.0.156:5020")
    });

//Download Service
builder.Services.AddScoped<IFileDownloadService, FileDownloadService>();

var app = builder.Build();


app.UseStaticFiles();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseExceptionHandler("/Error", createScopeForErrors: true);
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseAntiforgery();

app.MapRazorComponents<App>().AddInteractiveServerRenderMode();

//Configuration of forwarded header to work with reverse proxy... Ngnix
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

//REMOVED TO AVOID AUTHENTICATION ERROR IN Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider ON Raspbery PI
//app.UseAuthentication();

//app.UseFileServer();
//var provider = new FileExtensionContentTypeProvider();
//provider.Mappings["{EXTENSION}"] = "{CONTENT TYPE}";
//app.UseStaticFiles(new StaticFileOptions { ContentTypeProvider = provider });
//app.UseFileServer(enableDirectoryBrowsing: true);



app.Run();

排查与解决建议

1. 修正Nginx配置的核心冲突

当前location /bank/同时使用root和proxy_pass,导致请求分流:部分资源被Nginx直接读取,部分被转发给Kestrel,这是404的主要原因。两种修正方案:

方案一:统一转发所有请求给Kestrel

直接删除root配置,让Kestrel处理所有请求(包括静态资源):

location /bank/ {
    proxy_pass         http://192.168.0.156:5023;
    include            proxy_params;
    access_log         /var/log/nginx/srv.local-bank-access.log;
    error_log          /var/log/nginx/srv.local-bank-error.log;
    proxy_set_header   Upgrade $http_upgrade;
    proxy_set_header   Connection keep-alive;
    proxy_set_header   Host $host;
    proxy_cache_bypass $http_upgrade;
    proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header   X-Forwarded-Proto $scheme;
    proxy_headers_hash_max_size 512;
    proxy_headers_hash_bucket_size 128; 
}

方案二:Nginx单独处理静态资源

让Nginx直接返回静态文件,动态请求转发给Kestrel:

location /bank/ {
    proxy_pass         http://192.168.0.156:5023;
    include            proxy_params;
    access_log         /var/log/nginx/srv.local-bank-access.log;
    error_log          /var/log/nginx/srv.local-bank-error.log;
    proxy_set_header   Upgrade $http_upgrade;
    proxy_set_header   Connection keep-alive;
    proxy_set_header   Host $host;
    proxy_cache_bypass $http_upgrade;
    proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header   X-Forwarded-Proto $scheme;
    proxy_headers_hash_max_size 512;
    proxy_headers_hash_bucket_size 128; 
}

# 单独匹配静态资源路径,直接返回本地文件
location ~ /bank/(css|javascript|images)/ {
    root /var/www/app/BlazorBankStatement;
    rewrite ^/bank/(.*)$ /wwwroot/$1 break; # 去掉URL中的/bank前缀,匹配正确路径
    expires 30d; # 开启静态资源缓存
}

2. 调整Program.cs中间件顺序

中间件执行顺序决定请求处理逻辑,UseForwardedHeaders必须放在UseStaticFiles之前,否则转发头信息无法生效,导致Kestrel处理路径错误:

var app = builder.Build();

// 先处理反向代理转发头
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

// 再处理静态文件
app.UseStaticFiles();

// 后续中间件保持原有顺序
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error", createScopeForErrors: true);
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseAntiforgery();

app.MapRazorComponents<App>().AddInteractiveServerRenderMode();

app.Run();

另外,生产环境下需确保发布时生成了staticwebassets.runtime.json文件,若缺失,重新发布时添加参数:dotnet publish --configuration Release。

3. 检查文件权限与发布完整性

  • 重置wwwroot权限:
sudo chown -R www-data:www-data /var/www/app/BlazorBankStatement/wwwroot
sudo chmod -R 755 /var/www/app/BlazorBankStatement/wwwroot
sudo find /var/www/app/BlazorBankStatement/wwwroot -type f -exec chmod 644 {} \;
  • 确认发布资源完整:检查树莓派部署目录的wwwroot/javascript、images等子目录是否和本地项目一致,若缺失则重新发布。

4. 修复Nginx日志为空问题

日志为空通常是权限不足或请求未匹配到当前location:

# 修复日志目录权限
sudo chown www-data:adm /var/log/nginx
sudo chmod 755 /var/log/nginx
# 重启Nginx
sudo systemctl restart nginx

之后访问静态资源,查看日志中的请求路径,确认是否符合预期。


内容的提问来源于stack exchange,提问作者Lauris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 21:23:10