502 Bad Gateway Deploying Express Generator Template on Elastic Beanstalk
Asked Answered
T

8

58

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);
});
Torment answered 1/4, 2014 at 19:39 Comment(4)
Solved. I believe the issue here was that AWS was doing node app.js BEFORE npm start. node app.js doesn't give an error, but it doesn't open any ports. So the solution was to rename app.js to anything else (I used main.js) and reference that in bin/www. It's now working correctly.Torment
This solution was extremely useful (I spent several hours on this). Thanks a bunch. Please elaborate how you find out "AWS was doing node app.js BEFORE npm start"Retard
Using express via the AWS tutorial docs.aws.amazon.com/elasticbeanstalk/latest/dg/… I not only had to rename app.js to something else but I also had to point to it in my /bin/www file: 'var app = require('../app');' to 'var app = require('../main');'Ga
Thanks this helped a ton! I made another huge & dumb mistake as I was trying to fix this... I was using git aws.push to push my changes, but hadnt committed my changes to git/github. So I was pushing old code with no changes. :/ Anyways finally got it fixed with your help. --Think you can make that the official answer instead of just a comment?Consummation
C
88

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.

Consummation answered 15/8, 2014 at 18:4 Comment(7)
where is that /bin/www file? on the ex2 instance?Granular
figured out the express 4 structure. literally did express inside a blank 'test' folder and updated my /bin/www following the rename. still no dice :/Granular
I update the answer to show the directory structure. I struggled with it a while. You are using ELB (Elastic Beanstalk) right? The directory I show is the whole thing that you upload to ELB. Are you uploading via github or a zip file? For zip you may want to try two things: zip the whole folder recibel in my cas, OR zip the contents within recibel.Consummation
Changing my main file from app.js to main.js solved all my issues. Seriously... thank you!!!Uniat
Thanks for the detailed answer. I think I am running into the same issue, and have followed your instructions for configuring the app, but I am getting a 'permission denied' error when running the start script 'server/bin/www' in my case. the root folder of the packaged distribution contains the server directory above. I've also added the exec permissions on the www script. Any ideas why I might be getting this error?Manyplies
Hmm.. This actually didn't solved for me directly. Maybe because I don't have server.js with my project. So instead of relying on instance to run npm in that order, we could bypass that by supplying custom start command to the environment, i.e. npm start.Kelila
Why anything besides server.js? When I started my project, I named my app.js file "server.js". I'm having this same issue. Should I rename server.js to something else?Modla
G
29

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.

Gigantean answered 9/6, 2015 at 21:41 Comment(2)
I didn't want to change my express structure so the final Edit in this answer was the perfect cure. It's a shame this isn't highlighted in the AWS EB tutorials.Cabalist
AWS console, Configuration/Software, 'Node command' set to 'npm start' worked great for me!Pinkney
A
5

Set running port to 8081

app.set('port', 8081);
Adele answered 30/12, 2016 at 21:39 Comment(1)
Nginx inside (for nodejs apps) Elasticbeanstalk listens 8081 for nodejs server, redirects requests to there by default. If you don’t set PORT env. variable and set nodejs app server’s port like: var port = process.env.PORT | 8080; EB will set PORT to 8081. Check: docs.aws.amazon.com/elasticbeanstalk/latest/dg/…Adele
S
3

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.

Silassilastic answered 16/7, 2016 at 12:11 Comment(0)
V
3

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
Viehmann answered 9/12, 2016 at 11:7 Comment(0)
J
2

In case anyone did the silly thing I did, make sure your bin folder is committed if you are using express. I had mine in my .gitignore file and this is why I was getting a 502 error.

Just remove /bin from .gitignore, commit, and the deploy changes to EB.

Jerri answered 25/7, 2015 at 16:38 Comment(0)
A
1

new to AWS and been a while since i webdeved, but was stuck tonight on same issue, and thanks to everyone in the thread, i am very happy to say that basic socket.io tutorial works now like a charm, i was just forgetting one line in package.json :

"scripts":
{
"start": "node app.js"
}

oh, and port ! the only thing i kept from elasticbean sample node.js app is this value instead of pure 3000 value :

var port = process.env.PORT || 3000;
Aloin answered 31/8, 2018 at 23:45 Comment(0)
T
0

Note: I ran into this issue and none of the solutions were working for me.

My solution was to make sure the devDependencies in package.json were actually in dependencies.

For example:

{
  "name": "whaler-test",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www",
    "create-db": "cd dynamodb && node createDonorsTable.js && cd ..",
    "delete-db": "cd dynamodb && node deleteDonorsTable.js && cd ..",
    "load-data": "cd dynamodb && node loadDonorsData.js && cd ..",
    "read-data": "cd dynamodb && node readDataTest.js && cd .."
  },
  "dependencies": {
    "cookie-parser": "~1.4.3",
    "debug": "~2.6.9",
    "express": "~4.16.0",
    "http-errors": "~1.6.2",
    "jade": "~1.11.0",
    "morgan": "~1.9.0",
    "nodemon": "1.17.5",
    "cors": "2.8.4",
    "aws-sdk": "^2.270.1"
  }
}

Not:

{
  "name": "whaler-test",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www",
    "create-db": "cd dynamodb && node createDonorsTable.js && cd ..",
    "delete-db": "cd dynamodb && node deleteDonorsTable.js && cd ..",
    "load-data": "cd dynamodb && node loadDonorsData.js && cd ..",
    "read-data": "cd dynamodb && node readDataTest.js && cd .."
  },
  "dependencies": {
    "cookie-parser": "~1.4.3",
    "debug": "~2.6.9",
    "express": "~4.16.0",
    "http-errors": "~1.6.2",
    "jade": "~1.11.0",
    "morgan": "~1.9.0",
    "nodemon": "1.17.5"
  },
  devDependencies {
    "cors": "2.8.4",
    "aws-sdk": "^2.270.1"
  }
}
Tokyo answered 9/7, 2018 at 8:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.