Carlos Sura

Docker ASP.NET Core SSL Certificate Configuration (Linux & Windows Containers)

Running ASP.NET Core applications over HTTPS inside Docker requires mounting a PKCS#12 (.pfx) certificate into the container and passing Kestrel certificate environment variables. On Windows Server Nano Server containers, this often triggers cryptographic key permission errors if the default container user cannot read the imported certificate store.

Below is the step-by-step configuration for both local development and Windows/Linux container deployments.


Generate a Local Development Certificate (Optional)

If you do not already have a production .pfx certificate issued by your CA, generate and trust a self-signed development certificate using the .NET CLI:

dotnet dev-certs https -ep $env:USERPROFILE\.aspnet\https\aspnetapp.pfx -p "YourStrongPassword"
dotnet dev-certs https --trust

Run the ASP.NET Core Container on Linux / macOS

On Linux hosts, mount the directory containing your .pfx file into /https/ inside the container and configure Kestrel via environment variables:

docker pull mcr.microsoft.com/dotnet/samples:aspnetapp

docker run --rm -it \
  -p 8000:80 \
  -p 8001:443 \
  -e ASPNETCORE_URLS="https://+;http://+" \
  -e ASPNETCORE_HTTPS_PORT=8001 \
  -e ASPNETCORE_Kestrel__Certificates__Default__Password="YourStrongPassword" \
  -e ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx \
  -v "${HOME}/.aspnet/https:/https/:ro" \
  mcr.microsoft.com/dotnet/samples:aspnetapp

Resolving Certificate Permission Errors on Windows Server Containers

When running ASP.NET Core inside Windows Server / Nano Server containers (versions after Windows Server 2016), the default runtime account is ContainerUser rather than ContainerAdministrator. Because Windows imports .pfx private keys into the machine key store during Kestrel startup, ContainerUser can fail with an Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Access is denied error (tracked in dotnet/dotnet-docker#915).

To resolve this on Windows containers where Kestrel terminates TLS directly, run the container as ContainerAdministrator and bind-mount the host certificate folder:

docker run -d `
  -u ContainerAdministrator `
  -p 8000:80 `
  -p 8001:443 `
  -e ASPNETCORE_URLS="https://+;http://+" `
  -e ASPNETCORE_HTTPS_PORT=443 `
  -e ASPNETCORE_Kestrel__Certificates__Default__Password="ssl-password" `
  -e ASPNETCORE_Kestrel__Certificates__Default__Path=C:\https\ssl-certificate.pfx `
  -v C:\path-to-ssl\ssl\https:C:\https `
  [image-name] [container-name]

Production Security Best Practices

  • Prefer Reverse Proxy TLS Termination: In production Kubernetes, Azure Container Apps, or Docker Swarm environments, terminate TLS at an ingress controller or reverse proxy (Nginx, Traefik, Envoy, or Azure Application Gateway) so containers can run as unprivileged non-root users (USER $APP_UID on Linux or ContainerUser on Windows).
  • Never Bake .pfx Files into Images: Always mount certificates at runtime via read-only volumes or secret mounts (such as Docker Secrets, Kubernetes tls Secrets, or Azure Key Vault CSI drivers).

References