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.
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'm trying to call some API, and currently my server make request for firewall, and I need to set proxy to pass, because the with proxy works perfectly and for security reason's the Company can't release the firewall for me.
Summary: How to call this API setting my proxy server with code in my server to all requests using proxy?
I try use express-http-proxy and http-proxy and I try:
require('dotenv').config({silent: true});
var httpProxy = require('http-proxy');
var server = require('./app', httpProxy.createServer(function (req, res, proxy) {
var buffer = httpProxy.buffer(req);
proxy.proxyRequest(req, res, {
host: 'pxdproxy.com',
port: 8080,
buffer: buffer
});
});
var port = process.env.PORT || process.env.VCAP_APP_PORT || 443;
server.listen(port, function() {
// eslint-disable-next-line
console.log('Server running on port: %d', port);
});
and my call for API:
var conversation = watson.conversation({
url: 'https://gateway.watsonplatform.net/conversation/api',
username: 'xxxxxxxxxxxxxxxxxxxxx',
password: 'xxxxxxxxxxxxxxxxxxxxxxx',
version_date: '2017-12-03',
version: 'v1',
});
I need to call the Conversation API with proxy set.
The SDK you are using to call the Watson API from Node.JS uses the request library.
In order to use a proxy to call the services, you just need to define an environment variable called HTTPS_PROXY.
Based on your example you will use:
HTTPS_PROXY=pxdproxy.com:8080
More information here.
These are the versions of node and required modules I am using:
Node.js: 0.10.16
Websocket Library: einaros/ws ws#0.4.28
Proxy server: nodejitsu/node-http-proxy http-proxy#0.10.3
When I run the following program my console output looks like this, and doesn't move beyond this point:
$ node app.js
proxy: got upgrade, proxying web request
wss: got connection
Here's the code:
// app.js
// A simple proxying example
//
// Setup websocket server on port 19000
// Setup proxy on port 9000 to proxy to 19000
// Make a websocket request to 9000
//
var WebSocket = require('ws'),
WebSocketServer = WebSocket.Server,
proxy = require('http-proxy');
// goes in a loop sending messages to the server as soon as
// the servers are setup
var triggerClient = function() {
var ws = new WebSocket('ws://localhost:9090/');
ws.on('open', function() {
console.log('ws: connection open');
setInterval(function() {
ws.send("Hello");
}, 1000);
});
ws.on('message', function(data) {
console.log('ws: got ' + data);
});
}
// setup websocket server and a proxy
//
var go = function() {
// setup a websocket server on port 19000
//
var wss = new WebSocketServer({ port: 19000 });
wss.on('connection', function(ws) {
console.log('wss: got connection');
ws.on('message', function(data) {
console.log('wss: got ' + data);
ws.send('wss response: ' + data);
});
});
// setup a proxy server
var server = proxy.createServer(function (req, res, proxy) {
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 19000
});
});
server.on('upgrade', function (req, socket, head) {
console.log('proxy: got upgrade, proxying web request');
server.proxy.proxyWebSocketRequest(req, socket, head, {
host: 'localhost',
port: 19000
});
});
server.listen(9090, triggerClient);
};
process.nextTick(go);
My problem eventually started when I was trying to use hipache, I then simplified things to node-http-proxy and then finally to this piece of code.
If you change the port the WebSocket client is connecting to from 9090 to 19000 (thereby bypassing the proxy), things seem to work fine.
Any suggestions, pointers, feedback would be greatly appreciated.
Thanks!
The core problem is that the master branch of node-http-proxy is only compatible with node <= 0.8.x (see https://github.com/nodejitsu/node-http-proxy#when-to-use-node-http-proxy): there's a tree that implements support for 0.10.x (see https://github.com/nodejitsu/node-http-proxy/tree/caronte) but it isn't the mainline branch and I haven't found any indication of when it will be merged in and available.
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);
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.