ASP.NET Core Dockerfile for .NET 10 (Multi-Stage, Non-Root)
This ASP.NET Core Dockerfile restores and publishes your app on the .NET 10 SDK image, then runs the output on the much smaller aspnet:10.0 runtime image. It uses the built-in non-root app user and Kestrel's default port 8080. It suits Minimal APIs, MVC and Razor Pages apps.
- CI status
- Build passing
- Image size (uncompressed)
- 230.1 MB
- Build time
- 6 s
- Runtime image
mcr.microsoft.com/dotnet/aspnet:10.0- Port
- 8080
- Last built
- 2026-10-15
# syntax=docker/dockerfile:1
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY *.csproj ./
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish --no-restore
FROM mcr.microsoft.com/dotnet/aspnet:10.0
WORKDIR /app
COPY --from=build /app/publish .
USER $APP_UID
EXPOSE 8080
ENTRYPOINT ["dotnet", "App.dll"].git
bin/
obj/
.vs/
.env
Dockerfile
.dockerignoreBefore you build
- Name the project file App.csproj, or change App.dll in the ENTRYPOINT to match your assembly name.
- Target net10.0 in the project file.
- Let Kestrel listen on the image's default port 8080, or override ASPNETCORE_HTTP_PORTS.
How this Dockerfile works
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS buildThe SDK image contains the compiler and NuGet tooling. It's large, but it's only used to produce the published output.
COPY *.csproj ./ RUN dotnet restoreRestoring NuGet packages from the project file alone creates a cached layer, so code changes don't trigger a full package restore.
RUN dotnet publish -c Release -o /app/publish --no-restoreCompiles a Release build into a single output folder. --no-restore reuses the packages restored in the earlier cached layer.
FROM mcr.microsoft.com/dotnet/aspnet:10.0The ASP.NET Core runtime image has no SDK or compiler, only what's needed to run web apps, which keeps the deployed image much smaller.
COPY --from=build /app/publish .Copies only the published assemblies and content files into the runtime image.
USER $APP_UIDOfficial .NET images define a non-root app user and expose its ID as APP_UID. Switching to it means the app never runs as root.
ENTRYPOINT ["dotnet", "App.dll"]Starts your assembly with the dotnet host as the main process, so stop signals trigger ASP.NET Core's graceful shutdown.
Build and run
docker build -t aspnet-core-app .
docker run --rm -p 8080:8080 aspnet-core-appBuild from the folder that contains App.csproj, then open http://localhost:8080. Set ASPNETCORE_ENVIRONMENT and connection strings with -e flags at runtime.
Other ASP.NET Core Dockerfile variants
The standard aspnet runtime image suits most apps. Chiseled Ubuntu images remove the shell and package manager for a smaller attack surface, and native AOT variants trade build complexity for faster startup. Verified variants appear in the table below.
| Variant | Runtime image | Image size | CI |
|---|---|---|---|
| .NET 10 SDK build + ASP.NET runtime | mcr.microsoft.com/dotnet/aspnet:10.0 | 230.1 MB | Passing |
Troubleshooting
- Could not execute because the specified command or file was not found: App.dll
- Your assembly has a different name. Use the name of your .csproj file, or set AssemblyName in the project, so the ENTRYPOINT matches.
- The app starts but nothing answers on port 8080
- Something overrides the listening URL, such as launchSettings or a UseUrls call. In containers, configure ports with ASPNETCORE_HTTP_PORTS instead.
- Permission denied writing to the app directory
- The non-root user can't write where root-owned files were copied. Write temporary data to /tmp, or use a mounted volume for persistent files.
FAQ
- Why is the port 8080 and not 80?
- Since .NET 8, the official images default to port 8080 so apps can run as non-root users, which can't bind to privileged ports such as 80.
- Do I need the SDK image in production?
- No. The SDK is only needed to build. The aspnet runtime image is far smaller and has fewer packages that could need security updates.
- How do I handle multiple projects in a solution?
- Copy every project file the web project references before running restore, then publish the web project by its path. Large solutions often copy the solution file too.