Daniel's blog

WIFIonICE not working on Linux with Docker

A few weeks back, I was travelling on an ICE train and tried to connect to the onboard WiFi, called “WIFIonICE”. The connection itself worked fine, but I could not reach the captive portal at all. No internet, no way to authenticate. Turns out Docker was to blame here.

Why It Breaks

The ICE onboard WiFi uses the IP address range 172.18.0.0/16. Docker, by default, assigns IP ranges from the 172.16.0.0/12 block to bridge networks in ascending order. The first 172.16.0.0/16 block is skipped since it is commonly used for local networks. The default bridge network gets the next one:

 1❯ docker network inspect bridge
 2[
 3  {
 4    ...
 5    "IPAM": {
 6      "Config": [
 7        {
 8          "Subnet": "172.17.0.0/16",
 9          "Gateway": "172.17.0.1"
10        }
11      ]
12    }
13  }
14]

The first user-created network gets the next available block - 172.18.0.0/16:

 1❯ docker network inspect demo
 2[
 3  {
 4    ...
 5    "IPAM": {
 6      "Config": [
 7        {
 8          "Subnet": "172.18.0.0/16",
 9          "Gateway": "172.18.0.1"
10        }
11      ]
12    }
13  }
14]

If you connect to the ICE WiFi with a Docker network already using that same range, you end up with two interfaces both claiming 172.18.0.0/16.

All packets meant for the WiFi gateway get routed into the Docker network instead and get lost. The captive portal is unreachable.

Workaround

If you do not need Docker during your train ride, the simplest option is to stop it entirely:

1sudo systemctl stop docker docker.socket

Re-enable it afterwards with sudo systemctl start docker docker.socket.

Permanent Fix

For a proper fix, configure the IP ranges Docker uses in /etc/docker/daemon.json. A good choice is a subset of the 10.0.0.0/8 private range:

1{
2  "default-address-pools": [
3    {
4      "base": "172.19.0.0/16",
5      "size": 24
6    }
7  ]
8}

This stays within the 172.16.0.0/12 range Docker already uses by convention, just in a block that does not overlap with the ICE WiFi. With a /24 prefix per network, you get 256 networks with 256 addresses each — more than enough for local development.

What About IPv6?

Since Docker engine version 27, IPv6 support is no longer experimental. You can create IPv6-only networks:

1docker network create --ipv6 --ipv4=false ipv6only

Or via Compose:

1networks:
2  ipv6only:
3    enable_ipv4: false
4    enable_ipv6: true

The unique local address space of IPv6 is large enough that collisions become practically impossible. The catch is that IPv6-only networks still have some limitations — forwarding an IPv4 host port to an IPv6-only container is not supported, and you cannot set IPv6-only as the default for new networks. So while it is the cleaner long-term answer, it is not quite there for everyday use yet.

Sources

Docker daemon configuration - https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file

Docker bridge networks - https://docs.docker.com/network/bridge/

← Previous Post

|

Next Post →