Skip to content

fix: port(-p flag) connection reset by peer#1197

Open
manojmahapatra wants to merge 1 commit intoapple:mainfrom
manojmahapatra:fix/ipv6-issue
Open

fix: port(-p flag) connection reset by peer#1197
manojmahapatra wants to merge 1 commit intoapple:mainfrom
manojmahapatra:fix/ipv6-issue

Conversation

@manojmahapatra
Copy link
Contributor

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

Fixes #1180

On macOS, localhost resolves to IPv6 (::1) first. Current port forwarder only bound IPv4 by default, so curl http://localhost could fail while 127.0.0.1 worked. This fix adds an IPv6 loopback listener alongside the existing IPv4 bind when publishing without an explicit host IP or when using IPv4 loopback.

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs

@jglogan
Copy link
Contributor

jglogan commented Feb 11, 2026

@manojmahapatra I'm not yet sure that implicitly starting port forwarders that the user didn't ask for is the answer. I'd want to check whether other applications do this, for one.

curl, at least, should not fail when ::1 fails to connect. I see that it immediately proceeds from the AAAA answer to the A answer:

% container run -d --rm --name web -p 8080:8000 python:slim python3 -m http.server --bind 0.0.0.0 8000 && while [ 1 ] ; do curl -v http://localhost:8080 ; sleep 1; done
Warning! Running debug build. Performance may be degraded.
web
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8080...
* connect to ::1 port 8080 from ::1 port 50013 failed: Connection refused
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.7.1
> Accept: */*
> 
* Request completely sent off
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: SimpleHTTP/0.6 Python/3.14.3
< Date: Wed, 11 Feb 2026 20:11:14 GMT
< Content-type: text/html; charset=utf-8
< Content-Length: 913
< 
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<style type="text/css">
:root {
color-scheme: light dark;
}
</style>
<title>Directory listing for /</title>
</head>
<body>
<h1>Directory listing for /</h1>
<hr>
<ul>
<li><a href="bin/">bin@</a></li>
<li><a href="boot/">boot/</a></li>
<li><a href="dev/">dev/</a></li>
<li><a href="etc/">etc/</a></li>
<li><a href="home/">home/</a></li>
<li><a href="lib/">lib@</a></li>
<li><a href="lost%2Bfound/">lost+found/</a></li>
<li><a href="media/">media/</a></li>
<li><a href="mnt/">mnt/</a></li>
<li><a href="opt/">opt/</a></li>
<li><a href="proc/">proc/</a></li>
<li><a href="root/">root/</a></li>
<li><a href="run/">run/</a></li>
<li><a href="sbin/">sbin@</a></li>
<li><a href="srv/">srv/</a></li>
<li><a href="sys/">sys/</a></li>
<li><a href="tmp/">tmp/</a></li>
<li><a href="usr/">usr/</a></li>
<li><a href="var/">var/</a></li>
</ul>
<hr>
</body>
</html>
* Closing connection
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8080...
* connect to ::1 port 8080 from ::1 port 50016 failed: Connection refused
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.7.1
> Accept: */*
> 
* Request completely sent off
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
...

@manojmahapatra
Copy link
Contributor Author

manojmahapatra commented Feb 12, 2026

Hi @jglogan, re

I'm not yet sure that implicitly starting port forwarders that the user didn't ask for is the answer.

I agree w/ the concern here. I initially thought #1180 was just the IPv6 localhost resolution problem, which is what this PR targets. After digging deeper, I don't think this PR fully addresses #1180.

The “connection reset by peer” looks more like a backend readiness race. I also saw failures on IPv4. And here is what I did to reproduce the issue;

  1. created a fresh worktree (to avoid local state) from main branch
    • git worktree add ../container-474906d 474906d
    • cd ../container-474906d
    • swift build
    • export CONTAINER_INSTALL_ROOT="$PWD"
    • bin/container system start --install-root "$PWD"
  2. mkdir -p /tmp/port-test, then use the dockerfile from [Bug]: port (-p flag) connection reset by peer #1180
  3. cd /tmp/port-test
  4. container build -t port-test .
  5. container run --rm --name port-test -p 5866:5866 port-test
  6. curl http://localhost:5866

This sometimes fails during the early startup window and then succeeds once the backend is ready. I don't think I've enough context on the backend readiness to address the issue completely. If you could add some pointers I will be happy to look into it.

Having said that, the current changes in the PR fixes only IPv6/localhost binding. Hope this helps.

@manojmahapatra
Copy link
Contributor Author

manojmahapatra commented Feb 12, 2026

I was also reading this;

Ports on the host's IPv6 addresses will map to the container's IPv4 address if no host IP is given in a port mapping, the bridge network is IPv4-only, and --userland-proxy=true (default).

https://docs.docker.com/engine/network/port-publishing/

So does it mean, with --userland-proxy=true (default), Docker can still accept IPv6 connections on the host and forward them to the container’s IPv4 address — effectively doing a v6 -> v4 proxy?

Also I realized in container, there is no IPv6 host -> IPv4 container bridging in the current design, which looks like intentional to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: port (-p flag) connection reset by peer

2 participants