Update July 28 2015: this answer has now been incorporated into the official Passenger documentation. Please refer to https://www.phusionpassenger.com/library/indepth/nodejs/reverse_port_binding.html for the latest answer.
Phusion Passenger author here. First, let me explain what why this error occurs.
As explained in the Node.js tutorial, Phusion Passenger inverses port binding by hooking into http.Server.listen()
. If there are multiple listen()
then Passenger doesn't know which http.Server object to use for receiving requests, so it throws this error.
To solve this problem, you need to tell Passenger "I want to specify explicitly which http.Server to use for receiving requests". This is done in two steps. First, you must call the following code as early as possible in your program:
if (typeof(PhusionPassenger) != 'undefined') {
PhusionPassenger.configure({ autoInstall: false });
}
Next, you need to modify one (and only one) invocation of http.Server.listen()
, and make it pass 'passenger'
s argument:
server.listen('passenger');
If Passenger notices that you have multiple listen('passenger')
calls, it will complain. You can only have one.
Since Phusion Passenger 4.0.52 you can also pass '/passenger'
as argument. This is intended for Hapi.js support (see below).
Express.js example
Here is a full example utilizing the Express framework. You must pass 'passenger'
to Express's listen()
call.
if (typeof(PhusionPassenger) != 'undefined') {
PhusionPassenger.configure({ autoInstall: false });
}
var express = require('express');
var app = express();
app.get('/', function(req, res){
var body = 'Hello World';
res.setHeader('Content-Type', 'text/plain');
res.setHeader('Content-Length', body.length);
res.end(body);
});
if (typeof(PhusionPassenger) != 'undefined') {
app.listen('passenger');
} else {
app.listen(3000);
}
Hapi.js example
When using Hapi.js, you must pass '/passenger'
(not 'passenger'
) to Hapi's server constructor. This will cause Hapi try to listen on a Unix domain socket, which allows Phusion Passenger's overrides to kick in. If you do not pass that initial slash, then Hapi will try to treat the argument as a TCP/IP domain name, and Hapi will fail with an error.
if (typeof(PhusionPassenger) != 'undefined') {
PhusionPassenger.configure({ autoInstall: false });
}
var Hapi = require('hapi');
var server;
if (typeof(PhusionPassenger) != 'undefined') {
// Requires Phusion Passenger >= 4.0.52!
server = new Hapi.Server('/passenger');
} else {
server = new Hapi.Server('localhost', 3000);
}
server.route({
method: 'GET',
path: '/hello',
handler: function (request, reply) {
reply('hello world');
}
});
server.start();