Skip to content

Commit bb88f49

Browse files
authored
Merge pull request #36656 from dotnet/main
2 parents 10b90ac + 0a66d9b commit bb88f49

1 file changed

Lines changed: 144 additions & 12 deletions

File tree

  • aspnetcore/blazor/host-and-deploy/webassembly

aspnetcore/blazor/host-and-deploy/webassembly/nginx.md

Lines changed: 144 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,188 @@
11
---
22
title: Host and deploy ASP.NET Core Blazor WebAssembly with Nginx
3+
ai-usage: ai-assisted
34
author: guardrex
45
description: Learn how to host and deploy Blazor WebAssembly using Nginx.
56
monikerRange: '>= aspnetcore-3.1'
67
ms.author: wpickett
78
ms.custom: mvc, linux-related-content
8-
ms.date: 11/11/2025
9+
ms.date: 01/21/2026
910
uid: blazor/host-and-deploy/webassembly/nginx
1011
---
1112
# Host and deploy ASP.NET Core Blazor WebAssembly with Nginx
1213

14+
By [Andrii Annenko](https://github.com/aannenko)
15+
1316
[!INCLUDE[](~/includes/not-latest-version.md)]
1417

15-
This article explains how to host and deploy Blazor WebAssembly using [Nginx](https://nginx.org/).
18+
This article explains how to host and deploy Blazor WebAssembly that targets .NET 8, 9 or 10 using [Nginx](https://nginx.org/).
1619

17-
The following `nginx.conf` file is simplified to show how to configure Nginx to send the `index.html` file whenever it can't find a corresponding file on disk.
20+
This article covers deploying the app either directly on a host or in a Docker container that includes Nginx and the published app's files. The Docker hosting section covers publishing the app, copying the published output to Nginx's web root in the container image, configuring Nginx for client-side routing, and applying common production settings.
1821

19-
```
22+
## Minimal Nginx configuration
23+
24+
The following `nginx.conf` file is a minimal Nginx configuration example showing how to configure Nginx to send the `index.html` file whenever it can't find a corresponding file on disk. It also directs Nginx to serve correct MIME types by defining a `types` block (alternatively, include a [`mime.types`](https://github.com/nginx/nginx/blob/7fa941a55e211ebd57f512fbfb24d59dbb97940d/conf/mime.types) file).
25+
26+
```nginx
2027
events { }
2128
http {
29+
types {
30+
text/html html;
31+
text/css css;
32+
application/javascript js mjs;
33+
application/json json;
34+
application/manifest+json webmanifest;
35+
36+
application/wasm wasm;
37+
38+
application/octet-stream dll pdb webcil;
39+
}
40+
2241
server {
2342
listen 80;
2443
2544
location / {
26-
root /usr/share/nginx/html;
45+
root /usr/share/nginx/html;
2746
try_files $uri $uri/ /index.html =404;
2847
}
2948
}
3049
}
3150
```
3251

33-
When setting the [NGINX burst rate limit](https://www.nginx.com/blog/rate-limiting-nginx/#bursts) with [`limit_req`](https://nginx.org/docs/http/ngx_http_limit_req_module.html#limit_req) and [`limit_req_zone`](https://nginx.org/docs/http/ngx_http_limit_req_module.html), Blazor WebAssembly apps may require a large `burst`/`rate` parameter values to accommodate the relatively large number of requests made by an app. Initially, set the value to at least 60:
52+
## Complete Nginx configuration
3453

35-
```
54+
The following `nginx.conf` example builds on the minimal configuration. It includes optional settings for caching, compression, rate limiting, and security headers. Review the comments and remove or adjust settings based on your app's requirements.
55+
56+
```nginx
57+
events { }
3658
http {
59+
# Security hardening: Don't reveal the Nginx version in responses.
60+
server_tokens off;
61+
62+
# Optional: Rate limiting to prevent a single client from sending too
63+
# many requests.
64+
# Blazor WebAssembly apps can generate many requests during startup.
3765
limit_req_zone $binary_remote_addr zone=one:10m rate=60r/s;
66+
67+
# Optional: Cache-Control policy by URI.
68+
# - index.html and service-worker.js: avoid caching so app updates are picked up.
69+
# - /_framework/*: fingerprinted assets can be cached long-term.
70+
map $uri $cache_control {
71+
default "max-age=3600";
72+
/index.html "no-cache";
73+
/service-worker.js "no-cache";
74+
75+
# IMPORTANT: .NET 8/9 Blazor WASM apps do not fingerprint these files
76+
# Uncomment if the Blazor WASM app targets .NET 8/9, remove for .NET 10
77+
# /_framework/blazor.boot.json "no-cache";
78+
# /_framework/blazor.webassembly.js "max-age=3600";
79+
# /_framework/dotnet.js "max-age=3600";
80+
81+
~^/_framework/ "public, max-age=31536000, immutable";
82+
~\.woff2?$ "public, max-age=31536000, immutable";
83+
}
84+
85+
# MIME types for Blazor WebAssembly assets.
86+
types {
87+
text/html html htm;
88+
text/css css;
89+
application/javascript js mjs;
90+
application/json json;
91+
application/manifest+json webmanifest;
92+
application/wasm wasm;
93+
text/plain txt;
94+
text/xml xml;
95+
application/octet-stream bin dll exe pdb blat dat webcil;
96+
97+
# Images
98+
image/png png;
99+
image/jpeg jpg jpeg;
100+
image/gif gif;
101+
image/webp webp;
102+
image/avif avif;
103+
image/svg+xml svg;
104+
image/x-icon ico;
105+
106+
# Fonts
107+
font/woff woff;
108+
font/woff2 woff2;
109+
110+
# Fallback for other MIME types
111+
application/octet-stream *;
112+
}
113+
38114
server {
39-
...
115+
listen 80;
40116
41117
location / {
42-
...
118+
# Root path for static site content.
119+
root /usr/share/nginx/html;
43120
121+
# SPA/Blazor routing:
122+
# - Serve a file if it exists.
123+
# - Otherwise fall back to index.html.
124+
try_files $uri $uri/ /index.html =404;
125+
126+
# Optional: Use the rate limit zone defined above.
44127
limit_req zone=one burst=60 nodelay;
128+
129+
# Optional: Serve precompressed *.gz files (when present) instead of
130+
# compressing on the fly.
131+
gzip_static on;
132+
133+
# Optional: Caching policy based on "map $uri $cache_control" above.
134+
add_header Cache-Control $cache_control always;
135+
136+
# Optional: Mitigate MIME sniffing.
137+
add_header X-Content-Type-Options "nosniff" always;
45138
}
46139
}
47140
}
48141
```
49142

50-
Increase the value if browser developer tools or a network traffic tool indicates that requests are receiving a *503 - Service Unavailable* status code.
143+
If browser developer tools or a network traffic tool indicates that requests are receiving a *503 - Service Unavailable* status code, increase the `rate` and `burst` values.
51144

52145
For more information on production Nginx web server configuration, see [Creating NGINX Plus and NGINX Configuration Files](https://docs.nginx.com/nginx/admin-guide/basic-functionality/managing-configuration-files/).
53146

147+
## Docker deployment
148+
149+
The following Dockerfile publishes a Blazor WebAssembly app and serves the app's static web assets from an Nginx image.
150+
151+
The example assumes that:
152+
153+
* The app's project file is named `BlazorSample.csproj` and located at the Docker build context root.
154+
* An `nginx.conf` file is available at the Docker build context root.
155+
156+
For example, `Dockerfile`, `nginx.conf` and `BlazorSample.csproj` are all located in the same directory where the rest of Blazor code is also located. In this case, `docker build` is launched in this working directory.
157+
158+
```dockerfile
159+
# Build stage
160+
# IMPORTANT: change the dotnet/sdk version to the one that your Blazor app targets
161+
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-noble AS build
162+
WORKDIR /source
163+
164+
RUN apt update \
165+
&& apt install -y python3 \
166+
&& dotnet workload install wasm-tools
167+
168+
COPY . .
169+
RUN dotnet publish BlazorSample.csproj --output /app
170+
171+
# Runtime stage
172+
FROM nginx:latest
173+
COPY --from=build /app/wwwroot/ /usr/share/nginx/html/
174+
COPY nginx.conf /etc/nginx/nginx.conf
175+
```
176+
177+
Build and run the image:
178+
179+
```bash
180+
docker build -t blazor-wasm-nginx .
181+
docker run --rm -p {PORT}:80 blazor-wasm-nginx
182+
```
183+
184+
For more information, refer to [Nginx Docker guide](https://hub.docker.com/_/nginx).
185+
54186
:::moniker range="< aspnetcore-8.0"
55187

56188
## Hosted deployment on Linux (Nginx)
@@ -66,7 +198,7 @@ Follow the guidance for an [ASP.NET Core SignalR app](xref:signalr/scale#linux-w
66198

67199
The following example configures the server for an app that responds to requests at the root path `/`:
68200

69-
```
201+
```nginx
70202
http {
71203
server {
72204
...
@@ -79,7 +211,7 @@ Follow the guidance for an [ASP.NET Core SignalR app](xref:signalr/scale#linux-w
79211

80212
The following example configures the sub-app path of `/blazor`:
81213

82-
```
214+
```nginx
83215
http {
84216
server {
85217
...

0 commit comments

Comments
 (0)