Skip to main content
Notice removed Draw attention by Mathias Conradt
Bounty Ended with harrymc's answer chosen by Mathias Conradt
added 801 characters in body
Source Link

For now, I just demonstrate the steps that I did with Powershell (but it does not work with the Docker approach either):========================= Powershell approach ==========================

========================= Docker approach ==========================

And this is my approach using Docker to manage the container:

C:\> docker run --name iisbase -it windowsservercore cmd
C:\> powershell.exe Install-WindowsFeature web-server
C:\> exit
PS C:\Windows\system32> docker commit iisbase windowsservercoreiis
64271b60a1c4af29ce37ebcee45b00d824883eb67c717d4cee765d9f696867bb
C:\> powershell.exe "if(!(Get-NetFirewallRule | where {$_.Name -eq 'TCP80'})) { New-NetFirewallRule -Name 'TCP80' -DisplayName 'HTTP on TCP/80' -Protocol tcp -LocalPort 80 -Action Allow -Enabled True }"
C:\> docker run --name iisdemo -it -p 80:80 windowsservercoreiis cmd

At the end, I can only reach the IIS via the container IP, not via the host IP.

I'm using Docker version 1.10.0-dev, build 18c9fe0.

For now, I just demonstrate the steps that I did with Powershell (but it does not work with the Docker approach either):

========================= Powershell approach ==========================

========================= Docker approach ==========================

And this is my approach using Docker to manage the container:

C:\> docker run --name iisbase -it windowsservercore cmd
C:\> powershell.exe Install-WindowsFeature web-server
C:\> exit
PS C:\Windows\system32> docker commit iisbase windowsservercoreiis
64271b60a1c4af29ce37ebcee45b00d824883eb67c717d4cee765d9f696867bb
C:\> powershell.exe "if(!(Get-NetFirewallRule | where {$_.Name -eq 'TCP80'})) { New-NetFirewallRule -Name 'TCP80' -DisplayName 'HTTP on TCP/80' -Protocol tcp -LocalPort 80 -Action Allow -Enabled True }"
C:\> docker run --name iisdemo -it -p 80:80 windowsservercoreiis cmd

At the end, I can only reach the IIS via the container IP, not via the host IP.

I'm using Docker version 1.10.0-dev, build 18c9fe0.

added 6 characters in body
Source Link

I tried both the approach via Powershell and Docker, butand in both cases, the port binding to the host does not work.

PS C:> wget -uri https://aka.ms/tp4/Install-ContainerHost -OutFile C:\Install-ContainerHost.ps1

PS C:> powershell.exe -NoProfile C:\Install-ContainerHost.ps1 

Querying status of Windows feature: Containers...
Feature Containers is already enabled.
Waiting for Hyper-V Management...
Networking is already configured.  Confirming configuration...
Getting Container OS image (NanoServer) version 10.0.10586.0 from OneGet (this may take a few minutes)...
Container base image install complete.  Querying container images...
OS image (NanoServer) is already installed.
The following images are present on this machine:
    ContainerImage (Name = 'NanoServer') [Publisher = 'CN=Microsoft', Version = '10.0.10586.0']
    ContainerImage (Name = 'WindowsServerCore') [Publisher = 'CN=Microsoft', Version = '10.0.10586.0']

Docker is already installed.
Stopping Docker...
Starting Docker...
Tagging new base image (8572198a60f1)...
Base image is now tagged:
nanoserver          10.0.10586.0        8572198a60f1        5 months ago        0 B
nanoserver          latest              8572198a60f1        5 months ago        0 B
Script complete!

Now that I added the port mapping (and firewall rule), I should be able to reach the IIS through my host. (Just to be sure, I disabled the firewall on the host entirely.)

I tried both the approach via Powershell and Docker, but in both cases, the port binding to the host does not work.

PS C:> wget -uri https://aka.ms/tp4/Install-ContainerHost -OutFile C:\Install-ContainerHost.ps1

PS C:> powershell.exe -NoProfile C:\Install-ContainerHost.ps1
Querying status of Windows feature: Containers...
Feature Containers is already enabled.
Waiting for Hyper-V Management...
Networking is already configured.  Confirming configuration...
Getting Container OS image (NanoServer) version 10.0.10586.0 from OneGet (this may take a few minutes)...
Container base image install complete.  Querying container images...
OS image (NanoServer) is already installed.
The following images are present on this machine:
    ContainerImage (Name = 'NanoServer') [Publisher = 'CN=Microsoft', Version = '10.0.10586.0']
    ContainerImage (Name = 'WindowsServerCore') [Publisher = 'CN=Microsoft', Version = '10.0.10586.0']

Docker is already installed.
Stopping Docker...
Starting Docker...
Tagging new base image (8572198a60f1)...
Base image is now tagged:
nanoserver          10.0.10586.0        8572198a60f1        5 months ago        0 B
nanoserver          latest              8572198a60f1        5 months ago        0 B
Script complete!

Now that I added the port mapping (and firewall rule), I should be able to reach the IIS through my host.

I tried both the approach via Powershell and Docker, and in both cases, the port binding to the host does not work.

PS C:> wget -uri https://aka.ms/tp4/Install-ContainerHost -OutFile C:\Install-ContainerHost.ps1

PS C:> powershell.exe -NoProfile C:\Install-ContainerHost.ps1 

Querying status of Windows feature: Containers...
Feature Containers is already enabled.
Waiting for Hyper-V Management...
Networking is already configured.  Confirming configuration...
Getting Container OS image (NanoServer) version 10.0.10586.0 from OneGet (this may take a few minutes)...
Container base image install complete.  Querying container images...
OS image (NanoServer) is already installed.
The following images are present on this machine:
    ContainerImage (Name = 'NanoServer') [Publisher = 'CN=Microsoft', Version = '10.0.10586.0']
    ContainerImage (Name = 'WindowsServerCore') [Publisher = 'CN=Microsoft', Version = '10.0.10586.0']

Docker is already installed.
Stopping Docker...
Starting Docker...
Tagging new base image (8572198a60f1)...
Base image is now tagged:
nanoserver          10.0.10586.0        8572198a60f1        5 months ago        0 B
nanoserver          latest              8572198a60f1        5 months ago        0 B
Script complete!

Now that I added the port mapping (and firewall rule), I should be able to reach the IIS through my host. (Just to be sure, I disabled the firewall on the host entirely.)

deleted 5370 characters in body
Source Link

I am running a Windows containerContainer using Docker on a Windows host (Windows Server 2016 TP4).

Note that I am using Windows Server 2016 (not any prior Windows version), where Windows Containers can run natively without an intermediate VM (no docker machine there) using Docker.

I followed the instructions on https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/inplace_setup to setup the Windows container host (bare metal host, no Hyper-V, no VM).

Specifically, this powershell script provided by Microsoft was executed to setup the Windows 2016 container host https://aka.ms/tp4/Install-ContainerHost, where it seems that all prerequisites regarding networking seem to be done.

Inside the container runs an IIS web server on the internal port 80.

I want to bind it to the host port 8800 (Windows Server 2016 TP4).

I followed the instruction as per:

https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/manage_docker#create-iis-image-1-

and ran the The container like this:

docker run --name iisdemo -it -p 8800:80 windowsservercoreiis cmd

and had also added the firewall rules as pershall run an https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/manage_docker#configure-network for ports 80IIS webserver on port 80 internally and 8800 beforehand. But I also turned off the Windows Firewall on the host entirely for testing purposes, justwant to be sure it's not conflicting.

As you can see from above docker callbind port 80 to the host, so I just made a slight change to the example given on the documentation page and changedcan reach it via the bound host port from 80 to 8800, so instead of -p 80:80 I run -p 8800:80IP/URL.

When I run "ipconfig"followed the instructions from Microsoft on both host and container, I get:

I am either having a misunderstanding what the host is or something does not work right.

The documentation says:

When the container has been created, open a browser, and browse to the IP address of the container host. Because port 80 (in my case it's 8800) of the host has been mapped to port 80 of the container, the IIS splash screen should be displayed.

Unfortunately, this does not work.

I can reach the IIS via the container IP: http://172.16.0.2:80 but not via the host IP address http://172.16.0.1:8800 or http://10.10.0.79:8800.

(I also tried -p 80:80, and also that does not work; I cannot reach 172.16.0.1:80).

Running a docker port iisdemo returns nothing:

PS C:\Windows\system32> docker port iisdemo
PS C:\Windows\system32>

and also docker ps does not show anything under "ports".

docker inspect iisdemo shows me:

    "PortBindings": {
        "80/tcp": [
            {
                "HostIp": "",
                "HostPort": "8800"
            }
        ]
    },
    ...
    "ExposedPorts": {
        "80/tcp": {}
    },

From my understanding, since I run docker "natively" from a Windows server with a Windows container, there is no intermediate VM (no docker machine) in between, so the "host" is the actual Windows Server that I run docker on.

So my question is, why does the host port binding not work? Why can I not reach the host as per Microsoft documentation? I tried both the approach via Powershell and Docker, but in both cases, the port binding to the host does not work.

What I also find confusing is that when I run netstat on both the host and the containerFor now, I get the same results! netstat onjust demonstrate the host does not show portsteps that I did with Powershell 8800, but(but it does show port 80, which should imho only appear when running netstat innot work with the container.Docker approach either):

netstat on Host:Deploying container host to existing system (Windows Server 2016 TP4)

PS C:\>netstat> wget -aburi |https://aka.ms/tp4/Install-ContainerHost findstr-OutFile "C:80"\Install-ContainerHost.ps1

PS C:> TCPpowershell.exe -NoProfile C:\Install-ContainerHost.ps1
Querying status of Windows feature: Containers...
Feature Containers is already enabled.
Waiting for Hyper-V Management...
Networking is already configured.  Confirming configuration...
Getting Container OS image (NanoServer) version 10.0.10586.0 from OneGet (this may take a few minutes)...
Container base image install complete.  Querying container images...
OS image (NanoServer) is already installed.
The following images are present on this machine:
    ContainerImage (Name = 'NanoServer') [Publisher = 'CN=Microsoft', Version = '10.0.10586.0']
    ContainerImage (Name = 'WindowsServerCore') [Publisher = 'CN=Microsoft', Version = '10.0:80.10586.0']

Docker is already installed.
Stopping Docker...
Starting Docker...
Tagging new base image (8572198a60f1)...
Base image is now test2016tagged:
nanoserver          10.0.10586.0        8572198a60f1      LISTENING  5 months ago        0 B
C:\>netstatnanoserver -ab | findstr ":8800"      latest              8572198a60f1        5 months ago        0 B
C:\>Script complete!

netstatPreparing image and container that runs IIS (based on Container:WindowsServerCore image)

C:\>netstat -ab | findstr ":80"
  TCP    0.0.0.0:80             test2016:0             LISTENING
  TCP    [::]:80                test2016:0             LISTENING
C:\>netstat -ab | findstr ":8800"
C:\>

And when I stop the container, the port 80 does not show anymore when I run netstat on the host. Why? It seems as if the network interfaces of host and container are the same.

I also read the documentation about NAT networking mode, although I must say, I am not a network expert. https://msdn.microsoft.com/en-us/virtualization/windowscontainers/management/container_networking#port-mapping

I am not sure though whether this is relevant or not regarding the "Getting started: IIS demo", since it's not mentioned there or linked to at all. (I did not run any configuration commands mentioned there.) From my understanding, it should only be relevant for port forwarding when requesting from the host from an external IP address.

FYI - this is what I get when I run some Powershell commands about the virtual switch information on my host:

PS C:> Get-VMSwitch

Name           SwitchType NetAdapterInterfaceDescription
----           ---------- ------------------------------
Virtual Switch NAT

PS C:> Get-NetNatStaticMapping

StaticMappingID               : 16
NatName                       : ContainerNAT
Protocol                      : TCP
RemoteExternalIPAddressPrefix : 0.0.0.0/0
ExternalIPAddress             : 0.0.0.0
ExternalPort                  : 80
InternalIPAddress             : 172.16.0.2
InternalPort                  : 80
InternalRoutingDomainId       : {00000000-0000-0000-0000-000000000000}
Active                        : True

and this is what I get withThese are the exact steps described in the Microsoft documentation at ipconfighttps://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/manage_powershell. I create a container from WindowsServerCore, install IIS on hostit, and container:

ipconfig (Container):make a new image out of it, which I can then later reuse.

PS C:\Windows\system32>> ipconfigGet-ContainerImage

WindowsName IP Configuration
            Publisher    Version      IsOSImage
Ethernet---- adapter vEthernet (Virtual Switch          -897f61a2cf88f8403d2e1bc946ef76710ac2540882b31b030445781fcf5eca25--------    -------      ---------
NanoServer        CN=Microsoft 10.0).10586.0 True
WindowsServerCore CN=Microsoft 10.0.10586.0 True


PS C:\> New-Container -Name TP4Demo -ContainerImageName WindowsServerCore -SwitchName "Virtual Switch"

Name   Connection State Uptime   ParentImageName
-specific--- DNS Suffix  .----- ------   ---------------
TP4Demo Off   00:00:00 WindowsServerCore


PS C:\> Get-Container

Name Link   State Uptime   ParentImageName
-local--- IPv6 Address . .----- .------ . . :---------------
TP4Demo fe80Off   00:00:94400 WindowsServerCore


PS C:73e2\> Start-Container -Name TP4Demo

PS C:2d58\> Enter-PSSession -ContainerName TP4Demo -RunAsAdministrator
[TP4Demo]:7c33%26 PS C:\Windows\system32> Install-WindowsFeature web-server

Success Restart Needed IPv4Exit Address.Code . . . . . .Feature .Result
------- .-------------- .--------- . : 172   --------------
True    No             Success        {Common HTTP Features, Default Document, D.16.0.2 


[TP4Demo]: PS C:\Windows\system32> Subnetexit
PS MaskC:\> .Stop-Container .-Name .TP4Demo

PS .C:\> .New-ContainerImage .-ContainerName .TP4Demo .-Name .WindowsServerCoreIIS .-Publisher .Demo :-Version 255.240.01.0 

Name   Default Gateway . . . . . . . . . : 172  Publisher Version IsOSImage
----                 --------- ------- ---------
WindowsServerCoreIIS CN=Demo   1.160.0.10 False


PS C:\> Remove-Container -Name TP4Demo -Force

ipconfig (Host): Now I have an IIS container ready that I bind to the "Virtual Switch".

PS C:\Windows\system32> ipconfig

Windows IP Configuration


Ethernet adapter Ethernet0:

  \> ConnectionNew-specific DNS Suffix  . :
  Container Link-local IPv6 Address .Name .IIS .-ContainerImageName .WindowsServerCoreIIS .-SwitchName :"Virtual fe80::19a9:f8bf:6e6d:5544%4Switch"
   IPv4 Address. . . . . . . . . . . : 10.10.0.79
 Name State SubnetUptime Mask . .ParentImageName
---- .----- .------ . . .---------------
IIS . .Off . . 00:00:00 255.255.254.0WindowsServerCoreIIS
   Default Gateway

PS .C:\> .Start-Container .-Name .IIS

PS .C:\> .Invoke-Command .-ContainerName .IIS .{ipconfig}

Windows :IP 10.10.0.1Configuration

Ethernet adapter vEthernet (Virtual Switch-30179F35-A9BD-4231-B264-BDD2994BD956-0):

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::cc1724f4:6b74c726:4fabed9b:ecce%3e603%28
   IPv4 Address. . . . . . . . . . . : 172.16.0.12
   Subnet Mask . . . . . . . . . . . : 255.240.0.0
   Default Gateway . . . . . . . . . :

Tunnel adapter isatap.{0DADB974-F583-4B51-B4B0-C7526A8BABAD}:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . :

Tunnel adapter isatap.{0D2767F2-FF2B-4D79-B338-94722C2CF8F9}:

   Media State . . . . . . . . . 172. 16. : Media disconnected
   Connection-specific DNS Suffix  0. :1

For testing purposes, I just installed an Apache httpd server on the Windows 2016 host and let it run on port 80, in order to blockAdding port 80 there.

Then I runmapping and firewall rule:

dockerPS runC:\> if (!(Get-NetNatStaticMapping | where {$_.ExternalPort -nameeq iisdemo80})) {Add-itNetNatStaticMapping -pNatName "ContainerNat" -Protocol TCP -ExternalIPAddress 0.0.0.0 -InternalIPAddress 172.16.0.2 -InternalPort 80 -ExternalPort 80}

PS C:\> if (!(Get-NetFirewallRule | where {$_.Name -eq "TCP80"})) {New-NetFirewallRule -Name "TCP80" -DisplayName "HTTP on TCP/80" -Protocol tcp -LocalPort 80 windowsservercoreiis-Action cmdAllow -Enabled True}

to see if it conflicts (which I expected) due to the port 80 already being in use, but it does not!

@harrymc pointed me to a ticket on Docker's github, where I just added a comment: https://github.com/docker/docker/issues/15740#issuecomment-202094318 and a new github ticket: https://github.com/docker/docker/issues/21558

======= UPDATE (Using powershell instead of Docker) =======

I tried a different approach, using Powershell instead of Docker to manage the Windows Container.

I followed the exact steps as mentioned on https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/manage_powershell#create-iis-container-1- including the networking configuration.

When I run the container, I also can only access the IIS default page via the container IP 172.16.0.2:80, but not via the host IP 172.16.0.1:80 or 10.10.0.79:80.

Here is some information I checked via Powershell about my current host environment:

PS C:> Get-ContainerHost

Name     ContainerImageRepositoryLocation                              
----     --------------------------------                              
TEST2016 C:\ProgramData\Microsoft\Windows\Hyper-V\Container Image Store


PS C:> Get-VMSwitch

Name           SwitchType NetAdapterInterfaceDescription
----           ---------- ------------------------------
Virtual Switch NAT                                      


PS C:> Get-NetNatStaticMapping

StaticMappingID               : 17
NatName                       : ContainerNat
Protocol                      : TCP
RemoteExternalIPAddressPrefix : 0.0.0.0/0
ExternalIPAddress             : 0.0.0.0
ExternalPort                  : 80
InternalIPAddress             : 172.16.0.2
InternalPort                  : 80
InternalRoutingDomainId       : {00000000-0000-0000-0000-000000000000}
Active                        : True

PS C:\> Get-NetFirewallRule | where {$_.Name -eq "TCP80"}

Name                  : TCP80
DisplayName           : HTTP on TCP/80
Description           :
DisplayGroup          :
Group                 :
Enabled               : True
Profile               : Any
Platform              : {}
Direction             : Inbound
Action                : Allow
EdgeTraversalPolicy   : Block
LooseSourceMapping    : False
LocalOnlyMapping      : False
Owner                 :
PrimaryStatus         : OK
Status                : The rule was parsed successfully from the store. (65536)
EnforcementStatus     : NotApplicable
PolicyStoreSource     : PersistentStore
PolicyStoreSourceType : Local

Now that I added the port mapping (and firewall rule), I should be able to reach the IIS through my host.

ipconfig on containerBut the host port binding does not work. I cannot reach the IIS through the host IPs and bound port via http://localhost:80/ nor http://172.16.0.1:80/ nor http://10.10.0.79:80/

[IIS]: PS C:\Windows\system32>\> ipconfig
wget http://10.10.0.79:80/
Windowswget IP: Configuration
Unable to connect to the remote server
EthernetAt adapterline:1 vEthernetchar:1
+ (Virtualwget Switch-05D94B20-1CA5-4198-A3AA-2CA7001925D0-http://10.10.0).79:80/
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
   Connection-specific DNS+ SuffixCategoryInfo  . :
   Link-local IPv6 Address . .: .InvalidOperation: (System. Net. HttpWebRequest:HttpWebRequest) fe80::d89d:bcca:e4fa:35db%26[Invoke-WebRequest], WebException
   IPv4 Address.+ .FullyQualifiedErrorId .: WebCmdletWebResponseException,Microsoft. PowerShell. Commands.InvokeWebRequestCommand

PS .C:\> .wget http://172. 16. 0.1:80/
wget : Unable to connect to the remote server
At line:1 char:1
+ wget http://172.16.0.21:80/
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
  Subnet Mask .+ .CategoryInfo . . . . . . . . . : 255.240.0.0
   Default GatewayInvalidOperation: (System. Net.HttpWebRequest:HttpWebRequest) .[Invoke-WebRequest], .WebException
 . . . .+ .FullyQualifiedErrorId : 172WebCmdletWebResponseException,Microsoft.16PowerShell.0Commands.1InvokeWebRequestCommand

ipconfig on host:

Ethernet adapter Ethernet0:

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::19a9:f8bf:6e6d:5544%4
   IPv4 Address. . . . . . . . . . . : 10.10.0.79
   Subnet Mask . . . . . . . . . . . : 255.255.254.0
   Default Gateway . . . . . . . . . : 10.10.0.1

Ethernet adapter vEthernet (Virtual Switch):

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::cc17:6b74:4fab:ecce%3
   IPv4 Address. . . . . . . . . . . : 172.16.0.1
   Subnet Mask . . . . . . . . . . . : 255.240.0.0
   Default Gateway . . . . . . . . . :

Tunnel adapter isatap.{0DADB974-F583-4B51-B4B0-C7526A8BABAD}:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . :

Tunnel adapter isatap.{0D2767F2-FF2B-4D79-B338-94722C2CF8F9}:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . :

I can only reach the IIS default page via the container IP (http://172.16.0.2:80).

I am running a Windows container using Docker on a Windows host (Windows Server 2016 TP4).

Note that I am using Windows Server 2016 (not any prior Windows version), where Windows Containers can run natively without an intermediate VM (no docker machine there) using Docker.

I followed the instructions on https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/inplace_setup to setup the Windows container host (bare metal host, no Hyper-V, no VM).

Specifically, this powershell script provided by Microsoft was executed to setup the Windows 2016 container host https://aka.ms/tp4/Install-ContainerHost, where it seems that all prerequisites regarding networking seem to be done.

Inside the container runs an IIS web server on the internal port 80.

I want to bind it to the host port 8800.

I followed the instruction as per:

https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/manage_docker#create-iis-image-1-

and ran the container like this:

docker run --name iisdemo -it -p 8800:80 windowsservercoreiis cmd

and had also added the firewall rules as per https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/manage_docker#configure-network for ports 80 and 8800 beforehand. But I also turned off the Windows Firewall on the host entirely for testing purposes, just to be sure it's not conflicting.

As you can see from above docker call, I just made a slight change to the example given on the documentation page and changed the bound host port from 80 to 8800, so instead of -p 80:80 I run -p 8800:80.

When I run "ipconfig" on both host and container, I get:

  • Host IP: 172.16.0.1 (vEthernet / Virtual Switch) / 10.10.0.79 (Ethernet0)
  • Container IP: 172.16.0.2 (vEthernet / Virtual Switch)

I am either having a misunderstanding what the host is or something does not work right.

The documentation says:

When the container has been created, open a browser, and browse to the IP address of the container host. Because port 80 (in my case it's 8800) of the host has been mapped to port 80 of the container, the IIS splash screen should be displayed.

Unfortunately, this does not work.

I can reach the IIS via the container IP: http://172.16.0.2:80 but not via the host IP address http://172.16.0.1:8800 or http://10.10.0.79:8800.

(I also tried -p 80:80, and also that does not work; I cannot reach 172.16.0.1:80).

Running a docker port iisdemo returns nothing:

PS C:\Windows\system32> docker port iisdemo
PS C:\Windows\system32>

and also docker ps does not show anything under "ports".

docker inspect iisdemo shows me:

    "PortBindings": {
        "80/tcp": [
            {
                "HostIp": "",
                "HostPort": "8800"
            }
        ]
    },
    ...
    "ExposedPorts": {
        "80/tcp": {}
    },

From my understanding, since I run docker "natively" from a Windows server with a Windows container, there is no intermediate VM (no docker machine) in between, so the "host" is the actual Windows Server that I run docker on.

So my question is, why does the host port binding not work? Why can I not reach the host as per Microsoft documentation?

What I also find confusing is that when I run netstat on both the host and the container, I get the same results! netstat on the host does not show port 8800, but it does show port 80, which should imho only appear when running netstat in the container.

netstat on Host:

C:\>netstat -ab | findstr ":80"
  TCP    0.0.0.0:80             test2016:0             LISTENING
C:\>netstat -ab | findstr ":8800"
C:\>

netstat on Container:

C:\>netstat -ab | findstr ":80"
  TCP    0.0.0.0:80             test2016:0             LISTENING
  TCP    [::]:80                test2016:0             LISTENING
C:\>netstat -ab | findstr ":8800"
C:\>

And when I stop the container, the port 80 does not show anymore when I run netstat on the host. Why? It seems as if the network interfaces of host and container are the same.

I also read the documentation about NAT networking mode, although I must say, I am not a network expert. https://msdn.microsoft.com/en-us/virtualization/windowscontainers/management/container_networking#port-mapping

I am not sure though whether this is relevant or not regarding the "Getting started: IIS demo", since it's not mentioned there or linked to at all. (I did not run any configuration commands mentioned there.) From my understanding, it should only be relevant for port forwarding when requesting from the host from an external IP address.

FYI - this is what I get when I run some Powershell commands about the virtual switch information on my host:

PS C:> Get-VMSwitch

Name           SwitchType NetAdapterInterfaceDescription
----           ---------- ------------------------------
Virtual Switch NAT

PS C:> Get-NetNatStaticMapping

StaticMappingID               : 16
NatName                       : ContainerNAT
Protocol                      : TCP
RemoteExternalIPAddressPrefix : 0.0.0.0/0
ExternalIPAddress             : 0.0.0.0
ExternalPort                  : 80
InternalIPAddress             : 172.16.0.2
InternalPort                  : 80
InternalRoutingDomainId       : {00000000-0000-0000-0000-000000000000}
Active                        : True

and this is what I get with ipconfig on host and container:

ipconfig (Container):

PS C:\Windows\system32> ipconfig

Windows IP Configuration

Ethernet adapter vEthernet (Virtual Switch-897f61a2cf88f8403d2e1bc946ef76710ac2540882b31b030445781fcf5eca25-0):

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::944:73e2:2d58:7c33%26
   IPv4 Address. . . . . . . . . . . : 172.16.0.2
   Subnet Mask . . . . . . . . . . . : 255.240.0.0
   Default Gateway . . . . . . . . . : 172.16.0.1

ipconfig (Host):

PS C:\Windows\system32> ipconfig

Windows IP Configuration


Ethernet adapter Ethernet0:

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::19a9:f8bf:6e6d:5544%4
   IPv4 Address. . . . . . . . . . . : 10.10.0.79
   Subnet Mask . . . . . . . . . . . : 255.255.254.0
   Default Gateway . . . . . . . . . : 10.10.0.1

Ethernet adapter vEthernet (Virtual Switch):

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::cc17:6b74:4fab:ecce%3
   IPv4 Address. . . . . . . . . . . : 172.16.0.1
   Subnet Mask . . . . . . . . . . . : 255.240.0.0
   Default Gateway . . . . . . . . . :

Tunnel adapter isatap.{0DADB974-F583-4B51-B4B0-C7526A8BABAD}:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . :

Tunnel adapter isatap.{0D2767F2-FF2B-4D79-B338-94722C2CF8F9}:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . :

For testing purposes, I just installed an Apache httpd server on the Windows 2016 host and let it run on port 80, in order to block port 80 there.

Then I run

docker run --name iisdemo -it -p 80:80 windowsservercoreiis cmd

to see if it conflicts (which I expected) due to the port 80 already being in use, but it does not!

@harrymc pointed me to a ticket on Docker's github, where I just added a comment: https://github.com/docker/docker/issues/15740#issuecomment-202094318 and a new github ticket: https://github.com/docker/docker/issues/21558

======= UPDATE (Using powershell instead of Docker) =======

I tried a different approach, using Powershell instead of Docker to manage the Windows Container.

I followed the exact steps as mentioned on https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/manage_powershell#create-iis-container-1- including the networking configuration.

When I run the container, I also can only access the IIS default page via the container IP 172.16.0.2:80, but not via the host IP 172.16.0.1:80 or 10.10.0.79:80.

Here is some information I checked via Powershell about my current host environment:

PS C:> Get-ContainerHost

Name     ContainerImageRepositoryLocation                              
----     --------------------------------                              
TEST2016 C:\ProgramData\Microsoft\Windows\Hyper-V\Container Image Store


PS C:> Get-VMSwitch

Name           SwitchType NetAdapterInterfaceDescription
----           ---------- ------------------------------
Virtual Switch NAT                                      


PS C:> Get-NetNatStaticMapping

StaticMappingID               : 17
NatName                       : ContainerNat
Protocol                      : TCP
RemoteExternalIPAddressPrefix : 0.0.0.0/0
ExternalIPAddress             : 0.0.0.0
ExternalPort                  : 80
InternalIPAddress             : 172.16.0.2
InternalPort                  : 80
InternalRoutingDomainId       : {00000000-0000-0000-0000-000000000000}
Active                        : True

PS C:\> Get-NetFirewallRule | where {$_.Name -eq "TCP80"}

Name                  : TCP80
DisplayName           : HTTP on TCP/80
Description           :
DisplayGroup          :
Group                 :
Enabled               : True
Profile               : Any
Platform              : {}
Direction             : Inbound
Action                : Allow
EdgeTraversalPolicy   : Block
LooseSourceMapping    : False
LocalOnlyMapping      : False
Owner                 :
PrimaryStatus         : OK
Status                : The rule was parsed successfully from the store. (65536)
EnforcementStatus     : NotApplicable
PolicyStoreSource     : PersistentStore
PolicyStoreSourceType : Local

ipconfig on container:

[IIS]: PS C:\Windows\system32> ipconfig

Windows IP Configuration

Ethernet adapter vEthernet (Virtual Switch-05D94B20-1CA5-4198-A3AA-2CA7001925D0-0):

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::d89d:bcca:e4fa:35db%26
   IPv4 Address. . . . . . . . . . . : 172.16.0.2
   Subnet Mask . . . . . . . . . . . : 255.240.0.0
   Default Gateway . . . . . . . . . : 172.16.0.1

ipconfig on host:

Ethernet adapter Ethernet0:

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::19a9:f8bf:6e6d:5544%4
   IPv4 Address. . . . . . . . . . . : 10.10.0.79
   Subnet Mask . . . . . . . . . . . : 255.255.254.0
   Default Gateway . . . . . . . . . : 10.10.0.1

Ethernet adapter vEthernet (Virtual Switch):

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::cc17:6b74:4fab:ecce%3
   IPv4 Address. . . . . . . . . . . : 172.16.0.1
   Subnet Mask . . . . . . . . . . . : 255.240.0.0
   Default Gateway . . . . . . . . . :

Tunnel adapter isatap.{0DADB974-F583-4B51-B4B0-C7526A8BABAD}:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . :

Tunnel adapter isatap.{0D2767F2-FF2B-4D79-B338-94722C2CF8F9}:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . :

I am running a Windows Container on a Windows host (Windows Server 2016 TP4).

The container shall run an IIS webserver on port 80 internally and I also want to bind port 80 to the host, so I can reach it via the host IP/URL.

I followed the instructions from Microsoft on

I tried both the approach via Powershell and Docker, but in both cases, the port binding to the host does not work.

For now, I just demonstrate the steps that I did with Powershell (but it does not work with the Docker approach either):

Deploying container host to existing system (Windows Server 2016 TP4)

PS C:> wget -uri https://aka.ms/tp4/Install-ContainerHost -OutFile C:\Install-ContainerHost.ps1

PS C:> powershell.exe -NoProfile C:\Install-ContainerHost.ps1
Querying status of Windows feature: Containers...
Feature Containers is already enabled.
Waiting for Hyper-V Management...
Networking is already configured.  Confirming configuration...
Getting Container OS image (NanoServer) version 10.0.10586.0 from OneGet (this may take a few minutes)...
Container base image install complete.  Querying container images...
OS image (NanoServer) is already installed.
The following images are present on this machine:
    ContainerImage (Name = 'NanoServer') [Publisher = 'CN=Microsoft', Version = '10.0.10586.0']
    ContainerImage (Name = 'WindowsServerCore') [Publisher = 'CN=Microsoft', Version = '10.0.10586.0']

Docker is already installed.
Stopping Docker...
Starting Docker...
Tagging new base image (8572198a60f1)...
Base image is now tagged:
nanoserver          10.0.10586.0        8572198a60f1        5 months ago        0 B
nanoserver          latest              8572198a60f1        5 months ago        0 B
Script complete!

Preparing image and container that runs IIS (based on WindowsServerCore image)

These are the exact steps described in the Microsoft documentation at https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/manage_powershell. I create a container from WindowsServerCore, install IIS on it, and make a new image out of it, which I can then later reuse.

PS C:> Get-ContainerImage

Name              Publisher    Version      IsOSImage
----              ---------    -------      ---------
NanoServer        CN=Microsoft 10.0.10586.0 True
WindowsServerCore CN=Microsoft 10.0.10586.0 True


PS C:\> New-Container -Name TP4Demo -ContainerImageName WindowsServerCore -SwitchName "Virtual Switch"

Name    State Uptime   ParentImageName
----    ----- ------   ---------------
TP4Demo Off   00:00:00 WindowsServerCore


PS C:\> Get-Container

Name    State Uptime   ParentImageName
----    ----- ------   ---------------
TP4Demo Off   00:00:00 WindowsServerCore


PS C:\> Start-Container -Name TP4Demo

PS C:\> Enter-PSSession -ContainerName TP4Demo -RunAsAdministrator
[TP4Demo]: PS C:\Windows\system32> Install-WindowsFeature web-server

Success Restart Needed Exit Code      Feature Result
------- -------------- ---------      --------------
True    No             Success        {Common HTTP Features, Default Document, D... 


[TP4Demo]: PS C:\Windows\system32> exit
PS C:\> Stop-Container -Name TP4Demo

PS C:\> New-ContainerImage -ContainerName TP4Demo -Name WindowsServerCoreIIS -Publisher Demo -Version 1.0 

Name                 Publisher Version IsOSImage
----                 --------- ------- ---------
WindowsServerCoreIIS CN=Demo   1.0.0.0 False


PS C:\> Remove-Container -Name TP4Demo -Force

Now I have an IIS container ready that I bind to the "Virtual Switch".

PS C:\> New-Container -Name IIS -ContainerImageName WindowsServerCoreIIS -SwitchName "Virtual Switch"

Name State Uptime   ParentImageName
---- ----- ------   ---------------
IIS  Off   00:00:00 WindowsServerCoreIIS


PS C:\> Start-Container -Name IIS

PS C:\> Invoke-Command -ContainerName IIS {ipconfig}

Windows IP Configuration

Ethernet adapter vEthernet (Virtual Switch-30179F35-A9BD-4231-B264-BDD2994BD956-0):

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::24f4:c726:ed9b:e603%28
   IPv4 Address. . . . . . . . . . . : 172.16.0.2
   Subnet Mask . . . . . . . . . . . : 255.240.0.0
   Default Gateway . . . . . . . . . : 172.16.0.1

Adding port mapping and firewall rule:

PS C:\> if (!(Get-NetNatStaticMapping | where {$_.ExternalPort -eq 80})) {Add-NetNatStaticMapping -NatName "ContainerNat" -Protocol TCP -ExternalIPAddress 0.0.0.0 -InternalIPAddress 172.16.0.2 -InternalPort 80 -ExternalPort 80}

PS C:\> if (!(Get-NetFirewallRule | where {$_.Name -eq "TCP80"})) {New-NetFirewallRule -Name "TCP80" -DisplayName "HTTP on TCP/80" -Protocol tcp -LocalPort 80 -Action Allow -Enabled True}

Now that I added the port mapping (and firewall rule), I should be able to reach the IIS through my host.

But the host port binding does not work. I cannot reach the IIS through the host IPs and bound port via http://localhost:80/ nor http://172.16.0.1:80/ nor http://10.10.0.79:80/

PS C:\> wget http://10.10.0.79:80/
wget : Unable to connect to the remote server
At line:1 char:1
+ wget http://10.10.0.79:80/
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

PS C:\> wget http://172.16.0.1:80/
wget : Unable to connect to the remote server
At line:1 char:1
+ wget http://172.16.0.1:80/
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

I can only reach the IIS default page via the container IP (http://172.16.0.2:80).

added 108 characters in body
Source Link
Loading
added 17 characters in body
Source Link
Loading
added 70 characters in body
Source Link
Loading
edited title
Link
Loading
added 3837 characters in body; edited tags; edited title
Source Link
Loading
added 20 characters in body
Source Link
Loading
added 272 characters in body
Source Link
Loading
added 543 characters in body
Source Link
Loading
added 38 characters in body
Source Link
Loading
Notice added Draw attention by Mathias Conradt
Bounty Started worth 50 reputation by Mathias Conradt
added 39 characters in body
Source Link
Loading
added 2872 characters in body
Source Link
Loading
added 5 characters in body
Source Link
Loading
added 40 characters in body
Source Link
Loading
added 392 characters in body
Source Link
Loading
added 124 characters in body
Source Link
Loading
added 22 characters in body
Source Link
Loading
deleted 1085 characters in body
Source Link
Loading
added 11 characters in body
Source Link
Loading