Use IPv6 (::) default for production#3847
Conversation
6a04515 to
acdb5ce
Compare
6f6fe36 to
a0ef3f8
Compare
|
@schneems I think you should make tests fixes in its own branch/PR, so we can merge that independent of this PR! |
d5e315a to
1493422
Compare
Done 💚 |
|
I'm not actually sure how large this change is. I had to adjust the tests to get it to pass for windows (switching from 127.0.0.1 to localhost) so it is a breaking change for some users, for sure, but I believe it's a small breaking change (if there is such a thing). To be on the safe side, this would be a minor at least (7.1 -> 7.2). If we were doing strict semver (we aren't) this would need to be (7.1 -> 8.0). |
Because it's a prod change, I'd prefer to mark this as a full breaking change. |
nateberkopec
left a comment
There was a problem hiding this comment.
- What do we do if binding to
::fails? Currently this raises and dies with non-zero exit. Should we do something else? - The Rails issue notes there are ipv6-only hosts b/c it can be disabled at the kernel level. That definitely warrants breaking change to me, do we have any idea how often this occurs?
For me this is kind of a no as-is. Breaks hard with not a lot of user benefit.
I've yet to find any sort of docker setup that reproduces that behavior. I believe it may exists, but given the difficulty to induce it makes me think the actual occurrence is small.
Without a system to test against it’s hard to say. In the scenario where IPv6 isn’t available I’m unclear if it still binds to IPv4 and behaves like 0.0.0.0 or if it fully fails. It might also be OS dependent. We could catch and retry with 0.0.0.0 as an option. I would ideally not want to do that unless the error was clear and we aren’t retrying for all socket binding failures. As a parallel thought: We could also allow setting tcp host via env var PUMA_TCP_HOST or just PUMA_HOST. Though it would only help people using something like the buildpack and not others who are running on a machine that doesn't have an IPv4 network. Maybe adding env var support for config makes it less risky as someone could put the old 0.0.0.0 in their dot files if it failed for them. |
|
Adding a datapoint: I changed the Heroku docs for recommended puma config to use IPv6 November 22 of 2024. People leave feedback on articles, and I've not had any issues, granted these people are also likely using Heroku for prod, but I also know these docs show up in general search, and people sometimes copy and use them on other infrastructure. It's not an overwhelming signal that no one has complained, but it is a signal. |
|
Tested how this change behaves in environments where IPv6 is partially or fully disabled:
The issue: Puma will log In this case table for
Suggestion: Perhaps checking for available IPv6 interfaces before deciding which address to bind to would help. For example: Using this check (or a similar one) would allow Puma to: Bind to 0.0.0.0 automatically if IPv6 is missing or disabled at the kernel level (partially or fully disabled), preventing startup crashes. Provide more accurate logging about which protocol is actually being used. |
IPv4 addresses like 0.0.0.0 are easy and familiar, but they're increasingly more expensive with providers such as AWS (https://aws.amazon.com/blogs/aws/new-aws-public-ipv4-address-charge-public-ip-insights/). IPv6 addresses are much more plentiful, and therefore cheaper (and represent the future). This update switches the default production address to IPv6 `::`. Here's the table of the URLs that each host supports: | Host | localhost:3000 | 127.0.0.1:3000 | \[::1\]:3000 | 0.0.0.0:3000 | \[::\]:3000 | Network Open | |:---:|:---:|:---:|:---:|:---:|:---:|:---:| | `localhost` | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ No | | `127.0.0.1` | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ No | | `::1` | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ No | | `0.0.0.0` | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ Yes | | `::` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ Yes | Generated with https://gist.github.com/schneems/0e3e5fb61b6e4128499af01c9cf7ac1c. Puma has no concept of a "development" default host, so we don't need to use `::1` instead of `127.0.0.1` or `localhost`. Also due to the behavior of `::1` not falling back to IPv4 the same way that `::` does, it seems a higher-cost, lower benefit update, so I'm not recomending it for other defaults such as Rails rails/rails#56470. Close #3812
dfa8dfb to
b2c901a
Compare
Changed my mind now that the next release is a major
28512ba to
3f2d92c
Compare
3f2d92c to
42c09a4
Compare
|
Codex speaking below. Puma uses
depending on platform/runtime configuration. A few concrete data points:
I also reproduced the behavior with Ruby sockets:
User impact
The new fallback in this PR (no non-loopback IPv6 interface => rewrite to This is manageable as a breaking-change note: if someone depends on IPv4 loopback checks, they should either use |
Strip the ::ffff: prefix from IPv4-mapped IPv6 addresses returned by dual-stack sockets so that REMOTE_ADDR and common_logger output show the original IPv4 address (e.g. 127.0.0.1 instead of ::ffff:127.0.0.1). This is a side-effect of puma#3847 which changed the default bind to :: on hosts with IPv6 interfaces.
Strip the ::ffff: prefix from IPv4-mapped IPv6 addresses returned by dual-stack sockets so that REMOTE_ADDR and common_logger output show the original IPv4 address (e.g. 127.0.0.1 instead of ::ffff:127.0.0.1). This is a side-effect of puma#3847 which changed the default bind to :: on hosts with IPv6 interfaces.
Strip the ::ffff: prefix from IPv4-mapped IPv6 addresses returned by dual-stack sockets so that REMOTE_ADDR and CommonLogger output show the original IPv4 address (e.g. 127.0.0.1 instead of ::ffff:127.0.0.1). This is a side-effect of puma#3847 which changed the default bind to :: on hosts with IPv6 interfaces.
* Fix IPv4-mapped IPv6 addresses in REMOTE_ADDR and request logs Strip the ::ffff: prefix from IPv4-mapped IPv6 addresses returned by dual-stack sockets so that REMOTE_ADDR and CommonLogger output show the original IPv4 address (e.g. 127.0.0.1 instead of ::ffff:127.0.0.1). This is a side-effect of #3847 which changed the default bind to :: on hosts with IPv6 interfaces. * Address review feedback on IPv4-mapped IPv6 fix --------- Co-authored-by: Nate Berkopec <[email protected]>
* Fix IPv4-mapped IPv6 addresses in REMOTE_ADDR and request logs Strip the ::ffff: prefix from IPv4-mapped IPv6 addresses returned by dual-stack sockets so that REMOTE_ADDR and CommonLogger output show the original IPv4 address (e.g. 127.0.0.1 instead of ::ffff:127.0.0.1). This is a side-effect of #3847 which changed the default bind to :: on hosts with IPv6 interfaces. * Address review feedback on IPv4-mapped IPv6 fix --------- Co-authored-by: Nate Berkopec <[email protected]> (cherry picked from commit 7406cc1)
* Fix IPv4-mapped IPv6 addresses in REMOTE_ADDR and request logs Strip the ::ffff: prefix from IPv4-mapped IPv6 addresses returned by dual-stack sockets so that REMOTE_ADDR and CommonLogger output show the original IPv4 address (e.g. 127.0.0.1 instead of ::ffff:127.0.0.1). This is a side-effect of #3847 which changed the default bind to :: on hosts with IPv6 interfaces. * Address review feedback on IPv4-mapped IPv6 fix --------- Co-authored-by: Nate Berkopec <[email protected]> (cherry picked from commit 7406cc1)
|
i fail to see the purpose here. are people using puma on public addresses directly instead of behind proxies? |
I believe it is an intended use case. |
IPv4 addresses like 0.0.0.0 are easy and familiar, but they're increasingly more expensive with provider such as AWS (https://aws.amazon.com/blogs/aws/new-aws-public-ipv4-address-charge-public-ip-insights/). IPv6 addresses are much more plentiful, and therefore cheaper (and represent the future).
This update switches the default production address to IPv6
::. Here's the table of the URLs that supports:localhost127.0.0.1::10.0.0.0::Generated with https://gist.github.com/schneems/0e3e5fb61b6e4128499af01c9cf7ac1c.
Puma has no concept of a "development" default host, so we don't need to use
::1instead of127.0.0.1orlocalhost. Also due to the behavior of::1not falling back to IPv4 the same way that::does, it seems a higher-cost, lower benefit update, so I'm not recomending it for other defaults such as Rails rails/rails#56470.Close #3812
[ci skip]to the title of the PR.#issue" to the PR description or my commit messages.