jbel406
jbel406

Reputation: 116

Multiple node.js projects with one domain name, each using path '/' as base url. Nginx & Express.js

I am successfully able to reverse proxy multiple node.js projects to different ports as in the Nginx set up below. What I am trying to accomplish however, is viewing the url as the root when it gets to the Node.js server.

For example, When someone goes to mydomain.com/projects/music_player, is it possible to have the Express application view the request url as just '/' instead of '/projects/music_player'.

My current Nginx setup, and Express configuration example are as follows.

Nginx:

server {
        listen 80;

        server_name mydomain_name.com;

        location /  {
                proxy_pass http://localhost:8080;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
        }

        location /projects/music_player/ {
                proxy_pass http://localhost:8000;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
        }
}

I want to do this:

app.get("/", function (req, res) {
        res.sendFile("index.html");
});

app.listen(8000);

Instead of this:

app.get("/projects/music_player", function (req, res) {
        res.sendFile("index.html");
});

app.listen(8000);

I am not sure if that is even possible. The reason is that I would like each of my node node.js/express applications to be deployable as standalone applications, without restructuring the code. I am trying to avoid having a bunch of domain names for each project, plus I think it would be pretty cool.

Upvotes: 2

Views: 1931

Answers (2)

martriay
martriay

Reputation: 5742

Yes! Of course you can.

I think the best way to do this is to rewrite your entire program into one express app, but you say you want to avoid this.

Then I think the short way with your current setup is to make each program listen to a different port and then map routes to them in your nginx.

For example:

dog.js

app.get("/", function (req, res) {
  res.sendFile("dog.html");
});

app.listen(8001);

cat.js

app.get("/", function (req, res) {
  res.sendFile("cat.html");
});

app.listen(8002);

And finally in your nginx config file:

server {
    listen 80;

    server_name mydomain_name.com;

    location / {
        proxy_pass http://localhost:8001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

    location /cat/ {
        rewrite /cat/ / break;
        proxy_pass http://localhost:8002;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

Notice the rewrite directive, this prevents for the /cat/ location from being sent to your cat.js app that only expects the / route.

Upvotes: 2

BJacobs
BJacobs

Reputation: 122

I ran into this same problem, where I didn't want to fully restructure my backend services while wanting to change the endpoint to match others.

I ended up using node-http-proxy with http-proxy-rules. Grabbing an example from the http-proxy-rules github README, you're solution would resemble the following.

var http = require('http'),
    httpProxy = require('http-proxy'),
    HttpProxyRules = require('http-proxy-rules');

// Set up proxy rules instance
var proxyRules = new HttpProxyRules({
    rules: {
        '.*/test': 'http://localhost:8080/cool', // Rule (1)
        '.*/test2/': 'http://localhost:8080/cool2/' // Rule (2)
    },
    default: 'http://localhost:8080' // default target
});

// Create reverse proxy instance
var proxy = httpProxy.createProxy();

// Create http server that leverages reverse proxy instance
// and proxy rules to proxy requests to different targets
http.createServer(function(req, res) {

    // a match method is exposed on the proxy rules instance
    // to test a request to see if it matches against one of the specified rules
    var target = proxyRules.match(req);
    if (target) {
        return proxy.web(req, res, {
            target: target
        });
    }

    res.writeHead(500, { 'Content-Type': 'text/plain' });
    res.end('The request url and path did not match any of the listed rules!');
}).listen(6010, cb);

Happy hacking!

Upvotes: 0

Related Questions