3

I'm new to NodeJS and trying to set up an existing project (developed by someone else) in Cloud9 IDE (I'm using an older Cloud9 account; so not running on AWS). I've pulled the git and installed everything. This all seemed to go without problems.

To run the app locally, outside of Cloud9, you would start the server with npm run start (I know from the person who developed the app, this works for him). But I want to set it up in Cloud9, and in Cloud9 it is necessary to set some variables first (if I don't define the host first, it gives the error "Invalid Host header"). Therefore, I use the following two commands:

export HOST=$C9_HOSTNAME && export PORT=8080
npm run start

The npm run start produces the error:

Could not find an open port at appname-username.c9users.io.

Network error message: listen EADDRNOTAVAIL 35.189.252.103

I believe I have the port correct, considering https://docs.c9.io/docs/run-an-application. I’ve also tried the values 8081, 8082 and $PORT but none of these work.

Any ideas how I could get the Cloud9 local preview working?


Upon request some lines from start.js:

const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
const HOST = process.env.HOST || '0.0.0.0';
console.log(`1. The host is ${HOST} on port ${DEFAULT_PORT}`);  //ADDED

choosePort(HOST, DEFAULT_PORT)
  .then(port => {
    console.log(`2. The host is ${HOST} on port ${DEFAULT_PORT}`);  //ADDED
    if (port == null) {
      // We have not found a port.
      return;
    }
    const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
    const appName = require(paths.appPackageJson).name;
    const urls = prepareUrls(protocol, HOST, port);
    // Create a webpack compiler that is configured with custom messages.
    const compiler = createCompiler(webpack, config, appName, urls, useYarn);
    // Load proxy config
    const proxySetting = require(paths.appPackageJson).proxy;
    const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
    // Serve webpack assets generated by the compiler over a web sever.
    const serverConfig = createDevServerConfig(
      proxyConfig,
      urls.lanUrlForConfig
    );
    const devServer = new WebpackDevServer(compiler, serverConfig);
    // Launch WebpackDevServer.
    devServer.listen(port, HOST, err => {
      if (err) {
        return console.log(err);
      }
      if (isInteractive) {
        clearConsole();
      }
      console.log(chalk.cyan('Starting the development server...\n'));
      openBrowser(urls.localUrlForBrowser);
    });

  })
  .catch(err => {
    if (err && err.message) {
      console.log(err.message);
    }
    process.exit(1);
  });

netstat --listen responds with the following information:

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp6       0      0 [::]:ssh                [::]:*                  LISTEN     
Active UNIX domain sockets (only servers)
Proto RefCnt Flags       Type       State         I-Node   Path
unix  2      [ ACC ]     STREAM     LISTENING     1533837857 /home/ubuntu/.c9/6614254/collab.sock
unix  2      [ ACC ]     STREAM     LISTENING     1533835235 /home/ubuntu/.c9/bridge.socket
unix  2      [ ACC ]     STREAM     LISTENING     1533836998 /tmp/tmux-1000/cloud92.2

The function choosePort is part of the node module "react-dev-utils" and reads as follows:

function choosePort(host, defaultPort) {
  return detect(defaultPort, host).then(
    port => new Promise(resolve => {
      if (port === defaultPort) {
        return resolve(port);
      }
      if (isInteractive) {
        clearConsole();
        const existingProcess = getProcessForPort(defaultPort);
        const question = {
          type: 'confirm',
          name: 'shouldChangePort',
          message: chalk.yellow(
            `Something is already running on port ${defaultPort}.` +
              `${existingProcess ? ` Probably:\n  ${existingProcess}` : ''}`
          ) + '\n\nWould you like to run the app on another port instead?',
          default: true,
        };
        inquirer.prompt(question).then(answer => {
          if (answer.shouldChangePort) {
            resolve(port);
          } else {
            resolve(null);
          }
        });
      } else {
        console.log(
          chalk.red(`Something is already running on port ${defaultPort}.`)
        );
        resolve(null);
      }
    }),
    err => {
      throw new Error(
        chalk.red(`Could not find an open port at ${chalk.bold(host)}.`) +
          '\n' +
          ('Network error message: ' + err.message || err) +
          '\n'
      );
    }
  );
}
Community
  • 1
  • 1
Nick
  • 3,496
  • 7
  • 42
  • 96
  • If you can't find how to preview your running app, try to use port 8080 in the URL. – RamThakur Dec 20 '18 at 13:13
  • Thanks @RamThakur, but I'm afraid I don't fully understand what you mean. Do you mean to first run `export HOST=$C9_HOSTNAME:8080` and then `npm run start`? This produces a similar error: "Could not find an open port at appname-username.c9users.io:8080". – Nick Dec 21 '18 at 17:05
  • Can we get access to the node.js code? It might be the case that the node.js server is specifying a static port in code instead of adhering to the `PORT` environment variable you are setting prior to starting the app. – willascend Dec 23 '18 at 18:39
  • @willascend, I have added what I think is the relevant part of the code to the post. – Nick Dec 24 '18 at 13:15
  • I just scanned the IP address you provided with nmap and 8080 is open. Are you sure you have the correct hostname and application name? – Nick Chapman Dec 25 '18 at 17:54
  • Since I use `export HOST=$C9_HOSTNAME` I know I'm not making any typos. Also, `echo $HOST` confirms export worked correctly. I added two console.log lines to `start.js` (see post). The first console.log returns `1. The host is appname-username.c9users.io on port 8080` as we would expect. The second console.log line is never reached since it goes to the `catch(err...` part of the code. – Nick Dec 25 '18 at 19:24
  • @Nick actually I was trying to say that can you open the URL with port 8080 in a different tab after pressing the run button on the top right which is along with preview button. for e.g- appname-username.c9users.io:8080 – RamThakur Dec 26 '18 at 06:53
  • @RamThakur, pressing the run button is the same as `npm run start`, which results in the described error message. – Nick Dec 26 '18 at 11:56
  • @Nick the fact that you're never reaching the second console.log is good information. The code is failing somewhere in the choosePort function. Can you paste that function's body as well? – willascend Dec 28 '18 at 19:52
  • Thanks @willascend, I've added the function to the original post. – Nick Dec 28 '18 at 20:41

1 Answers1

5

I did some googling on this and I think the issue might be with the host value you are setting. Per this Cloud9 support thread which references a similar error:

...You need to use 0.0.0.0 instead since c9user.io is the public address of the proxy. Or modify your /etc/hosts file. echo "0.0.0.0 $C9_HOSTNAME" | sudo tee -a /etc/hosts

So, try setting the host to 0.0.0.0 instead of the public hostname:

export HOST=0.0.0.0 && export PORT=8080 && npm run start

Also just found this on the support page you linked to:

If you're developing a server application, please note that you need to listen to 0.0.0.0 ($IP) and 8080 ($PORT). Listening to this port will enable your app to be viewable at http://-.c9users.io

Listening on 0.0.0.0 should resolve the issue.

Edit (in response to additional error being returned):

For the "Invalid host header" error, I think you're on the right track with setting disableHostCheck to true, but your npm script command isn't likely adhering to the flag from.the CLI. There are probably a few ways to get that flag passed, but the simplest might be to update your code to set the option when creating the dev server. Keep in mind this is just a quick fix to see if we can get it to work. It would be better to update the createDevServerConfig function to set the option:

const devServer = new WebpackDevServer(compiler, { ...serverConfig, disableHostCheck: true});

Another edit:

The disableHostCheck option is insecure and can open you up to vulnerabilities. It's considered a quick fix when testing locally and should only be used in a closed network. To fix the"Invalid host header" in an exposed environment, use the public option, where public is your DNS host name or public IP address:

const devServer = new WebpackDevServer(compiler, { ...serverConfig, public: process.env.PUBLIC_HOST }

You can then have this value passed in via the CLI environment like your other vars:

export HOST=0.0.0.0 && export PORT=8080 && export PUBLIC_HOST=$C9_HOSTNAME:8080 && npm run start

Disclaimer: I don't think the changes above are the best way to go about doing this (it would likely be better to update the createDevServerConfig function, but they should resolve your issues. More information on the disableHostCheck option can be found here, here, and here.

willascend
  • 1,503
  • 8
  • 15
  • Thanks, I enter `export HOST=0.0.0.0 && export PORT=8080 && npm run start`. Then I visit appname-username.c9users.io:8080. This produces the error "Invalid Host header". On https://help.crossbrowsertesting.com/faqs/testing/invalid-host-header-error/ I read this is “most commonly caused by a misconfiguration of the application server that causes it to reject non-local connections.”. I tried `npm run start --disable-host-check`. This however still results in "Invalid Host header". – Nick Dec 28 '18 at 20:52
  • Hi @Nick. I edited my answer. If what I provided doesn't work, you night need to update the `createDevServerConfig` function. Also, depending on what the `npm run start` script actually is, it may be possible to update it and add the CLI option there. – willascend Dec 29 '18 at 04:33
  • If I change it to `const devServer = new WebpackDevServer(compiler, {serverConfig, disableHostCheck: true});` it gives the error "Invalid configuration object. webpack-dev-server has been initialised using a configuration object that does not match the API schema. - configuration has an unknown property 'serverConfig'." I also tried `const devServer = new WebpackDevServer(compiler, serverConfig, {disableHostCheck: true});` but then it doesn't seem to process `disableHostCheck` as it it still gives the "Invalid Host Header" error. – Nick Dec 29 '18 at 12:30
  • Hi Nick, did you add the three dots in front of the `serverConfig` identifier in the object? I updated the code there was a typo. Please see if what's there now will work. – willascend Dec 29 '18 at 12:40
  • Thanks, awesome, it now works! Is there also a way to disable the HostCheck without makes changes to the code? (it sounds a bit insecure, so if someone else working with the code doesn't need to disable it to make it run locally, I'm sure they would prefer not to have this disabled.) – Nick Dec 29 '18 at 12:49
  • Hi @Nick, code or configuration changes will be required to resolve this issue. Can you open a pull request on the original repo? With that said, you are correct about the security vulnerability. I've updated my answer to also include the `public` option, which should be used when proxying the server. Will that resolve your issue? – willascend Dec 29 '18 at 14:18
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/185913/discussion-between-willascend-and-nick). – willascend Dec 29 '18 at 14:57
  • Great! Glad I could help! – willascend Dec 30 '18 at 03:32