NODE as Proxy – Proxying HTTP and Websockets

Posted on Posted in linux, node

Hello and welcome to another SySadmin & DBA tips, the first thing to do is apologise for this time without blogging but I’m spending the little time I have for others projects like tweetbinder.

Ok in this post we’ll use node to create a proxy web/app server. Let’s suppose you were running multiple http services like apache, tomcat apps, node applications, etc, 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.

Like the official author says, some features:

  • Reverse proxies incoming http.ServerRequest streams
  • Can be used as a CommonJS module in node.js
  • Uses event buffering to support application latency in proxied requests
  • Reverse or Forward Proxy based on simple JSON-based configuration
  • Supports WebSockets
  • Supports HTTPS
  • Minimal request overhead and latency
  • Full suite of functional tests
  • Battled-hardened through production usage @ nodejitsu.com
  • Written entirely in Javascript
  • Easy to use API

Install node-http-proxy

Install Node

apt-get update
apt-get install git-core curl build-essential openssl libssl-dev
clone
https://github.com/joyent/node.git && cd node
./configure
make
make install
node -v

Install forever

Next, lets make it persistent using Forever, so once we logoff it still runs and will restart even if node throws an error.

npm install forever --global

Installing npm (node package manager)

curl https://npmjs.org/install.sh | sh

Installing node-http-proxy

npm install http-proxy

node-http-proxy examples

Hostname ProxyTable

When you wants routing based on the HTTP ‘Host’ header:

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

var options = {
  hostnameOnly: true,
  maxSockets: 500,
  router: {
    'albertolarripa.com': '127.0.0.1:8080',
    'albertosysadmin.com': '127.0.0.1:8181',
    'test.albertolarripa.com': '127.0.0.1:8282'
  }
}
var proxyServer = httpProxy.createServer(options).listen(80);

ProxyTable Proxy

When you wants routing based on the HTTP ‘Host’ header + target location:

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

var options = {
  maxSockets: 500,
  router: {
    'albertolarripa.com/doc': '127.0.0.1:8080',
    'albertosysadmin.com/info': '127.0.0.1:8181',
    'test.albertolarripa.com/author': '127.0.0.1:8282'
  }
}
var proxyServer = httpProxy.createServer(options).listen(80);

PathName Proxy

When you wants routing based on PathName without cate about forwarding to different hosts:

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

var options = {
  pathnameOnly: true,
  maxSockets: 500,
  router: {
    '/doc': '127.0.0.1:8080',
    '/info': '127.0.0.1:8181',
    '/author': '127.0.0.1:8282'
  }
}
var proxyServer = httpProxy.createServer(options).listen(80);

Forward traffic Proxy

If you want your front-facing/production server to forward traffic to another location. For example, If you need put maintenance your production server and not shutdown the service.

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

var proxyServerWithForwarding = httpProxy.createServer(9000, 'localhost', {
  forward: {
    port: 9000,
    host: 'cdr.albertolarripa.com'
  }
});
proxyServerWithForwarding.listen(80);

Round-Robing balancing

If you need to create a Round-Robing balancing system

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

var addresses = [
  {
    host: 'srv1.albertolarripa.com',
    port: 80
  },
  {
    host: 'srv2.albertolarripa.com',
    port: 80
  }
];

httpProxy.createServer(function (req, res, proxy) {
  var target = addresses.shift();
  proxy.proxyRequest(req, res, target);
  addresses.push(target);
});

Start the service

Test the proxy

Now test if the node script run as properly

node nodeproxy.js

init.d

Configure the startup script

#!/bin/bash
### BEGIN INIT INFO
# Provides:             nodeproxy
# Required-Start:       $syslog $remote_fs
# Required-Stop:        $syslog $remote_fs
# Should-Start:         $local_fs
# Should-Stop:          $local_fs
# Default-Start:        2 3 4 5
# Default-Stop:         0 1 6
### END INIT INFO
#

NAME="nodeproxy"
NODE_BIN_DIR="/usr/bin"
NODE_PATH="/usr/local/etc/node_proxy/node_modules"
APPLICATION_DIRECTORY="/usr/local/etc/node_proxy"
APPLICATION_START="nodeproxy.js"
LOG="/var/log/nodeproxy.log"
NODE_ENV="production"
PIDFILE="/tmp/nodeproxy.pid"
export HOME="/tmp"
export NODE_PATH=$NODE_PATH

start() {
    PATH=$NODE_BIN_DIR:$PATH
    PATH=$NODE_BIN_DIR:$PATH
    echo "Starting $NAME"
    exec forever --pidFile $PIDFILE --sourceDir $APPLICATION_DIRECTORY -a -l $LOG \
         --minUptime 5000 --spinSleepTime 2000 start $APPLICATION_START &
    RETVAL=$?
}

stop() {
    PATH=$NODE_BIN_DIR:$PATH
 if [ -f $PIDFILE ]; then
    echo "Shutting down $NAME"
    exec forever stop $APPLICATION_START >> $LOG
    rm -f $PIDFILE
    RETVAL=$?
 else
        echo "$NAME is not running."
        RETVAL=0
 fi
}

restart() {
    echo "Restarting $NAME"
    stop
    start
}

status() {
    echo "Status for $NAME:"
    exec forever list
    RETVAL=$?
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    status)
        status
        ;;
    restart)
        restart
        ;;
    *)
        echo "Usage: {start|stop|status|restart}"
        exit 1
        ;;
esac
exit $RETVAL

And finally start the service

# /etc/init.d/nodejs_proxy start
Starting nodejs_proxy
# info:    Forever processing file: nodejs_proxy.js

Leave a Reply

Your email address will not be published. Required fields are marked *