I want to do a simple node.js reverse proxy to host multiple Node.JS applications along with my apache server on the same port 80. So I found this example here
var http = require('http')
, httpProxy = require('http-proxy');
httpProxy.createServer({
hostnameOnly: true,
router: {
'www.my-domain.com': '127.0.0.1:3001',
'www.my-other-domain.de' : '127.0.0.1:3002'
}
}).listen(80);
The problem is that I want to have for example app1.my-domain.com pointing to localhost:3001, app2.my-domain.com pointing to localhost:3002, and all other go to port 3000 for example, where my apache server will be running. I couldn't find anything in the documentation on how to have a "default" route.
Any ideas?
EDIT I want to do that because I have a lot of domains/subdomains handled by my apache server and I don't want to have to modify this routing table each time I have want to add a new subdomain.
For nearly a year, I had successfully used the accepted answer to have a default host, but there's a much simpler way now that node-http-proxy allows for RegEx in the host table.
var httpProxy = require('http-proxy');
var options = {
// this list is processed from top to bottom, so '.*' will go to
// '127.0.0.1:3000' if the Host header hasn't previously matched
router : {
'example.com': '127.0.0.1:3001',
'sample.com': '127.0.0.1:3002',
'^.*\.sample\.com': '127.0.0.1:3002',
'.*': '127.0.0.1:3000'
}
};
// bind to port 80 on the specified IP address
httpProxy.createServer(options).listen(80, '12.23.34.45');
The requires that you do NOT have hostnameOnly set to true, otherwise the RegEx would not be processed.
This isn't baked into node-http-proxy, but it's simple to code:
var httpProxy = require('http-proxy'),
http = require('http'),
addresses;
// routing hash
addresses = {
'localhost:8000': {
host: 'localhost',
port: 8081
},
'local.dev:8000': {
host: 'localhost',
port: 8082
},
'default': {
host: 'xkcd.com',
port: 80
}
};
// create servers on localhost on ports specified by param
function createLocalServer(ports) {
ports.forEach(function(port) {
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('<h1>Hello from ' + port + '</h1');
}).listen(port);
});
console.log('Servers up on ports ' + ports.join(',') + '.');
}
createLocalServer([8081, 8082]);
console.log('======================================\nRouting table:\n---');
Object.keys(addresses).forEach(function(from) {
console.log(from + ' ==> ' + addresses[from].host + ':' + addresses[from].port);
});
httpProxy.createServer(function (req, res, proxy) {
var target;
// if the host is defined in the routing hash proxy to it
// else proxy to default host
target = (addresses[req.headers.host]) ? addresses[req.headers.host] : addresses.default;
proxy.proxyRequest(req, res, target);
}).listen(8000);
If you visit localhost on port 8000 it will proxy to localhost port 8081.
If you visit 127.0.0.1 on port 8000 (which is not defined in our routing hash) it will go to the default 'location', namely xkcd.com on port 80.
Related
I've got greenlock express running well in node.js on my Windows server. However, I've added some more IP addresses to the server and find that node.js and greenlock are listening to port 443 on 0.0.0.0, thereby tieing up all the IP addresses.
How do I tell greenlock to listen to port 443 only on one specific IP address?
Is there any configuration value that I can add to this?
var greenlock = require('greenlock-express')
.init({
packageRoot: __dirname,
maintainerEmail: "....",
configDir: './greenlock.d',
cluster: false
});
That's in the examples folder https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/https/server.js
That's the folder you need to be looking at for more advanced uses.
"use strict";
// The WRONG way:
//var https = require('https');
//var httpsServer = https.createServer(tlsOptions, app);
//
// Why is that wrong?
// Greenlock needs to change some low-level http and https options.
// Use glx.httpsServer(tlsOptions, app) instead.
//require("greenlock-express")
require("../../")
.init({
packageRoot: __dirname,
configDir: "./greenlock.d",
maintainerEmail: "jon#example.com",
cluster: false
})
.ready(httpsWorker);
function httpsWorker(glx) {
//
// HTTPS 1.1 is the default
// (HTTP2 would be the default but... https://github.com/expressjs/express/issues/3388)
//
// Get the raw https server:
var httpsServer = glx.httpsServer(null, function(req, res) {
res.end("Hello, Encrypted World!");
});
httpsServer.listen(443, "0.0.0.0", function() {
console.info("Listening on ", httpsServer.address());
});
// Note:
// You must ALSO listen on port 80 for ACME HTTP-01 Challenges
// (the ACME and http->https middleware are loaded by glx.httpServer)
var httpServer = glx.httpServer();
httpServer.listen(80, "0.0.0.0", function() {
console.info("Listening on ", httpServer.address());
});
}
I saw that you left an issue (yesterday?), but I forgot to respond.
I am using the http-proxy npm module for connecting multiple servers to a single port.
I wrote the following code and it's working fine:
var http = require('http');
var httpProxy = require('http-proxy');
// Proxy Address
var proxyAddresses = [
{
host: "localhost",
port: 3001
},
{
host: "localhost",
port: 3002
}
];
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '9090');
app.set('port', port);
//Create a set of proxy servers
var proxyServers = proxyAddresses.map(function (target) {
return new httpProxy.createProxyServer({
target: target
});
});
/**
* Create HTTP server.
*/
var server = http.createServer(function(req, res){
var proxy = proxyServers.shift();
proxy.web(req, res);
proxyServers.push(proxy);
});
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port, function(){console.log("server is listening on port " + port);});
server.on('error', onError);
server.on('listening', onListening);
My problem:
If one of my servers (for example port 3002) is not started or has an error, how can I automatically redirect requests to the other available server (i.e. port 3001)?
I've been using the http-proxy-rules extension as described here: https://github.com/donasaur/http-proxy-rules
I set up some rules and it gives the option to default if the page requested doesn't exist:
var proxyRules = new HttpProxyRules({
rules: {
'.*/test': 'http://localhost:8080/cool', // Rule (1)
'.*/test2/': 'http://localhost:8080/cool2/', // Rule (2)
'/posts/([0-9]+)/comments/([0-9]+)': 'http://localhost:8080/p/$1/c/$2', // Rule (3)
'/author/([0-9]+)/posts/([0-9]+)/': 'http://localhost:8080/a/$1/p/$2/' // Rule (4)
},
default: 'http://localhost:8080' // default target
The default bit being relevant to you. There's also some code which states a message to display:
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('The request url and path did not match any of the listed rules!');
I haven't tested this extensively but certainly got the redirection if a rule wasn't matched working - might be of some help to you.
I've setup a simple HTTPS server to handle the following to situations:
Requests to https://localhost:5000/ that have a matching file in my directory are served via connect.static(__dirname). This works great for everything like my index.html and my CSS files and is working exactly as I need.
Requests to https://localhost:5000/api should redirect to https://subdomain.mydomain.com:443/api.
The proxy is properly transferring everything over HTTPS and the SSL handshake part seems to be working exactly as I would expect. The problem is that my API uses the subdomain to determine what database to connect to and what data to return. So, my API sees the request
https://localhost:5000/api/something
instead of
https://subdomain.mydomain.com/api/something
and is throwing an error telling me I have to supply the subdomain.
How can I tell the node proxy to forward (or use) the domain/subdomain when doing the proxy?
Here is my code:
var fs = require('fs');
var connect = require('connect'),
https = require('https'),
httpProxy = require('http-proxy'),
options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
},
endpoint = {
host: 'subdomain.mydomain.com',
port: 443,
prefix: '/api',
target: { https: true }
};
var proxy = new httpProxy.RoutingProxy();
var app = connect()
.use(connect.logger('dev'))
.use(function(req, res, next) {
if (req.url.indexOf(endpoint.prefix) === 0) {
proxy.proxyRequest(req, res, endpoint);
} else {
next();
}
})
.use(connect.static(__dirname));
https.createServer(options, app).listen(5000);
console.log('Listening on port 5000');
Just in case someone bumps into this old question, you should use http-proxy's changeOrigin option.
When modifying a node-http-proxy example...
The Issue: When manually changing the req.headers.host to a remote host ('example.com'), the url in the the browser is not changing.
Note: I thought this was working, however when using google.com as my example, it turned out google was detecting the proxy and changing the host.
Question: Is there a way to change the url in the browser to a remote host (ie. example.com), everytime? Thanks!
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/node-http-proxy');
//
// Http Server with proxyRequest Handler and Latency
//
var proxy = new httpProxy.RoutingProxy();
http.createServer(function (req, res) {
req.headers.host = 'example.com'; // manually setting example.com
var buffer = httpProxy.buffer(req);
setTimeout(function () {
proxy.proxyRequest(req, res, {
port: 80,
host: 'example.com',
buffer: buffer
});
}, 200);
}).listen(8004);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '8004 '.yellow + 'with proxyRequest handler'.cyan.underline + ' and latency'.magenta);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow);
A few solutions that will do this are:
Issue a 301 redirect.
Use IPTables to DNAT and change the desination address.
Use TPROXY to transparently proxy the requests without modifying the
packets.
I have written http proxy in node.js running on port 80. All I need is to redirect socket.io traffic to port 9090 and standard http traffic to Apache on 8080. This is my proxy code:
httpProxy = require('http-proxy');
httpProxy.createServer(function (req, res, proxy) {
if (req.url.match(/socket.io/)) {
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 9090
});
} else {
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 8080
});
}
}).listen(80);
Everything works, but io.socket falls back to xhr-polling.
http://localhost/client.htm - falls back to xhr-polling
file:///C:/.../client9090.htm - still uses websocket
socket.io app is running on port 9090, client.htm connects to 80 and client9090.htm connects directly to 9090.
It looks like a node-http-proxy makes socket.io app to work in xhr-polling mode.
Client is Chrome v.25
socket.io app code
var io = require('socket.io').listen(9090);
io.on('connection', function (socket) {
socket.on('hi!', function (data) {
console.log(data);
socket.emit('news');
});
socket.on('ahoj', function (data) {
console.log(data);
});
});
client.htm code
<script src="http://localhost/socket.io/socket.io.js"></script>
<script>
var chat = io.connect('http://localhost')
chat.on('connect', function () {
chat.emit('hi!');
});
chat.on('news', function () {
chat.emit('ahoj',{a:1,b:2});
});
</script>
client9090.htm is the same but localhost is replaced by localhost:9090
As I said, everythig works well, only problem is, that node-http-proxy makes to fall back from websockets to xhr-polling.
Can anyone help?
According to https://npmjs.org/package/http-proxy, when adding a callback to the httpProxy.createServer(), you have to manually proxy 'upgrade' events, so something like this:
httpProxy = require('http-proxy');
// added `var server =` here
var server = httpProxy.createServer(function (req, res, proxy) {
if (req.url.match(/socket.io/)) {
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 9090
});
} else {
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 8080
});
}
}).listen(80);
// added upgrade listener section here:
server.on('upgrade', function (req, socket, head) {
server.proxy.proxyWebSocketRequest(req, socket, head);
});
However, for the usage you described above, you don't even need the callback function - you could just as easily do something like this:
httpProxy = require('http-proxy');
var options = {
pathnameOnly: true,
router: {
'/wiki': '127.0.0.1:8001',
'/blog': '127.0.0.1:8002',
'/api': '127.0.0.1:8003'
}
}
var proxyServer = httpProxy.createServer(options);
proxyServer.listen(80);