Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue thinks local IP address is global, causing several issues #1616

Closed
kissge opened this issue Jun 19, 2018 · 28 comments
Closed

Vue thinks local IP address is global, causing several issues #1616

kissge opened this issue Jun 19, 2018 · 28 comments
Labels

Comments

@kissge
Copy link

kissge commented Jun 19, 2018

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.

@LinusBorg
Copy link
Member

The devserver is meant for local development and is not accessible from outside by default.

However, you can adjust this behaviour in vue.config.js with the devServer option.

https://cli.vuejs.org/config/#devserver

Options to look into:

https://webpack.js.org/configuration/dev-server/#devserver-disablehostcheck

https://webpack.js.org/configuration/dev-server/#devserver-host

@kissge
Copy link
Author

kissge commented Jun 20, 2018

Thanks for you reply.
Yes, I read that and have already tried; if my understanding is correct, that means putting this file?
It was not effective.
App cannot be accessed via domain (Invalid Host header), and even if I somehow connect (e.g. using global IP address) HMR fails because vue-cli-service thinks local address as global.
Also the console shows "App running at: Local: localhost:8080 Network: xxx.xxx.xxx.xxx:8080" where xxx.xxx.xxx.xxx is local IP address (I think this is meaningless).

@LinusBorg
Copy link
Member

LinusBorg commented Jun 20, 2018

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,
  },
};

@kissge
Copy link
Author

kissge commented Jun 21, 2018

Oops, my fault... thanks for pointing out.
But still, two other problems persist.
I think address.ip() used here is something meant to get local IP address, unlike other things like this and this?

  • 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

@LinusBorg
Copy link
Member

The code you mention should not be running if I set the host option (to your external IP)

@kissge
Copy link
Author

kissge commented Jun 21, 2018

So you mean the right configuration is not host: '0.0.0.0', but host: 'ggg.ggg.ggg.ggg', where ggg.ggg.ggg.ggg is my global IP address, right?
It also didn't work (of course no other process is listening to 8080, just to make it clear):

$ npm run serve

> anne3@0.1.0 serve /***/***/***/***
> vue-cli-service serve

 INFO  Starting development server...
Starting type checking service...
Using 1 worker with 2048MB memory limit
 10% building modules 1/1 modules 0 activeevents.js:183                            
      throw er; // Unhandled 'error' event
      ^

Error: listen EADDRNOTAVAIL ggg.ggg.ggg.ggg:8080
    at Object._errnoException (util.js:992:11)
    at _exceptionWithHostPort (util.js:1014:20)
    at Server.setupListenHandle [as _listen2] (net.js:1338:19)
    at listenInCluster (net.js:1396:12)
    at GetAddrInfoReqWrap.doListen [as callback] (net.js:1505:7)
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:97:10)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! anne3@0.1.0 serve: `vue-cli-service serve`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the anne3@0.1.0 serve script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/ec2-user/.npm/_logs/2018-06-21T07_43_06_386Z-debug.log

@LinusBorg
Copy link
Member

Hm, I see...

Side question: why do you want to run the development server on a remote machine?

@kissge
Copy link
Author

kissge commented Jun 21, 2018

Well, I thought that occurs everywhere... at least in the companies I have been at :)
Manager gives an EC2 instance to each developer, and they do their development on that machine.
This way provisioning is easy and you can destroy and rebuild machines at any time.
Plus you can limit resource access (e.g. RDB) within the network (on the cloud).
Another good point is I usually use my Windows PC but can develop on Linux.

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.

@LinusBorg
Copy link
Member

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?

@ryanjaeb
Copy link

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.

@padiazg
Copy link

padiazg commented Jul 20, 2018

@ryanjaeb You can use my patch/workarround to solve this issue, look here #1905

@yyx990803
Copy link
Member

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 ccc90c9 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.

@lc-thomas
Copy link

lc-thomas commented Aug 22, 2018

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)

@titpetric
Copy link

@lux-lth yeah, that was my confusion here too. It took quite a bit of research over GH issues and webpack questions to find out that one can just create a vue.config.js in the root of the project, with the contents that Linus suggested above. Thanks!

@JCKodel
Copy link

JCKodel commented Nov 25, 2018

I've found this issue looking for a solution where a device connected through Chrome's port forwarding was trying to connect to the hot reloading module in my local IP address (192.168.0.250) instead of localhost (Chrome port forwarding only works on localhost), causing the hot reloading module not to work on mobile.

Based on what is written in this issue, my vue.config.js:

const fs = require("fs");
const path = require("path");
const port = 18001; // Easy to change the port here

function resolvePath(dir)
{
    return path.join(__dirname, "certificates", dir); // c:\project\certificates contains my self-signed HTTPs certificates
}

module.exports =
    {
        lintOnSave: false,
        baseUrl: `https://localhost:${port}/`,
        devServer:
        {
            https: // Only needed if you want https (I need them for location and web notifications)
            {
                key: fs.readFileSync(resolvePath("server.key")),
                cert: fs.readFileSync(resolvePath("server.crt")),
                ca: fs.readFileSync(resolvePath("server.pem.key"))
            },

            headers:
            {
                "Access-Control-Allow-Origin": "*"
            },

            overlay: true,
            port, // This will take care of desktop machine
            public: `0.0.0.0:${port}`, // This will take care of mobile device
            disableHostCheck: true,
        }
    };

And it works (there is a huge warning on Android because of not trusted certificate, but that's another issue).

 DONE  Compiled successfully in 302ms                                                                                                                                                           16:30:24
                                                                                                                                                                          Type checking in progress...

  App running at:
  - Local:   https://localhost:18001/
  - Network: https://0.0.0.0:18001/

No type errors found
Version: typescript 3.1.6
Time: 609ms

@peterblazejewicz
Copy link

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!

@eng1n88r
Copy link

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

@mrcl
Copy link

mrcl commented Apr 24, 2019

Same issue with @vue/cli-service@3.6.0

@Tarasovych
Copy link

Same issue here with an app inside VirtualBox

@phalconVee
Copy link

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
  }
}

@ararename
Copy link

ararename commented Jan 21, 2020

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 ...

@marcoippolito
Copy link

marcoippolito commented Jan 23, 2020

In Ubuntu 18.04.03 Server Edition and with vue@2.6.11, I'm getting these error messages, when deploying my starting-page of webapp with vue.js: npm run serve

INFO Starting development server…
98% after emitting CopyPlugin

DONE Compiled successfully in 10220ms 3:02:16 PM

App running at:

    Local: http://192.168.1.7:8081/
    Network: http://192.168.1.7:8081/

GET https://192.168.1.7:8081/sockjs-node/info?t=1579780726858
net::ERR_SSL_PROTOCOL_ERROR
GET https://192.168.1.7/sockjs-node/info?t=1579780726857
net::ERR_CERT_COMMON_NAME_INVALID

sockejsError01

sockejsError02

sockejsError03

This is my vue.config.js file :

module.exports = {
  productionSourceMap: false,
  pluginOptions: {
    i18n: {
      enableInSFC: true
    }
  },
  devServer: {
    host: '192.168.1.7',
    hot: true,
    disableHostCheck: true
  }
}

How to solve the problem?

@alex700
Copy link

alex700 commented Jan 24, 2020

In my case I had HOST env variable in .env file. It was specified with production host which caused same error.

@marcoippolito
Copy link

@alex700 in which file exactly you had HOST env variable set to production, which caused sockjs error?
I get these error messages: net::ERR_CONNECTION_REFUSED
sockejsError05
sockejsError06

@alex700
Copy link

alex700 commented Jan 28, 2020

@marcoippolito HOST env was specified in .env file during usage at local installation. For example if my production is example.com and local installation local.example.com and HOST=example.com is specified at local installation I have the same error in Vue.

@marcoippolito
Copy link

Thanks @alex700 . I guess I miss something because I didn't specify any .env file

@m-root
Copy link

m-root commented Jun 29, 2020

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.

Worked like magic for me :-)

@neontuna
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests