ASP.NET Core 2.1 application in Docker with HTTPS enabled

In one of my previous blog posts, I talked about using HSTS in ASP.Net Core application, today we look into how to deploy ASP.NET Core 2.1 application in Docker with HTTPS enabled.

If you want to use Docker for development, you will have a problem using https and that is that you must install the certificate in the image. Using a dotnet RUN dev-certs https -trust in the Dockerfile is not an option, because that command belongs to the netcore SDK and therefore is not available in an image with just the runtime (besides the small detail that, for the moment, it is not available for Linux).

Docker File

To see what we need, let’s start with the typical Dockerfile of multistage generated by Visual Studio itself:

FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY Webapi8/mywebapi.csproj mywebapi/
RUN dotnet restore Webapi8/mywebapi.csproj
COPY . .
WORKDIR /src/mywebapi
RUN dotnet build mywebapi.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish mywebapi.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "mywebapi.dll"]

If we start it, the first thing we will see is that it gives us an error when redirecting to https.

This error ( Failed to determine the https port for redirect ) is because the redirection middleware does not know which is the port of HTTPS, since this port is set in an environment variable called ASPNETCORE_HTTPS_PORT, therefore we must establish a value to that variable, using p. ex :

docker run -p5000:80 -p:5001:443 -e ASPNETCORE_HTTPS_PORT=5001 mywebapi

If you now browse to http://localhost:500 /api/values the browser will be redirected to https://localhost: 5001/api/values, but nobody is listening there. Kestrel has not lifted the SSL port. To raise it, we must indicate it using the ASPNETCORE_URLS environment variable:

docker run -p5000:80 -p:5001:443 -e ASPNETCORE_HTTPS_PORT=5001 -e ASPNETCORE_URLS=https://+;http://+ mywebapi

And now, when launching the image, we will receive an error that Kestrel cannot open the https port because it does not have the certificate:

crit: Microsoft.AspNetCore.Server.Kestrel[0]
      Unable to start Kestrel.
System.InvalidOperationException: Unable to configure HTTPS endpoint. No server certificate was specified, and the default developer certificate could not be found.

HTTPS Certificate

We need to share the certificate of development that we have in our machine, with the image of Docker. For this we export it to pfx, using the following command from our machine (use the route you want):

dotnet dev-certs https -v -ep d:\temp\cert-aspnetcore.pfx -p ufo

Important: You MUST use -p to set a password for the pfx file, otherwise it will not work, since the private key will not be included in the file (and Kestrel will give you an error ( System.NotSupportedException: The server mode SSL must use a certificate with the associated private key ) when accessing via https).

With that, we export the development certificate of our machine (in my case ad: \ temp \ cert-aspnetcore.pfx). The next step is to tell Kestrel that it runs in Docker where that certificate is , using the environment variables Kestrel__Certificates__Default__Path and Kestrel__Certificates__Default__Password and of course sharing the pfx file using a bind mount :

docker run -p5000:80 -p:5001:443 -e ASPNETCORE_HTTPS_PORT=5001 -e ASPNETCORE_URLS=https://+;http://+ -e Kestrel__Certificates__Default__Path=/root/.dotnet/https/cert-aspnetcore.pfx -e Kestrel__Certificates__Default__Password=ufo -v D:\temp\:/root/.dotnet/https mywebapi

With that, Kestrel looks for the certificate in the indicated directory (/root/.dotnet/https) where there is the pfx that we have in our development machine.

And if you now access http://localhost: 5000/api/values, you will be redirected to https://localhost: 5001/api/values and you should not receive any errors.

Of course, it’s much better to use a compose file before that “docker run” call with so many parameters -ey -v, but well, that’s already minor details 😉 The important thing is that you follow these:

  • We generate a certificate on our machine using dotnet dev-certs.
  • We export it to pfx
  • We share this certificate with to Docker’s image
  • We use the Kestrel configuration block: Certificates: Default to indicate where the certificate is and its password

You may also like...

Leave a Reply

Your email address will not be published.