502 Bad Gateway Deploying Express Generator Template on Elastic Beanstalk

31,210

Solution 1

For clarity, I'll state the answer from the comments.

AWS ELB runs node app.js BEFORE npm start. node app.js doesn't give an error, but it doesn't open any ports.

The solution is to simply rename app.js to anything else except server.js (ie main.js) and reference that in bin/www by pointing to it in the /bin/www file: var app = require('../app'); to var app = require('../main');

Then it should be working correctly!


For clarity, here is what my directory looks like:

The package.json file will get called by ELB when it launches the application server. Here it has the instruction to run the start script node bin/www enter image description here

This is the bin/www file that gets run. We see the require to ../main and the app.set('port'...) enter image description here

Then the main.js file that runs the routing and all: enter image description here

When I created the project, the main.js file was named app.js. The problem this caused was based on the priority ELB start sequences. ELB will launch the application and check first to see if app.js exists -- if it does exist, it runs node app.js, otherwise it will check if package.json exists and try to run npm start. When the main.js had the name app.js ELB tried to start the whole application by running it. However this file doesn't open any ports.

Solution 2

An alternative to renaming app.js is to create an elastic beanstalk configuration file. Add a .config file into the .ebextensions folder, for example, .ebextensions/34.config. Change the NodeCommand setting in the namespace aws:elasticbeanstalk:container:nodejs to whatever command you want to run to start the server. For example, this is a minimal .config file to run npm start instead of app.js:

option_settings:
  - namespace: aws:elasticbeanstalk:container:nodejs
    option_name: NodeCommand
    value: "npm start"

See http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create_deploy_nodejs_custom_container.html and http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options.html#command-options-nodejs for more information.

Edit: An even easier way - using the AWS console, Configuration/Software has the "Node command" option - just set that to npm start.

Solution 3

Set running port to 8081

app.set('port', 8081);

Solution 4

Actually, there is another option.

At the Elastic Beanstalk console, inside your app-environment section, there is a Configuration menu item on your left side (right bellow Dashboard menu option). If you click there, you will find many configuration options. Click at Software Configuration and then define which is your node command. There explain the order of commands it tries indeed: "Command to start the Node.js application. If an empty string is specified, app.js is used, then server.js, then "npm start" in that order"

My mistake was at my start command script. It was starting nodemon:

"scripts": {
    "start": "NODE_ENV=production && nodemon ./bin/www"

Then I changed to node and it worked:

"scripts": {
    "start": "NODE_ENV=production && node ./bin/www"

Hope I helped someone.

Solution 5

If you use port 8081 for running your express app and use sudo for running node server, Your application will be accessed directly from elasticbean url without port numbers, otherwise it will display a 502 Gateway error from nginx.

Nginx proxying 8081 port by default for node app on elastibeanstalk.

Create file: .ebextensions/nodecommand.config and put the option settings below:

option_settings:
  aws:elasticbeanstalk:container:nodejs:
    NodeCommand: sudo pm2 start server.js (server command with sudo ie. sudo node /bin/www)

You can create another file for container commands: .ebextensions/01_init.config and put the desired commands which will be run before deployment. For example:

container_commands:
  01_node_v6_install:
    command: sudo curl --silent --location https://rpm.nodesource.com/setup_6.x | bash -
  02_install_node:
    command: sudo yum -y install nodejs
  03_npm_install_gulp_webpack:
    command: sudo npm install -g gulp webpack pm2
  04_npm_install:
    command: sudo npm install
  05_webpack_run:
      command: sudo webpack
Share:
31,210
user3486588
Author by

user3486588

Updated on September 20, 2020

Comments

  • user3486588
    user3486588 over 3 years

    I used the express generator to create a simple express app, which when started on dev works fine on localhost:3000.

    When I push this to elastic beanstalk using the eb command-- git aws.push, however, I get a 502 error on the production server.

    Looking into the logs, the error I get is:

    2014/04/01 19:29:40 [error] 24204#0: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.31.2.178, server: , request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8081/", host: "macenvexp-env-hqv9ucmzev.elasticbeanstalk.com"
    2014/04/01 19:29:40 [error] 24204#0: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.31.2.178, server: , request: "GET /favicon.ico HTTP/1.1", upstream: "http://127.0.0.1:8081/favicon.ico", host: "macenvexp-env-hqv9ucmzev.elasticbeanstalk.com"
    

    I'm using the default nginx configuration. When I run a node.js sample app without Express, it works fine. Here's the express code in app.js:

    var express = require('express');
    var http = require('http');
    var path = require('path');
    var favicon = require('static-favicon');
    var logger = require('morgan');
    var cookieParser = require('cookie-parser');
    var bodyParser = require('body-parser');
    
    var routes = require('./routes');
    var users = require('./routes/user');
    
    var app = express();
    
    // view engine setup
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'jade');
    
    app.use(favicon());
    app.use(logger('dev'));
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded());
    app.use(cookieParser());
    app.use(express.static(path.join(__dirname, 'public')));
    app.use(app.router);
    
    app.get('/', routes.index);
    app.get('/users', users.list);
    
    /// catch 404 and forwarding to error handler
    app.use(function(req, res, next) {
        var err = new Error('Not Found');
        err.status = 404;
        next(err);
    });
    
    /// error handlers
    
    // development error handler
    // will print stacktrace
    if (app.get('env') === 'development') {
        app.use(function(err, req, res, next) {
            res.render('error', {
                message: err.message,
                error: err
            });
        });
    }
    
    // production error handler
    // no stacktraces leaked to user
    app.use(function(err, req, res, next) {
        res.render('error', {
            message: err.message,
            error: {}
        });
    }); 
    
    
    module.exports = app;
    

    And here's the package.json file:

    {
      "name": "macEnvExp",
      "version": "0.0.1",
      "private": true,
      "scripts": {
        "start": "DEBUG=macEnvExp node bin/www"
      },
      "dependencies": {
        "express": "~3.4.8",
        "static-favicon": "~1.0.0",
        "morgan": "~1.0.0",
        "cookie-parser": "~1.0.1",
        "body-parser": "~1.0.0",
        "debug": "~0.7.4",
        "jade": "~1.3.0"
      }
    }
    

    And here is bin/www:

    #!/usr/bin/env node
    var debug = require('debug')('my-application');
    var app = require('../app');
    app.configure(function(){
    app.set('port', process.env.PORT || 3000);
    });
    console.log(app.get('port'));
    var server = app.listen(app.get('port'), function() {
      debug('Express server listening on port ' + server.address().port);
    });