Pi Day Project

The idea is thus:  I and my wife have several development sites internal to our network that we, at times, want to show to customers, relatives or friends (you know just to show off) and were in need of a way to make these sites publicly available.  Sure we could each use separate odd/non-standard ports to serve up our local Apache instances, but what fun is that, really? 

Having had the new Rapsberry Pi 2 sitting around for a couple of days and itch to play around with Node.js I decided I would combine the two in to a project for the upcoming Pi Day.  

To begin the journey you'll need a Raspberry Pi with all the accoutrements: a power supply, SD card, network cable, monitor (although this is only needed for a short period).  Now you'll need to decide upon a Pi distro.  You can use pretty much any distro, but I'd recommend Raspbian.  I won't cover the installation of the distro in this article as it is well covered elsewhere and will assume you have a viable distro.

Ok, let's dig in to the Pi.  Yep, there will likely be more Pi puns.

We are going to need the IP of our Pi to be static so to begin we will edit /etc/network/interfaces.  I am using a wired connection, and recommend you do the same, so I will be editing the entry for eth0.  If you're using a wireless dongle you will need to edit he wlan0 entry. 

From the start your entry for eth0 will likely look exactly like:

iface eth0 inet dhcp

We are going to change that to:

iface eth0 inet static
address 192.168.1.15
netmask 255.255.255.0
broadcast 192.168.1.255
gateway 192.168.1.1

Much of the above is self explanatory, however, what we have done here is to change the dhcp to static and added the four lines below that to specify the address we want to always use, the netmask of the network, the broadcast address, and the gateway.  Your entries and ip will vary. If you need assistance determining what these values should be take a look at the howto over at eLinux.org

Right then, time for some jam, ok not really.  Now it is time to install Node.js.  I'll say here that there are apt packages for node, however, I went the rugged route and compiled node from scratch.  I have not tested my setup with the pre-compiled apt packages, but suspect it would work. I, however, am a glutton for punishment, so again I compiled, and here is how to do that:

From the terminal:

pi@raspberrypi ~/ $ git clone git://github.com/ry/node.git 
pi@raspberrypi ~/reverseProxy $ cd node 
pi@raspberrypi ~/reverseProxy $ ./configure 
pi@raspberrypi ~/reverseProxy $ make 
pi@raspberrypi ~/reverseProxy $ sudo make install

Easy as Pi...yeah, they're still coming.  But, while you're waiting for the make to finish why not go grab a cup of tea or coffee, or since it is close to St. Paddy's day, perhaps an Irish coffee.  

Once the compile finishes we are almost done.  We just need to do a few things. Let's start by creating a project directory to store our proxy.  I stored mine in /home/pi/reverseProxy. 

Go ahead and change directory to the project directory. Once inside go ahead and install http-proxy using npm:

pi@raspberrypi ~/reverseProxy $ npm i http-proxy 

Ok now for the incredibly simple reverse proxy code. Let's create a new file named server.js within our project directory with the following contents:

var http = require('http'),
    httpProxy = require('http-proxy'),
    proxy = httpProxy.createProxyServer({}),
    url = require('url'),
    port = 8080;

http.createServer(function(req, res) {
    var hostname = req.headers.host.split(":")[0];
    var pathname = url.parse(req.url).pathname;

    console.log(hostname);
    console.log(pathname);
    switch(hostname)
    {
        case 'example1.com':
            //uncomment the line below if you're using apache virtual hosts and need to change the header to reflect virtual host
            //req.headers.host = "example1.com"
            proxy.web(req, res, { target: 'http://example1.dev' });
            break;
        case 'example1.ddns.net':
            //uncomment the line below if you're using apache virtual hosts and need to change the header to reflect virtual host
            //req.headers.host = "example2.dev";
            proxy.web(req, res, { target: 'http://example2.dev' });
            break;
        case 'dmccarthy.io':
	case 'www.dmccarthy.io':
            proxy.web(req, res, { target: 'http://192.168.1.151' });
            break;
        default:
            break;
    }
}).listen(port, function() {
    console.log('proxy listening on port ' + port);
});

The code above is setting up an http_proxy server on port 8080. In the create server function we grab the requested hostname and pass it through a switch statement to determine where we should send the request to.  You might notice that in the example1 and example2 cases above there is a line there to set the request header.  I had to do this because I have several virtual hosts setup within my local Apache install and if I didn't rewrite the header here Apache would serve up the first, alphabetically, virtual host found.  

I have provided 3 examples here to give you an idea of what you can do.  You can send the request to IP, or a domain name within your network, or if the request isn't really relevant to the proxy you can ignore the request.  You will of course have to forward port 80 traffic from your router to the static IP of the Pi on port 8080. 

With the server.js saved you can start it up!  Whilst still in the project directory execute the following 

pi@raspberrypi ~/reverseProxy $ node server.js 


You should see a few messages in the console. The server started up, which port, etc. Go ahead make a request one of the sites. I will warn you now that there is no error handling in this. If the server.js errors out it is going to terminate. Yeah, I will fix that later, but for now we see everything is working. Yay!

Ok, this is great! We have our working reverse proxy, but what if the Pi is restarted? Must you be logged in to execute this code, and what happens when you logout? Well as we have it configured here you would need to be logged and upon logout the reverse proxy process would end. But fear not there is a solution. We just need to create an init script to start this on server startup.

I thought I would be writing my own init script but being the ever lazy person I am I Googled and found node-startup. This is a github project designed to specifically start node projects on machine start.  I'll let you follow along on the github page to install this script. 

Now, enjoy your Pi. Yep, that's the last one.  I've had my fill. Ok, now that was the last one.  

If you have any questions or comments feel free to leave them below or hit me up Twitter.  

2 Comments
swathichitti wrote on 04/02/2017 - 04:37am:

i want to include angular controller in node js and node js files are used in angular controller is there any possibility.


swathichitti wrote on 04/02/2017 - 04:41am:

i want to include angular controller in node js and node js files are used in angular controller is there any possibility.





Post Comment