meteor/node-http-proxy

Name: node-http-proxy

Owner: Meteor

Description: A full-featured http proxy for node.js

Created: 2013-06-07 18:03:47.0

Updated: 2015-09-04 09:22:19.0

Pushed: 2014-12-04 23:48:52.0

Homepage: http://github.com/nodejitsu/node-http-proxy

Size: 1471

Language: JavaScript

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

node-http-proxy Build Status

Battle-hardened node.js http proxy
Features
When to use node-http-proxy

Let's suppose you were running multiple http application servers, but you only wanted to expose one machine to the internet. You could setup node-http-proxy on that one machine and then reverse-proxy the incoming http requests to locally running services which were not exposed to the outside network.

Installing npm (node package manager)
 https://npmjs.org/install.sh | sh
Installing node-http-proxy
install http-proxy
Using node-http-proxy

There are several ways to use node-http-proxy; the library is designed to be flexible so that it can be used by itself, or in conjunction with other node.js libraries / tools:

  1. Standalone HTTP Proxy server
  2. Inside of another HTTP server (like Connect)
  3. In conjunction with a Proxy Routing Table
  4. As a forward-proxy with a reverse proxy
  5. From the command-line as a long running process
  6. customized with 3rd party middleware.

In each of these scenarios node-http-proxy can handle any of these types of requests:

  1. HTTP Requests (http://)
  2. HTTPS Requests (https://)
  3. WebSocket Requests (ws://)
  4. Secure WebSocket Requests (wss://)

See the examples for more working sample code.

Setup a basic stand-alone proxy server
http = require('http'),
httpProxy = require('http-proxy');

reate your proxy server

Proxy.createServer(9000, 'localhost').listen(8000);


reate your target server

.createServer(function (req, res) {
s.writeHead(200, { 'Content-Type': 'text/plain' });
s.write('request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2));
s.end();
isten(9000);
Setup a stand-alone proxy server with custom server logic
http = require('http'),
httpProxy = require('http-proxy');


reate a proxy server with custom application logic

Proxy.createServer(function (req, res, proxy) {

 Put your custom server logic here

oxy.proxyRequest(req, res, {
host: 'localhost',
port: 9000
;
isten(8000);

.createServer(function (req, res) {
s.writeHead(200, { 'Content-Type': 'text/plain' });
s.write('request successfully proxied: ' + req.url +'\n' + JSON.stringify(req.headers, true, 2));
s.end();
isten(9000);
Setup a stand-alone proxy server with latency (e.g. IO, etc)
http = require('http'),
httpProxy = require('http-proxy');


reate a proxy server with custom application logic

Proxy.createServer(function (req, res, proxy) {

 Buffer the request so that `data` and `end` events
 are not lost during async operation(s).

r buffer = httpProxy.buffer(req);


 Wait for two seconds then respond: this simulates
 performing async actions before proxying a request

tTimeout(function () {
proxy.proxyRequest(req, res, {
  host: 'localhost',
  port: 9000, 
  buffer: buffer
});      
 2000);
isten(8000);

.createServer(function (req, res) {
s.writeHead(200, { 'Content-Type': 'text/plain' });
s.write('request successfully proxied: ' + req.url +'\n' + JSON.stringify(req.headers, true, 2));
s.end();
isten(9000);
Proxy requests within another http server
http = require('http'),
httpProxy = require('http-proxy');


reate a new instance of HttProxy to use in your server

proxy = new httpProxy.RoutingProxy();


reate a regular http server and proxy its handler

.createServer(function (req, res) {

 Put your custom server logic here, then proxy

oxy.proxyRequest(req, res, {
host: 'localhost',
port: 9000
;
isten(8001);

.createServer(function (req, res) {
s.writeHead(200, { 'Content-Type': 'text/plain' });
s.write('request successfully proxied: ' + req.url +'\n' + JSON.stringify(req.headers, true, 2));
s.end();
isten(9000); 
Proxy requests using a ProxyTable

A Proxy Table is a simple lookup table that maps incoming requests to proxy target locations. Take a look at an example of the options you need to pass to httpProxy.createServer:

options = {
uter: {
'foo.com/baz': '127.0.0.1:8001',
'foo.com/buz': '127.0.0.1:8002',
'bar.com/buz': '127.0.0.1:8003'


The above route table will take incoming requests to 'foo.com/baz' and forward them to '127.0.0.1:8001'. Likewise it will take incoming requests to 'foo.com/buz' and forward them to '127.0.0.1:8002'. The routes themselves are later converted to regular expressions to enable more complex matching functionality. We can create a proxy server with these options by using the following code:

proxyServer = httpProxy.createServer(options);
yServer.listen(80);
Proxy requests using a 'Hostname Only' ProxyTable

As mentioned in the previous section, all routes passes to the ProxyTable are by default converted to regular expressions that are evaluated at proxy-time. This is good for complex URL rewriting of proxy requests, but less efficient when one simply wants to do pure hostname routing based on the HTTP 'Host' header. If you are only concerned with hostname routing, you change the lookup used by the internal ProxyTable:

options = {
stnameOnly: true,
uter: {
'foo.com': '127.0.0.1:8001',
'bar.com': '127.0.0.1:8002'


Notice here that I have not included paths on the individual domains because this is not possible when using only the HTTP 'Host' header. Care to learn more? See RFC2616: HTTP/1.1, Section 14.23, “Host”.

Proxy requests using a 'Pathname Only' ProxyTable

If you dont care about forwarding to different hosts, you can redirect based on the request path.

options = {
thnameOnly: true,
uter: {
'/wiki': '127.0.0.1:8001',
'/blog': '127.0.0.1:8002',
'/api':  '127.0.0.1:8003'


This comes in handy if you are running separate services or applications on separate paths. Note, using this option disables routing by hostname entirely.

Proxy requests with an additional forward proxy

Sometimes in addition to a reverse proxy, you may want your front-facing server to forward traffic to another location. For example, if you wanted to load test your staging environment. This is possible when using node-http-proxy using similar JSON-based configuration to a proxy table:

proxyServerWithForwarding = httpProxy.createServer(9000, 'localhost', {
rward: {
port: 9000,
host: 'staging.com'


yServerWithForwarding.listen(80);

The forwarding option can be used in conjunction with the proxy table options by simply including both the 'forward' and 'router' properties in the options passed to 'createServer'.

Listening for proxy events

Sometimes you want to listen to an event on a proxy. For example, you may want to listen to the 'end' event, which represents when the proxy has finished proxying a request.

httpProxy = require('http-proxy');

server = httpProxy.createServer(function (req, res, proxy) {
r buffer = httpProxy.buffer(req);

oxy.proxyRequest(req, res, {
host: '127.0.0.1',
port: 9000,
buffer: buffer
;


er.proxy.on('end', function () {
nsole.log("The request was proxied.");


er.listen(8000);

It's important to remember not to listen for events on the proxy object in the function passed to httpProxy.createServer. Doing so would add a new listener on every request, which would end up being a disaster.

Using HTTPS

You have all the full flexibility of node-http-proxy offers in HTTPS as well as HTTP. The two basic scenarios are: with a stand-alone proxy server or in conjunction with another HTTPS server.

Proxying to HTTP from HTTPS

This is probably the most common use-case for proxying in conjunction with HTTPS. You have some front-facing HTTPS server, but all of your internal traffic is HTTP. In this way, you can reduce the number of servers to which your CA and other important security files are deployed and reduce the computational overhead from HTTPS traffic.

Using HTTPS in node-http-proxy is relatively straight-forward:

fs = require('fs'),
http = require('http'),
https = require('https'),
httpProxy = require('http-proxy');

options = {
tps: {
key: fs.readFileSync('path/to/your/key.pem', 'utf8'),
cert: fs.readFileSync('path/to/your/cert.pem', 'utf8')




reate a standalone HTTPS proxy server

Proxy.createServer(8000, 'localhost', options).listen(8001);


reate an instance of HttpProxy to use with another HTTPS server

proxy = new httpProxy.HttpProxy({
rget: {
host: 'localhost', 
port: 8000


s.createServer(options.https, function (req, res) {
oxy.proxyRequest(req, res)
isten(8002);


reate the target HTTPS server for both cases

.createServer(function (req, res) {
s.writeHead(200, { 'Content-Type': 'text/plain' });
s.write('hello https\n');
s.end();
isten(8000);
Using two certificates

Suppose that your reverse proxy will handle HTTPS traffic for two different domains fobar.com and barbaz.com. If you need to use two different certificates you can take advantage of Server Name Indication.

https = require('https'),
path = require("path"),
fs = require("fs"),
crypto = require("crypto");


eneric function to load the credentials context from disk

tion getCredentialsContext (cer) {
turn crypto.createCredentials({
key:  fs.readFileSync(path.join(__dirname, 'certs', cer + '.key')),
cert: fs.readFileSync(path.join(__dirname, 'certs', cer + '.crt'))
.context;



 certificate per domain hash

certs = {
obar.com":  getCredentialsContext("foobar"),
arbaz.com": getCredentialsContext("barbaz")



roxy options

options = {
tps: {
SNICallback: function (hostname) {
  return certs[hostname];
}

stnameOnly: true,
uter: {
'fobar.com':  '127.0.0.1:8001',
'barbaz.com': '127.0.0.1:8002'




reate a standalone HTTPS proxy server

Proxy.createServer(options).listen(8001);


reate the target HTTPS server

.createServer(function (req, res) {
s.writeHead(200, { 'Content-Type': 'text/plain' });
s.write('hello https\n');
s.end();
isten(8000);
Proxying to HTTPS from HTTPS

Proxying from HTTPS to HTTPS is essentially the same as proxying from HTTPS to HTTP, but you must include the target option in when calling httpProxy.createServer or instantiating a new instance of HttpProxy.

fs = require('fs'),
https = require('https'),
httpProxy = require('http-proxy');

options = {
tps: {
key: fs.readFileSync('path/to/your/key.pem', 'utf8'),
cert: fs.readFileSync('path/to/your/cert.pem', 'utf8')

rget: {
https: true // This could also be an Object with key and cert properties




reate a standalone HTTPS proxy server

Proxy.createServer(8000, 'localhost', options).listen(8001);


reate an instance of HttpProxy to use with another HTTPS server

proxy = new httpProxy.HttpProxy({ 
rget: {
host: 'localhost', 
port: 8000,
https: true



s.createServer(options.https, function (req, res) {
oxy.proxyRequest(req, res);
isten(8002);


reate the target HTTPS server for both cases

s.createServer(options.https, function (req, res) {
s.writeHead(200, { 'Content-Type': 'text/plain' });
s.write('hello https\n');
s.end();
isten(8000);
Middleware

node-http-proxy now supports connect middleware. Add middleware functions to your createServer call:

Proxy.createServer(
quire('connect-gzip').gzip(),
00, 'localhost'
sten(8000);

A regular request we receive is to support the modification of html/xml content that is returned in the response from an upstream server.

Harmon is a stream based middleware plugin that is designed to solve that problem in the most effective way possible.

Proxying WebSockets

Websockets are handled automatically when using httpProxy.createServer(), however, if you supply a callback inside the createServer call, you will need to handle the 'upgrade' proxy event yourself. Here's how:

options = {
....


server = httpProxy.createServer(
callback/middleware, 
options


er.listen(port, function () { ... });
er.on('upgrade', function (req, socket, head) {
server.proxy.proxyWebSocketRequest(req, socket, head);

If you would rather not use createServer call, and create the server that proxies yourself, see below:

http = require('http'),
httpProxy = require('http-proxy');


reate an instance of node-http-proxy

proxy = new httpProxy.HttpProxy({
rget: {
host: 'localhost',
port: 8000



server = http.createServer(function (req, res) {

 Proxy normal HTTP requests

oxy.proxyRequest(req, res);


er.on('upgrade', function (req, socket, head) {

 Proxy websocket requests too

oxy.proxyWebSocketRequest(req, socket, head);


er.listen(8080);
with custom server logic
httpProxy = require('http-proxy')

server = httpProxy.createServer(function (req, res, proxy) {

 Put your custom server logic here

oxy.proxyRequest(req, res, {
host: 'localhost',
port: 9000
;


er.on('upgrade', function (req, socket, head) {

 Put your custom server logic here

rver.proxy.proxyWebSocketRequest(req, socket, head, {
host: 'localhost',
port: 9000
;


er.listen(8080);
Configuring your Socket limits

By default, node-http-proxy will set a 100 socket limit for all host:port proxy targets. You can change this in two ways:

  1. By passing the maxSockets option to httpProxy.createServer()
  2. By calling httpProxy.setMaxSockets(n), where n is the number of sockets you with to use.
POST requests and buffering

express.bodyParser will interfere with proxying of POST requests (and other methods that have a request body). With bodyParser active, proxied requests will never send anything to the upstream server, and the original client will just hang. See https://github.com/nodejitsu/node-http-proxy/issues/180 for options.

Using node-http-proxy from the command line

When you install this package with npm, a node-http-proxy binary will become available to you. Using this binary is easy with some simple options:

e: node-http-proxy [options] 

options should be set with the syntax --option=value

ons:
port   PORT       Port that the proxy server should run on
target HOST:PORT  Location of the server the proxy will target
config OUTFILE    Location of the configuration file for the proxy server
silent            Silence the log output from the proxy server
, --help          You're staring at it


Why doesn't node-http-proxy have more advanced features like x, y, or z?

If you have a suggestion for a feature currently not supported, feel free to open a support issue. node-http-proxy is designed to just proxy http requests from one server to another, but we will be soon releasing many other complimentary projects that can be used in conjunction with node-http-proxy.

Options
Http Proxy

createServer() supports the following options


rward: { // options for forward-proxy
port: 8000,
host: 'staging.com'

rget : { // options for proxy target
port : 8000, 
host : 'localhost',

urce : { // additional options for websocket proxying 
host : 'localhost',
port : 8000,
https: true

able : {
xforward: true // enables X-Forwarded-For

angeOrigin: false, // changes the origin of the host header to the target URL
meout: 120000 // override the default 2 minute http socket timeout value in milliseconds

Run Tests

The test suite is designed to fully cover the combinatoric possibilities of HTTP and HTTPS proxying:

  1. HTTP –> HTTP
  2. HTTPS –> HTTP
  3. HTTPS –> HTTPS
  4. HTTP –> HTTPS
 test/*-test.js --spec
 test/*-test.js --spec --https
 test/*-test.js --spec --https --target=https
 test/*-test.js --spec --target=https


License

(The MIT License)

Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.