다음을 통해 공유


Nginx를 사용하여 ASP.NET Core Blazor WebAssembly 호스트 및 배포

안드리 아넨코

비고

이 기사는 최신 버전이 아닙니다. 현재 릴리스는 이 문서의 .NET 10 버전을 참조하세요.

경고

이 버전의 ASP.NET Core는 더 이상 지원되지 않습니다. 자세한 내용은 .NET 및 .NET Core 지원 정책을 참조하세요. 현재 릴리스는 이 문서의 .NET 10 버전을 참조하세요.

이 문서에서는 Blazor WebAssembly를 사용하여 .NET 8, 9 또는 10을 대상으로 하는 호스트 및 배포 방법을 설명합니다.

이 문서에서는 호스트 또는 Nginx 및 게시된 앱의 파일을 포함하는 Docker 컨테이너에 직접 앱을 배포하는 것에 대해 설명합니다. Docker 호스팅 섹션에서는 앱을 게시하고, 게시된 출력을 컨테이너 이미지의 Nginx 웹 루트에 복사하고, 클라이언트 쪽 라우팅을 위해 Nginx를 구성하고, 일반적인 프로덕션 설정을 적용하는 방법을 설명합니다.

최소 Nginx 구성

다음 nginx.conf 파일은 디스크에서 해당 파일을 찾을 수 없을 때마다 파일을 보내 index.html 도록 Nginx를 구성하는 방법을 보여 주는 최소 Nginx 구성 예제입니다. 또한 Nginx가 types 블록을 정의하여 올바른 MIME 타입을 제공하도록 지시합니다. (대안으로는 mime.types 파일을 포함할 수도 있습니다.)

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;
        }
    }
}

Nginx 구성 완료

다음 nginx.conf 예제에서는 최소 구성을 기반으로 합니다. 여기에는 캐싱, 압축, 속도 제한 및 보안 헤더에 대한 선택적 설정이 포함됩니다. 댓글을 검토하고 앱의 요구 사항에 따라 설정을 제거하거나 조정합니다.

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;
        }
    }
}

브라우저 개발자 도구 또는 네트워크 트래픽 도구에서 요청이 503 - 서비스 사용 불가 상태 코드를 수신하고 있음을 나타내는 경우, rateburst 값을 증가시키세요.

프로덕션 Nginx 웹 서버 구성에 대한 자세한 내용은 NGINX Plus 및 NGINX 구성 파일 만들기를 참조하세요.

Docker 배포

다음 Dockerfile은 Blazor WebAssembly 앱을 게시하고, Nginx 이미지로 앱의 정적 웹 자산을 제공합니다.

이 예제에서는 다음을 가정합니다.

  • 앱의 프로젝트 파일 이름은 BlazorSample.csproj Docker 빌드 컨텍스트 루트에 있습니다.
  • nginx.conf Docker 빌드 컨텍스트 루트에서 파일을 사용할 수 있습니다.

예를 들어 Dockerfile, nginx.confBlazorSample.csproj 모두 코드의 Blazor 나머지 부분도 있는 동일한 디렉터리에 있습니다. 이 경우 docker build 이 작업 디렉터리에서 시작됩니다.

# 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

이미지를 빌드하고 실행합니다.

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

자세한 내용은 Nginx Docker 가이드를 참조하세요.

Linux에서 호스트된 배포(Nginx)

ForwardedHeadersOptions를 사용하여 헤더 X-Forwarded-ForX-Forwarded-Proto를 전달하도록 앱을 구성하고, 프록시 서버와 부하 분산 장치에서 ASP.NET Core를 작동하도록 구성 지침을 따르십시오.

하위 앱 경로 구성을 포함하여 앱의 기본 경로를 설정하는 방법에 대한 자세한 내용은 ASP.NET Core Blazor 앱 기본 경로를 참조하세요.

다음 변경 내용에 대해 ASP.NET Core SignalR 앱의 지침을 따릅니다.

  • 이 설정은 proxy_buffering off; 앱 클라이언트-서버 상호 작용과 관련이 없는 SSE(Server-Sent 이벤트)에 적용되므로 프록시 버퍼링(Blazor)에 대한 구성을 제거합니다.

  • location 경로를 /hubroute (location /hubroute { ... })에서 하위 앱 경로 /{PATH} (location /{PATH} { ... })로 변경합니다. 여기서 {PATH} 자리 표시자는 하위 앱 경로를 나타냅니다.

    다음 예제에서는 루트 경로 /의 요청에 응답하는 앱에 대한 서버를 구성합니다.

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

    다음 예는 /blazor의 하위 앱 경로를 구성합니다.

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

추가 리소스