Condividi tramite


Ospitare e distribuire ASP.NET Core Blazor WebAssembly con Nginx

Di Andrii Annenko

Annotazioni

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 10 di questo articolo.

Avvertimento

Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 10 di questo articolo.

Questo articolo spiega come ospitare e distribuire applicazioni che prendono di mira .NET 8, 9 o 10 usando Blazor WebAssembly.

Questo articolo illustra la distribuzione dell'app direttamente in un host o in un contenitore Docker che include Nginx e i file dell'app pubblicata. La sezione hosting Docker illustra la pubblicazione dell'app, la copia dell'output pubblicato nella radice Web di Nginx nell'immagine del contenitore, la configurazione di Nginx per il routing sul lato client e l'applicazione di impostazioni di produzione comuni.

Configurazione minima di Nginx

Il file seguente nginx.conf è un esempio di configurazione Nginx minimo che mostra come configurare Nginx per inviare il index.html file ogni volta che non riesce a trovare un file corrispondente su disco. Indirizza inoltre Nginx a gestire i tipi MIME corretti definendo un types blocco (in alternativa, includere un mime.types file).

events { }
http {
    types {
        text/html                    html;
        text/css                     css;
        application/javascript       js mjs;
        application/json             json;
        application/manifest+json    webmanifest;

        application/wasm             wasm;

        application/octet-stream     dll pdb webcil;
    }

    server {
        listen 80;

        location / {
            root /usr/share/nginx/html;
            try_files $uri $uri/ /index.html =404;
        }
    }
}

Completare la configurazione di Nginx

L'esempio seguente nginx.conf si basa sulla configurazione minima. Include impostazioni facoltative per la memorizzazione nella cache, la compressione, la limitazione della frequenza e le intestazioni di sicurezza. Esaminare i commenti e rimuovere o modificare le impostazioni in base ai requisiti dell'app.

events { }
http {
    # Security hardening: Don't reveal the Nginx version in responses.
    server_tokens off;

    # Optional: Rate limiting to prevent a single client from sending too 
    # many requests.
    # Blazor WebAssembly apps can generate many requests during startup.
    limit_req_zone $binary_remote_addr zone=one:10m rate=60r/s;

    # Optional: Cache-Control policy by URI.
    # - index.html and service-worker.js: avoid caching so app updates are picked up.
    # - /_framework/*: fingerprinted assets can be cached long-term.
    map $uri $cache_control {
        default             "max-age=3600";
        /index.html         "no-cache";
        /service-worker.js  "no-cache";

        # IMPORTANT: .NET 8/9 Blazor WASM apps do not fingerprint these files
        # Uncomment if the Blazor WASM app targets .NET 8/9, remove for .NET 10
        # /_framework/blazor.boot.json        "no-cache";
        # /_framework/blazor.webassembly.js   "max-age=3600";
        # /_framework/dotnet.js               "max-age=3600";

        ~^/_framework/      "public, max-age=31536000, immutable";
        ~\.woff2?$          "public, max-age=31536000, immutable";
    }

    # MIME types for Blazor WebAssembly assets.
    types {
        text/html                           html htm;
        text/css                            css;
        application/javascript              js mjs;
        application/json                    json;
        application/manifest+json           webmanifest;
        application/wasm                    wasm;
        text/plain                          txt;
        text/xml                            xml;
        application/octet-stream            bin dll exe pdb blat dat webcil;

        # Images
        image/png                           png;
        image/jpeg                          jpg jpeg;
        image/gif                           gif;
        image/webp                          webp;
        image/avif                          avif;
        image/svg+xml                       svg;
        image/x-icon                        ico;

        # Fonts
        font/woff                           woff;
        font/woff2                          woff2;

        # Fallback for other MIME types
        application/octet-stream            *;
    }

    server {
        listen 80;

        location / {
            # Root path for static site content.
            root      /usr/share/nginx/html;

            # SPA/Blazor routing:
            # - Serve a file if it exists.
            # - Otherwise fall back to index.html.
            try_files $uri $uri/ /index.html =404;

            # Optional: Use the rate limit zone defined above.
            limit_req zone=one burst=60 nodelay;

            # Optional: Serve precompressed *.gz files (when present) instead of 
            # compressing on the fly.
            gzip_static on;

            # Optional: Caching policy based on "map $uri $cache_control" above.
            add_header Cache-Control $cache_control always;

            # Optional: Mitigate MIME sniffing.
            add_header X-Content-Type-Options "nosniff" always;
        }
    }
}

Se gli strumenti di sviluppo del browser o uno strumento di traffico di rete indicano che le richieste ricevono un codice di stato 503 - Servizio non disponibile , aumentare i rate valori e burst .

Per altre informazioni sulla configurazione del server Web Nginx in ambiente di produzione, vedere Creating NGINX Plus and NGINX Configuration Files (Creazione di file di configurazione NGINX Plus e NGINX).

Distribuzione di Docker

Il Dockerfile seguente pubblica un'app Blazor WebAssembly e gestisce gli asset Web statici dell'app da un'immagine Nginx.

L'esempio presuppone che:

  • Il file di progetto dell'app è denominato BlazorSample.csproj e si trova nella radice del contesto di compilazione Docker.
  • Un nginx.conf file è disponibile nella radice del contesto di compilazione Docker.

Ad esempio, Dockerfilenginx.conf e BlazorSample.csproj si trovano tutti nella stessa directory in cui si trova anche il resto del Blazor codice. In questo caso, docker build viene avviato in questa directory di lavoro.

# Build stage
# IMPORTANT: change the dotnet/sdk version to the one that your Blazor app targets
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-noble AS build
WORKDIR /source

RUN apt update \
    && apt install -y python3 \
    && dotnet workload install wasm-tools

COPY . .
RUN dotnet publish BlazorSample.csproj --output /app

# Runtime stage
FROM nginx:latest
COPY --from=build /app/wwwroot/ /usr/share/nginx/html/
COPY nginx.conf /etc/nginx/nginx.conf

Compilare ed eseguire l'immagine:

docker build -t blazor-wasm-nginx .
docker run --rm -p {PORT}:80 blazor-wasm-nginx

Per altre informazioni, vedere la guida di Nginx Docker.

Distribuzione ospitata in Linux (Nginx)

Configurare l'app con ForwardedHeadersOptions per inoltrare le X-Forwarded-For e X-Forwarded-Proto intestazioni seguendo le indicazioni riportate in Configurare ASP.NET Core per l'uso con server proxy e bilanciatori di carico.

Per altre informazioni sull'impostazione del percorso di base dell'app, inclusa la configurazione del percorso dell'app secondaria, vedere ASP.NET percorso di base dell'app CoreBlazor.

Seguire le indicazioni per un'app SignalR ASP.NET Core con le modifiche seguenti:

  • Rimuovere la configurazione per il buffering proxy (proxy_buffering off;) perché l'impostazione si applica solo agli eventi inviati dal server (SSE), che non sono rilevanti per Blazor le interazioni client-server dell'app.

  • Modificare il percorso location da /hubroute (location /hubroute { ... }) al percorso della sottoapp /{PATH} (location /{PATH} { ... }), dove il segnaposto {PATH} rappresenta il percorso della sottoapp.

    L'esempio seguente configura il server per un'app che risponde alle richieste nel percorso /radice :

    http {
        server {
            ...
            location / {
                ...
            }
        }
    }
    

    L'esempio seguente configura il percorso dell'app secondaria di /blazor:

    http {
        server {
            ...
            location /blazor {
                ...
            }
        }
    }
    

Risorse aggiuntive