Skip to content

fix(init): resolve localhost IP family for devServer allowedHosts#4715

Merged
alexander-akait merged 3 commits intowebpack:mainfrom
ThierryRakotomanana:fix/devserver-allowedhosts-localhost-resolution
Mar 25, 2026
Merged

fix(init): resolve localhost IP family for devServer allowedHosts#4715
alexander-akait merged 3 commits intowebpack:mainfrom
ThierryRakotomanana:fix/devserver-allowedhosts-localhost-resolution

Conversation

@ThierryRakotomanana
Copy link
Contributor

@ThierryRakotomanana ThierryRakotomanana commented Mar 21, 2026

Summary

When host: "localhost" is set in the generated webpack.config.js, webpack-dev-server lets the OS decide at bind time whether localhost resolves to 127.0.0.1 (IPv4) or ::1 (IPv6).
On Windows 10/11 with modern network stacks, IPv6 is often prioritized, meaning localhost::1. If allowedHosts is not explicitly set, webpack-dev-server's security checks can block WebSocket connections. This is precisely why you might see those persistent disconnection loops in the console as shown on the image bellow

Ipv4 Ipv6
npm serve npm serve
Unable to connect to the server 127.0.0.1 Unable to connect to the server ::1

What kind of change does this PR introduce?

This PR esolve the OS-preferred IP family. By asking the system's native DNS what it actually prefers in the moment, we can grab the primary IP family and include it directly in the allowedHosts list.
This makes the template adaptable to your specific environment. Whether you have IPv6 at the top of your priority list or you’ve switched back to IPv4, the server will recognize the address it's running on and allow the traffic through smoothly.

Did you add tests for your changes?
I've update the snapshot test in init

Does this PR introduce a breaking change?
not really, just a fix and features to detect the local IP adress bound by the OS

If relevant, what needs to be documented once your changes are merged or what have you already documented?
Not necesserary

Use of AI
Partly, in order to understand the real issue.

…config

- Windows 10/11 can prioritize IPv6, making localhost resolve to ::1 instead of 127.0.0.1

- This causes HMR WebSocket connections to silently fail when the bound address doesn't match

- Templates now resolve the OS-preferred IP family at generation time using dns.lookup()

- Resolved value is baked into allowedHosts (127.0.0.1 or ::1)

- If resolution fails, allowedHosts is omitted and webpack-dev-server falls back to its own 'auto' behavior

- Updated templates: default, vue, react, svelte

- Updated snapshots
@changeset-bot
Copy link

changeset-bot bot commented Mar 21, 2026

🦋 Changeset detected

Latest commit: 2c52d57

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
create-webpack-app Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@codecov
Copy link

codecov bot commented Mar 21, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.43%. Comparing base (c76ab1c) to head (2c52d57).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #4715   +/-   ##
=======================================
  Coverage   91.43%   91.43%           
=======================================
  Files          14       14           
  Lines        4716     4716           
  Branches      679      679           
=======================================
  Hits         4312     4312           
  Misses        402      402           
  Partials        2        2           

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c76ab1c...2c52d57. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@alexander-akait
Copy link
Member

We don't need to do it, it is out of scope our basic generation

@ThierryRakotomanana
Copy link
Contributor Author

@alexander-akait okay, Just out of curiosity, isn't it counter-intuitive that the server runs on localhost but blocks the IP address it’s bound to? Neither 127.0.0.1 nor ::1 are actually blocked by default, so it feels a bit strange for new users

@alexander-akait
Copy link
Member

alexander-akait commented Mar 21, 2026

@ThierryRakotomanana Sorry I don't understand you, we are not blocking 127.0.0.1/::1/localhost

@ThierryRakotomanana
Copy link
Contributor Author

ThierryRakotomanana commented Mar 21, 2026

@alexander-akait My PR description might have been unclear, sorry for that, so to simplify: currently, when running a fresh project via the cli npx create-webpack-app and starting the server with npm run serve, the server only listens on localhost.
If a user tries to access the server via 127.0.0.1 (IPv4) or ::1 (IPv6), depending on the IP family OS priority, this happens inside the console on the browser side :

index.js:642 [webpack-dev-server] Disconnected!
index.js:642 [webpack-dev-server] Trying to reconnect...
installHook.js:1 [webpack-dev-server] Invalid Host/Origin header

a loop who alway tray do reconnect to the server, as shown in the attached image, I've put on the PR description. I have confirmed this behavior across different OS : Windows 10, WSL, and native Ubuntu, and use different version of Node.
The issue is that the server strictly expects the string 'localhost' and rejects IP addresses.
My change addresses this by adding dynamicly allowedHosts to 127.0.0.1 or ::1(depending on the OS/environment preference). So everytime a new user install it, he does'nt have to retype this config to the webpack.config.js

@ThierryRakotomanana
Copy link
Contributor Author

When attempting to access the application via a IP address (e.g., 127.0.0.1 or ::1) instead of the localhost

Ipv4 Ipv6
npm serve npm serve

@alexander-akait
Copy link
Member

Sorry, I can't reproduce it locally, looks like you have something wrong on your side in your configuration

@ThierryRakotomanana
Copy link
Contributor Author

ThierryRakotomanana commented Mar 23, 2026

Yes, it's conifg problem: it’s coming from the webpack.config.js.tpl file in the template. The host is hardcoded as a string "localhost", which is too restrictive.

<% if (devServer) { %>
    devServer: {
        open: true,
        host: "localhost", // This causes the origin mismatch
    },<% } %>

Because it's explicitly set to the string "localhost", the server only expects that exact host. If you try to access it via a loopback address like 127.0.0.1 or ::1, the browser sees it as a different origin, which triggers a CORS error.

How to reproduce it

  1. Generate a project:
npx create-webpack app localhost-problem
  1. Fire it up:
npm run serve
  1. Check your terminal. You'll likely see something like:
    • Loopback: http://localhost:8080/, http://[::1]:8080/
    • OR
    • Loopback: http://localhost:8080/, http://127.0.0.1:8080/
  2. Now, try to open the IP version (the 127.0.0.1 or [::1] link) instead of "localhost".
  3. Open your browser console and you'll see the origin/CORS errors popping up.
index.js:642 [webpack-dev-server] Disconnected!
index.js:642 [webpack-dev-server] Trying to reconnect...
installHook.js:1 [webpack-dev-server] Invalid Host/Origin header

My suggestion to fix it

We have two solid options here:

  • Option A: Add allowedHosts: ["dynamic loopback IP adress "] (like I suggested in my PR).
  • Option B (Cleaner and all webpack.config.js presented in the docs are like this one): Just delete the host: "localhost" line entirely from the templates. This lets Webpack use its default logic, which handles all loopback addresses automatically without the CORS headache.

@alexander-akait
Copy link
Member

Option B (Cleaner and all webpack.config.js presented in the docs are like this one): Just delete the host: "localhost" line entirely from the templates. This lets Webpack use its default logic, which handles all loopback addresses automatically without the CORS headache.

Let's do it

@ThierryRakotomanana
Copy link
Contributor Author

Option B (Cleaner and all webpack.config.js presented in the docs are like this one): Just delete the host: "localhost" line entirely from the templates. This lets Webpack use its default logic, which handles all loopback addresses automatically without the CORS headache.

Let's do it

Done, could you please reopen the PR?

@alexander-akait
Copy link
Member

@ThierryRakotomanana Done

@alexander-akait alexander-akait merged commit ae94d81 into webpack:main Mar 25, 2026
19 checks passed
@alexander-akait
Copy link
Member

To be honestly it sounds like a bug for localhost in dev server too, can you take a look?

@ThierryRakotomanana
Copy link
Contributor Author

To be honestly it sounds like a bug for localhost in dev server too, can you take a look?

Sure, I’ll dive in and see what's going on.

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.

2 participants