Why Docker Containers Time Out on HTTPS: MTU Misconfiguration and How to Fix It
When running Jenkins inside a Docker container on a VM, HTTPS requests to accounts.google.com time out due to an MTU mismatch between the host and the container, which can be resolved by adjusting the MSS via iptables or setting a lower MTU for Docker interfaces.
Story Origin
We needed to set up Jenkins, a Java application, on a new environment. To avoid maintaining a Java runtime ourselves, we decided to run Jenkins inside Docker. After provisioning a VM, installing Docker, and launching the official Jenkins Docker image, the Jenkins UI reported an error.
The Jenkins log showed a java.net.SocketTimeoutException: Read timed out , but it was unclear which service caused the timeout.
Collecting Information
Using
tcpdumpduring Jenkins startup, we discovered that connections to a specific IP on port 443 were hanging, even though the IP was reachable via ping, indicating a problem above layer 3.
Further DNS capture revealed that the IP corresponded to accounts.google.com . Inside the container we could ping the domain and successfully
curl http://accounts.google.com, but
curl https://accounts.google.comalways timed out. Other HTTPS sites were reachable, albeit slowly.
On the VM host,
curl https://accounts.google.comworked fine, confirming that the host network was healthy.
Answer
Reviewing Docker’s networking model shows the packet path:
container eth0 → host veth → docker0 bridge → host eth0 → WAN. Since the host network works, the issue lies between the container and the host bridge.
Packet captures showed that after the TCP handshake, HTTP traffic flowed normally, but HTTPS traffic stalled. The packets returning from port 443 had a length of 0, suggesting they were dropped due to an oversized MTU.
Because the host’s MTU is 1450 while Docker defaults to 1500, the extra encapsulation added by the overlay network exceeds the MTU, causing fragmentation or loss of TLS packets.
Proof
The mismatch in MTU leads to incorrect TCP MSS negotiation. The host’s MTU is 1450, but Docker’s default is 1500. When the container assumes an MTU of 1500, packets larger than the allowed size are dropped, resulting in the observed HTTPS timeout.
Solution
Two practical fixes are available:
Use MSS clamping with
iptablesto force the TCP handshake MSS to a safe value (e.g., 1410):
<code>iptables -I FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1410</code>Specify a lower MTU for Docker’s default bridge when starting the daemon:
<code>dockerd --default-network-opt=bridge=com.docker.network.driver.mtu=1234</code>After applying either fix, HTTPS requests from the Docker container succeed.
Efficient Ops
This public account is maintained by Xiaotianguo and friends, regularly publishing widely-read original technical articles. We focus on operations transformation and accompany you throughout your operations career, growing together happily.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.