Running nodejs under nginx

Problem

I'm currently trying out nginx and nodejs with connect running nodejs proxied in nginx. The problem I have is that I currently don't run nodejs under the root (/) but under /data as nginx should handle the static requests as normal. nodejs should not have to know that it's under /data but it seems to be required.

In other words. I want nodejs to "think" it runs at /. Is that possible?

nginx config:

upstream app_node {
    server 127.0.0.1:3000;
}

server {
...

     location /data {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_set_header X-NginX-Proxy true;

            proxy_pass http://app_node/data;
            proxy_redirect off;
    }
}

nodejs code:

exports.routes = function(app) {
    // I don't want "data" here. My nodejs app should be able to run under
    // any folder
    app.get('/data', function(req, res, params) {
            res.writeHead(200, { 'Content-type': 'text/plain' });
            res.end('app.get /data');
    });
    // I don't want "data" here either
    app.get('/data/test', function(req, res, params) {
            res.writeHead(200, { 'Content-type': 'text/plain' });
            res.end('app.get /data/test');
    });
};
Problem courtesy of: Asken

Solution

I think this solution may be better (if you are using something like Express OR something similar that uses the "middleware" logic):

Add a middleware function to change the url like so

rewriter.js

module.exports = function temp_rewrite() {
  return function (req, res, next) {
    req.url = '/data' + req.url;
    next();
  }
}

In your Express app do like so:

app.config

// your configuration
app.configure(function(){
  ...
  app.use(require('./rewriter.js').temp_rewrite());
  ...
});

// here are the routes
// notice you don't need to write '/data' in front anymore all the time

app.get('/', function (req, res) {
  res.send('This is actually site.com/data/');
});

app.get('/example', function (req, res) {
  res.send('This is actually site.com/data/example')
});
Solution courtesy of: alessioalex

Discussion

Solutions:

  • Write your app to look for the directory on the command line. Pass the directory on the command line when you run the app.

  • Write your app to look for the directory in a specific environment variable. Set the environment variable first when you run the app.

  • Write your app to assume its current directory is the intended directory. Change into the directory first when you run the app.

  • Write your app to step up the directory tree looking for a known file (e.g., step up the directory looking for ./app2.js, and then the directory in which that file is found is the intended directory).

Discussion courtesy of: yfeldblum

Temporary solution: Not ideal to me but it'll have to due for now as I can at least configure it. I'm starting the node server using:

node app2.js /data

Code to handle the root node:

exports.routes = function(app) {
    var me = this;

    // get the root path
    me.proxyRootPath = process.argv[2];

    // using the proxyRootPath to answer to the correct request
    app.get(me.proxyRootPath, function(req, res, params) {
            res.writeHead(200, { 'Content-type': 'text/plain' });
            res.end('app.get /data');
    });
    // using the proxyRootPath to answer to the correct request
    app.get(me.proxyRootPath + '/test', function(req, res, params) {
            res.writeHead(200, { 'Content-type': 'text/plain' });
            res.end('app.get /data/test');
    });
};
Discussion courtesy of: Asken

I normally do this:

nginx config:

upstream app_node {
  server 127.0.0.1:3000;
}

server {
  ...
  location /data/ {
    ...
    proxy_pass http://app_node
    rewrite ^/data/(.*)? /$1 break;
  }
}

node.js app:

app.get('/something', function(req, res, next) {
  ...
});

Then from the outside world I could make a request such as http://my-host-name/data/something?someKey=someValue, which nginx will pass over to the node.js app, who will only see it as /something?someKey=someValue (since the url was rewritten).

I know this isn't the only approach, but imo among the better ones, as I always respect the philosophy of "things that do one thing and do it well". Here, Nginx is good at rewriting URLs, whereas Node.js is good at handling the requests themselves.

Discussion courtesy of: Khang

This recipe can be found in it's original form on Stack Over Flow.