vue-cli: Vue thinks local IP address is global, causing several issues

Version

3.0.0-rc.2

Reproduction link

https://github.com/kissge/vue-cli-bug

Steps to reproduce

  1. Using vue create to start a project, on a remote machine (say, AWS EC2 instance)
  2. Run npm run serve

What is expected?

What is actually happening?

  • Local IP address is shown in console
  • HMR fails because sockjs tries to connect to local IP address
  • App cannot be accessed from outside the network, so I have to use tricks like ssh port forwarding

I also tried tweaking webpack config from vue.config.js, with no luck.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 7
  • Comments: 28 (6 by maintainers)

Most upvoted comments

the devServer options have their own options property in vue.config.js because we process them internally before handing them to the devserver:

module.exports = {
  configureWebpack: {
    // other webpack options to merge in ...
  },
  // devServer Options don't belong into `configureWebpack`
  devServer: {
    host: '0.0.0.0',
    hot: true,
    disableHostCheck: true,
  },
};

So first, a small update. the devServer.public setting should allow you to set the public host to 0.0.0.0:8080

 devServer: {
    // setting host should not be necessary
    // host: '0.0.0.0:8080'
    public: '0.0.0.0:8080'
    disableHostCheck: true,
  },

Out of curiosity, when you develop on localhost, then I wonder why HMR wants to connect to the server via local network address, not localhost.

It doesn’t do that for me. An that’s a different scenario that yours, where you do access from an external host, right?

I think vue create my_project_name should also generate a vue.config.js file at the root of the project with the default configuration (and maybe hostCheck option set to true)

Cases like this happen if you are running another app (e.g. Laravel via the artisan CLI) concurrently on your network that uses the same port as your Vuejs app. So basically it is listening to both your local and network IP when running the app in your dev environment.

if you are working on Vue CLI, may not be able to configure webpack dev server directly. instead, locate your vue.config.js file and use the sample below.

module.exports = {
  publicPath: '/',
  devServer: {
    host: 'localhost',
    port: 3000
  }
}

I think setting devServer.public to 0.0.0.0 is a misconfiguration. The linked docs say:

When using inline mode and you’re proxying dev-server, the inline client script does not always know where to connect to. It will try to guess the URL of the server based on window.location, but if that fails you’ll need to use this.

Based on my testing, the address given for devServer.public is what the (browser) client will use when attempting to open a websocket connection for HMR. So if you set it to 0.0.0.0 it won’t be able to open the websocket because that’s not a routable IP.

Something that can be confusing is the auto-detection can end up using an IP from a purely local network adapter. For example, the yarn serve defaults give me:

App running at:
  - Local:   http://localhost:8080/
  - Network: http://10.0.75.1:8080/

That 10.0.75.1 IP is for DockerNAT. It’s only accessible from my machine. I’ve always thought you can bind to localhost and 0.0.0.0 reliably and beyond that you need user specific config. Where does the 10.0.75.1 get detected?

The Network IP (10.0.75.1) is the same IP that is used (by default) for the HMR websocket for me. Where is that default getting set? If vue-cli-service serve is setting it, I don’t think it should. The window.location strategy described in the Webpack docs seems like the most reliable way to do it. If that doesn’t work, I can’t think of a way you’d be able to figure it out (reliably) without having the user specify it. Is there another way?

What exactly is the Network address being reported? When I set devServer.public to an alternate IP, the HMR websocket connection uses the newly set IP (as expected), but yarn serve still reports Network: http://10.0.75.1:8080/.

It also seems like the server binds to 0.0.0.0 even though the above App running at message gives the impression it bound to 2 specific interfaces. By default, I can access the server from another PC on my LAN. If I set devServer.host to 0.0.0.0, there’s no change:

// vue.config.js
module.exports = {
    devServer: {
        host: '0.0.0.0',
    },
}

gives:

App running at:
  - Local:   http://localhost:8080/
  - Network: http://10.0.75.1:8080/

The app is still accessible from my LAN. If I set devServer.host to localhost something doesn’t like it:

App running at:
  - Local:   http://localhost:8080/
  - Network: undefined

However, the app is only accessible at localhost which makes sense since I set host to localhost.

Is the goal to avoid giving the user http://0.0.0.0:8080 as an address? If so, maybe you could do something like this (ignoring https options):

Server listening at:
- Host: devServer.host
- Port: devServer.port

Then, if devServer.host is 0.0.0.0 (this always includes localhost):

App available at:
- Local:  http://localhost:devServer.port
- Public: devServer.public or 'None'
See: https://webpack.js.org/configuration/dev-server/#devserver-public

Otherwise:

App available at:
- Local:  http://devServer.host:devServer.port
- Public: devServer.public or 'None'
See: https://webpack.js.org/configuration/dev-server/#devserver-public

The --public option described in the Webpack Docs doesn’t seem to pass through on the CLI. Is it supposed to? Ideally the OPs case would be solved by (note: this does not work currently):

yarn serve --host "0.0.0.0" --port "8080" --public "mydomain.example.com:8080"

with the output:

Server listening at:
- Host: 0.0.0.0
- Port: 8080

App available at:
- Local:  http://localhost:8080
- Public: http://mydomain.example.com:8080
See: https://webpack.js.org/configuration/dev-server/#devserver-public

@kissge Try this vue.config.js:

// vue.config.js
module.exports = {
    devServer: {
        host: '0.0.0.0',
        port: '8080',
        public: 'mydomain.example.com:8080',
    },
}

Note that you must be able to connect to mydomain.example.com on port 8080.

@LinusBorg A decent use case for wanting to do this is to have a site / app running on an alternate device during development. For example, at the moment I’m playing around with an app on a Raspberry Pi. The screen is fairly low resolution (800x480), the color reproduction isn’t comparable to the monitor I use for development, and I want to test the touch input. It’s useful to have it plugged in beside me auto-reloading as I make changes.

Same issue with @vue/cli-service@3.6.0

So, the inference for public network API has its limitations, but you can always explicitly specify the public URL to use with devServer.public in vue.config.js.

In ccc90c98 I’ve also added:

  • allow specifying devServer public url via vue-cli-service serve --public your/url:port
  • made the console message prioritize this value.

Wanted to leave a comment here for folks arriving from Google looking to get this working with an ngrok tunnel. Ngrok configuration is standard http tunnel. The final working dev server config for us ended up being

devServer: {
  public: 'your-subdomain.ngrok.io',
  disableHostCheck: true,
  headers: {
    'Access-Control-Allow-Origin': '*',
  },
},

This ought to allow you to access via tunnel (including https) with hot reloading working and no CORS issues.

Not sure why yet, but after upgrade to @vue/cli-service to 3.5.3 start getting

GET http://localhost:8080/sockjs-node/info?t=1554912129403 net::ERR_CONNECTION_REFUSED

on 3.5.0 was working fine without touching vue.config.js

Maybe i don’t get something essential but i think i encounter some behaviour with cli version4 that seems to be the same thing and nothing here on this page seems to completely help:

I do a standard vue create, without any vue.config.js file in the root dir, and npm run servetells me: App running at:

Calling it in the browser the page gets loaded fine but the console gives me (cross-origin) warnings: xxx.xxx.xxx.xxx:8081/sockjs-node/info?t=1579649486458 could not be read, one by one, adding up.

Then, after adding a vue.config.js file in the root folder with the content suggested by phalconVee npm run servetells me: App running at:

and the warnings are gone. Still, the browser now connects to http://localhost:8081 two times for each XHR:

[HMR] Waiting for update signal from WDS… log.js:24 XHRGEThttp://localhost:8081/sockjs-node/info?t=1579650320832 [HTTP/1.1 200 OK 1ms]

XHRGEThttp://localhost:8081/sockjs-node/info?t=1579650320833 [HTTP/1.1 200 OK 2ms]

What would i have to do to have no extra network participating at all? Like with vue init webpack ...

I think this is a bug, because it occurs when creating the default template with all defaults settings too:

So I’ve run vue create hello-world --default :

vue create hello-world --default        


Vue CLI v3.2.1
✨  Creating project in /Users/piotrblazejewicz/git/pwa-builder-test/hello-world.
🗃  Initializing git repository...
⚙  Installing CLI plugins. This might take a while...


> fsevents@1.2.4 install /Users/piotrblazejewicz/git/pwa-builder-test/hello-world/node_modules/fsevents
> node install

[fsevents] Success: "/Users/piotrblazejewicz/git/pwa-builder-test/hello-world/node_modules/fsevents/lib/binding/Release/node-v59-darwin-x64/fse.node" is installed via remote

> yorkie@2.0.0 install /Users/piotrblazejewicz/git/pwa-builder-test/hello-world/node_modules/yorkie
> node bin/install.js

setting up Git hooks
done

added 1177 packages from 761 contributors and audited 14846 packages in 41.504s
found 0 vulnerabilities

🚀  Invoking generators...
📦  Installing additional dependencies...

added 26 packages from 23 contributors, updated 2 packages, moved 5 packages and audited 15136 packages in 13.117s
found 0 vulnerabilities

⚓  Running completion hooks...

📄  Generating README.md...

🎉  Successfully created project hello-world.
👉  Get started with the following commands:

 $ cd hello-world
 $ npm run serve

and I’ve ended using Google to learn that I have to add vue.config.js with just single property to just remove those errors.

Thanks!