How does Docker Desktop compute the URL to be used by Open in Browser command?

Hello everyone,

Could someone who knows explain how Docker Desktop computes the URL of the page that is launched when user clicks Open in Browser command for a running ASP.NET 5.0 Core microservice container? Specifically:

  • How does it figure whether to use HTTP or HTTPS (or does it always use one or the other)?
  • What does it do to construct the rest of the URL and/or Where does it look to get the info it needs to construct the URL?

Assume the following about the microservice (if needed to answer the question):

  • It is implemented in ASP.NET 5.0 Core in Visual Studio 2019.
  • It supports both HTTP and HTTPS
  • The Visual Studio Project of the microservice is enabled with Docker support - but NOT Container Orchestration. Therefore, the project has a Dockerfile, launchSettings.json and an appsettings.json - but it does NOT have a docker compose project and file.
  • launchUrl (in the Docker profile in launchSettings.json) is set to “{Scheme}://{ServiceHost}:{ServicePort}” - where Scheme can be either http or https, ServiceHost is “localhost” and ServicePort is either <httpPort> or <sslPort> (depending on Scheme).
  • sslPort and httpPort are also specified in the Docker profile in launchSettings.json - and are different from one another.
  • Both the above URLs launch the Swagger page of the microservice.
  • The microservice and its Docker container are launched from Visual Studio itself (not from a terminal prompt).
  • The Docker container os is Debian GNU/Linux version 10 (buster)…

Please let me know if you need any other information in order to answer the questions.

I am hoping the above information will help me find root cause of an issue I am seeing when I use Open in Browser on containers of microservices that I am working on.

I’d guess it’s just using the lowest internal port one has published. At least, that is what it seems to be doing for a container that does not even serve any web pages. Like the following makes it show only port 81 in the GUI, and clicking the button tries to open http://localhost:81 (which won’t work as busybox is not serving anything on port 123):

docker run --rm -it -p 81:123 -p 80:124 -p 443:125 busybox

Same goes for a different order of the command line arguments, which makes me assume it’s using the lowest port number in the container, not the first port that is published:

docker run --rm -it -p 443:125 -p 80:124 -p 81:123 busybox

This makes it use port 80:

docker run --rm -it -p 443:125 -p 80:124 -p 81:126 busybox

And both the following make it use port 443, but always http://, not https://:

docker run --rm -it -p 443:125 busybox
docker run --rm -it -p 443:443 busybox

So, I also assume that your browser is boldly trying HTTPS for you. It may even do that for non-443 ports, but you may not notice if the browser cannot connect, and then tries HTTP.

In short: just eye candy in Desktop.

Are you sure you don’t get redirected to that URL when going to just the domain name and port number?

@avbentem Thanks for your response.

I saw your hypothesis mentioned in one of the comments in this Issue: How do I configure what port will be opened in the browser when clicking on "Open in Browser" in the dashboard · Issue #9537 · docker/for-win · GitHub. But your explanation above is much clearer and more detailed - thank you for that. If the hypothesis is proved (or confirmed) to be correct, it would be nice if the explanation can be included in Docker Desktop documentation somewhere.

However, in my case it seems to be doing the exact opposite - which is what is causing the issue that I am investigating.

  • In my case, there are only 2 internal ports exposed in the docker run command issued by Visual Studio - 443 and 80.
  • These ports are mapped to 2 different ports on the host via the launchSettings.json of the microservice and you can see the mapping in the docker run command issued by VS (see below for the full run command).
  • If DD was taking the lowest internal port number, then “Open in Browser” should be using the port mapped to port 80 when constructing the URL - is that correct?. If it did that (and continued to use http as the protocol), then I wouldn’t have the issue that I do.
  • But, instead, it seems to be using the port mapped to port 443 (the “higher” port number) and trying to open that with http (instead of https) - this leads to page load failure with error code ERR_EMPTY_RESPONSE.
  • I have tried swapping the mapped ports - but behavior does not change. It seems to always use whatever port is mapped to port 443.

So I was hoping you or someone else on this forum has access to the Docker Desktop source code and can look it up and explain how exactly it constructs the URL - which would help me figure out the root cause of the issue.

Here is the docker run command issued by Visual Studio for your reference:

docker run --name=servicename --hostname=5006cbb77610 --env=ASPNETCORE_LOGGING__CONSOLE__DISABLECOLORS=true --env=ASPNETCORE_ENVIRONMENT=Development --env='ASPNETCORE_URLS=https://+:443;http://+:80' --env=ASPNETCORE_HTTPS_PORT=55019 --env=NUGET_PACKAGES=/root/.nuget/fallbackpackages2 --env='NUGET_FALLBACK_PACKAGES=/root/.nuget/fallbackpackages;/root/.nuget/fallbackpackages2' --env=DOTNET_USE_POLLING_FILE_WATCHER=1 --env=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin --env=DOTNET_RUNNING_IN_CONTAINER=true --env=DOTNET_VERSION=5.0.11 --env=ASPNET_VERSION=5.0.11 --volume='C:\Program Files\dotnet\sdk\NuGetFallbackFolder:/root/.nuget/fallbackpackages' --volume='C:\Users\userid\vsdbg\vs2017u5:/remote_debugger:rw' --volume='c:\pathToMicroserviceFolder:/app' --volume='c:\repopath:/src/' --volume='C:\Users\userid\AppData\Roaming\Microsoft\UserSecrets:/root/.microsoft/usersecrets:ro' --volume='C:\Users\userid\AppData\Roaming\ASP.NET\Https:/root/.aspnet/https:ro' --volume='C:\Users\userid\.nuget\packages\:/root/.nuget/fallbackpackages2' --network=xxxx-docker_default --workdir=/app **-p 55018:443 -p 55019:80** --restart=no --label='com.microsoft.visual-studio.project-name=microservicename' --label='com.microsoft.created-by=visual-studio' --runtime=runc --detach=true -t microservicename:dev -f /dev/null
.

To answer your question:

Are you sure you don’t get redirected to that URL when going to just the domain name and port number?

Yes - but only if I have a call to app.UseHttpsRedirection() in the Configure method of the Startup class of the microservice. If I do not include that line, then the Swagger page comes up under both HTTP and HTTPS without redirection.

Which port is shown in Docker Desktop? (Where it says “RUNNING PORT: 81” in my screenshot?)

And what do you see if you repeat my tests with busybox? (My tests executed with the latest Docker Desktop on both an M1 and Intel Mac.)

When clicking the container name, I also see the ports sorted on the container’s port number:

Docker Desktop shows the port number mapped to port 443 (55018 in the docker run command I provided earlier).

In my case, when I click the container name, ports are REVERSE-sorted on the container’s port number (443 comes first - then .

Do you think the difference in order is causing the issue? If so, what determines the order? (is it the order it appears in the docker run command?).

I am using Docker Desktop v4.0.1 (68347), Engine 20.10.8.

If you still want me to test with busybox, I will do that and get back to you…

For busybox we know there’s nothing in the container that provides any hints to Desktop, if (which I doubt) Desktop is somehow being smart about a .NET container. (Busybox is not serving any web application.) So, running at least docker run --rm -it -p 443:125 -p 80:124 -p 81:126 busybox may tell you more.

Like shown in my tests: not for me, with busybox.

I’m running Desktop 4.1.1 (69879) here, with the same Engine.

But I’m afraid one can say it’s not a reliable way to help people open your application in their browser. (I’ve seen Desktop offer opening a web browser for database containers, also not serving HTTP at all.)

I ran the docker run command you provided and here is what I see:

Port number displayed in Docker Desktop is 80.

Port order is sorted by container port number (increasing) as it was for you.

Clicking Open in Browser gives me the same ERR_EMPTY_RESPONSE error page - URL is http://localhost (without port number). Editing the URL and hitting Enter does not resolve the issue. I am assuming this is expected behavior since busybox does not serve a web application.

So it looks like in my case, something is making it think that 443 is the “lowest” numbered internal port - and not 80. Either that or (as you said) it is using a different algorithm to select the port number for Open in Browser in case of a .NET Core container.

Let me know if you have any additional thoughts.

Regardless, I do appreciate your time and help on this.

Curious if there’s an answer to the original question: “How does Docker Desktop compute the URL to be used by Open in Browser command?”

Or if there’s a way to set the URL (not just the port) for the ‘OPEN IN BROWSER’ button:
image