Publish official container image for Microsoft.AspNetCore.Components.Gateway (Blazor Gateway)
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
Description
## Summary
Publish an official container image for the Blazor Gateway (`Microsoft.AspNetCore.Components.Gateway`) so customers can run it as a sidecar/reverse-proxy in Kubernetes, Docker Compose, ACA, and other container hosts without authoring their own Dockerfile.
This mirrors the existing [`mcr.microsoft.com/dotnet/nightly/yarp`](https://hub.docker.com/_/microsoft-dotnet-nightly-yarp/) image produced by [`dotnet/dotnet-docker`](https://github.com/dotnet/dotnet-docker), and follows the same distribution pattern already used for YARP and `dotnet-monitor`.
## Motivation
The Blazor Gateway today is shipped as a NuGet package (`Microsoft.AspNetCore.Components.Gateway`) that is consumed by the Blazor WebAssembly standalone template via ``. The package's `tools/blazor-gateway.dll` layout makes it trivially extractable, but every customer who wants to deploy the gateway separately from their WASM app has to write their own Dockerfile to do so.
Common deployment scenarios that need a prebuilt image:
- Running the gateway as an ingress/reverse-proxy in front of a Blazor WASM app served by a static host (S3, blob storage, nginx).
- Running the gateway as a sidecar in a Kubernetes pod alongside a backend API.
- Running the gateway in Azure Container Apps / App Service Containers as part of a multi-service Blazor deployment.
These are the same scenarios that motivated the official YARP image. Providing a Microsoft-published image avoids forcing every customer to repeat the same boilerplate and gives us a single hardened, scanned, and patched artifact to recommend.
## Proposed image
| Property | Value |
|---|---|
| Repository | `mcr.microsoft.com/dotnet/nightly/blazor-gateway` (eventually `mcr.microsoft.com/dotnet/blazor-gateway` for GA) |
| Source repo | `dotnet/dotnet-docker` |
| Base image | `mcr.microsoft.com/dotnet/aspnet:-azurelinux-distroless` (with non-distroless variants per the YARP matrix) |
| Tags | ``, `-azurelinux`, `-azurelinux-distroless`, `latest` — same axes as YARP |
| Architectures | `linux/amd64`, `linux/arm64` (same as YARP) |
| Entrypoint | `["dotnet", "/app/blazor-gateway.dll"]` |
| Listening port | `8080` (matches distroless aspnet default), configurable via `ASPNETCORE_URLS` |
| Configuration | Same env vars supported by the gateway today (cluster URL, identity provider URL, etc.) |
## Distribution pattern
The Blazor Gateway nupkg already ships a tool-shaped layout under `tools/`. The image build can reuse it directly — no new artifact format is required.
### Dockerfile sketch (validated locally against the existing package)
```dockerfile
# installer stage — extract the gateway binaries from the official .nupkg
FROM mcr.microsoft.com/azurelinux/base/core:3.0 AS installer
ARG BLAZOR_GATEWAY_VERSION
RUN tdnf install -y unzip ca-certificates && tdnf clean all \
&& curl -fsSL "https://www.nuget.org/api/v2/package/Microsoft.AspNetCore.Components.Gateway/${BLAZOR_GATEWAY_VERSION}" \
-o /tmp/gateway.nupkg \
&& mkdir -p /app \
&& unzip /tmp/gateway.nupkg "tools/*" -d /tmp/pkg \
&& cp -r /tmp/pkg/tools/. /app/ \
&& rm -rf /tmp/pkg /tmp/gateway.nupkg
# runtime stage — distroless aspnet
FROM mcr.microsoft.com/dotnet/aspnet:11.0-azurelinux3.0-distroless
COPY --from=installer /app /app
ENV ASPNETCORE_HTTP_PORTS=8080
ENTRYPOINT ["dotnet", "/app/blazor-gateway.dll"]
EXPOSE 8080
```
This is structurally identical to the [YARP image Dockerfile in `dotnet/dotnet-docker`](https://github.com/dotnet/dotnet-docker), the only differences being:
| | YARP | Blazor Gateway |
|---|---|---|
| Source artifact | per-RID zip on `dotnetstage.blob.core.windows.net/reverse-proxy/$version/reverse-proxy-linux-{x64,arm64}.zip` | RID-agnostic `.nupkg` on nuget.org |
| Extraction | `unzip` zip to `/app` | `unzip tools/* ` from `.nupkg` to `/app` |
| Entrypoint dll | `yarp.dll` | `blazor-gateway.dll` |
| Default config | `/etc/yarp.config` mounted by the user | env-var based (no external config file required for the standalone template scenario) |
### Why this works without changing the gateway package
I prototyped this locally (see #67092) against the current `Microsoft.AspNetCore.Components.Gateway.11.0.0-dev.nupkg`. The extracted `tools/` layout contains everything the gateway needs at runtime:
- `blazor-gateway.dll` + `blazor-gateway.deps.json` + `blazor-gateway.runtimeconfig.json`
- All transitive dependency DLLs (OpenTelemetry, YARP, Microsoft.Extensions.ServiceDiscovery, Polly, Resilience, HealthChecks)
- `appsettings.json`
Combined with `mcr.microsoft.com/dotnet/aspnet:11.0-preview` (or distroless variant), the image starts and serves `/health` and `/alive` with no additional configuration.
The only hardening work that is **not** carried by the current package and would be needed for the image is the same work `dotnet/dotnet-docker` already does for YARP and `dotnet-monitor`:
- Pick a stable non-root UID and ensure `/app` is readable to it.
- Set `ASPNETCORE_HTTP_PORTS` so the gateway binds to a port the non-root user can use (8080 by convention).
- Expose `/health` and `/alive` as documented liveness/readiness endpoints.
## Work breakdown
- [ ] Add `src/blazor-gateway/` to `dotnet/dotnet-docker` mirroring `src/yarp/` (Dockerfile per OS × distro × distroless, Compose-based smoke tests).
- [ ] Wire the image into the `dotnet/dotnet-docker` build matrix and MCR publishing pipeline (`nightly` → `main` graduation).
- [ ] Add a manifest for the image (`manifest.json`) so it shows up in the `dotnet/dotnet-docker` README and on MCR.
- [ ] Documentation:
- README under `dotnet/dotnet-docker/src/blazor-gateway/` describing supported tags, environment variables, default ports, health endpoints.
- Update the Blazor WASM template docs to mention the container image as a production deployment option.
- [ ] Decide on a versioning cadence (track the ASP.NET Core minor like YARP, or independent semver).
## Alternative considered
Repackaging the gateway as a `dotnet tool` (`PackAsTool=true`) so it can be installed with `dotnet tool install -g blazor-gateway`. Investigated in #67092 and rejected because NU1212 prevents tool packages from being consumed via ``, which would break the existing WASM template UX. The container image is therefore the right vehicle for sidecar/standalone deployment without changing the package shape.
## References
- #67092 — Investigation of tool packaging (closed as won't-fix; container approach validated)
- [`dotnet/dotnet-docker/src/yarp/`](https://github.com/dotnet/dotnet-docker/tree/main/src/yarp) — YARP image precedent
- [`dotnet/dotnet-docker/src/monitor/`](https://github.com/dotnet/dotnet-docker/tree/main/src/monitor) — dotnet-monitor image precedent (also a published tool with a container image)
- [`mcr.microsoft.com/dotnet/nightly/yarp`](https://mcr.microsoft.com/en-us/artifact/mar/dotnet/nightly/yarp) — published YARP image
Contributor guide
Assessment
This issue has not been assessed yet.