The concept

Everyone likes watching movies (hopefully). Unfortunately sometimes we have to use a VPN for that, when we happen to be in the wrong country (by the judge of some bad company :). Up until recently I had to set up the VPN server manually and connect to it. That era was ended when I received a ESP8266 chip and decided to use it to automate the process with a push of a button.

The basic components I used for that are outlined on the picture below but very similar results can be achieved with different setup. Especially the NodeJS+Express component could be replaced with any other server. I just happened to play with NodeJS recently so I just grabbed it.

ESP+NodeJS+Vagrant
Basic components

Cloud

For the Cloud part I used the Digital Ocean dropplets. The pros are obvious: it’s very cheap and starts very fast but of course it’s possible to use any other cloud provider as long as it’s not blocked as a source of VPN (as in in the case of AWS and Amazon Prime).

Vagrant

On my home server I used Ubuntu but it can be any Linux from Slackware to Proteus ;). Vagrant was used to setup and configure the box:

Download vagran http://www.vagrantup.com/downloads

apt-get install libz-dev
vagrant plugin install vagrant-digitalocean
vagrant box add digital_ocean https://github.com/smdahlen/vagrant-digitalocean/raw/master/box/digital_ocean.box
ssh-keygen
vagrant init

Then I created the following Vagrantfile (make sure to use the proper token in place of DIGITAL_OCEAN_TOKEN

  config.vm.box = "digital_ocean"
  config.ssh.private_key_path = "~/.ssh/id_rsa"
  config.vm.provider :digital_ocean do |provider,override|
    override.vm.box = 'digital_ocean'
    provider.ssh_key_name = "chrzaszczyrzewoszyce"
    override.vm.box_url = "https://github.com/smdahlen/vagrant-digitalocean/raw/master/box/digital_ocean.box"
    provider.image = 'ubuntu-14-04-x64'
    provider.token = "DIGITAL_OCEAN_TOKEN"
    provider.region = 'nyc3'
    provider.size = '512mb'
  end
 config.vm.provision :shell, path: "bootstrap.sh"

I left the rest of the file untouched. I used following tutorial for some help:

https://www.digitalocean.com/community/tutorials/how-to-use-digitalocean-as-your-provider-in-vagrant-on-an-ubuntu-12-10-vps

The only missing part was bootstrap.sh script to configure the machine to act as pptp server:

#!/usr/bin/env bash

apt-get update
apt-get install -y pptpd

echo "
localip 10.176.0.254
remoteip 10.176.0.1-100
" >> /etc/pptpd.conf

echo "
vpn pptpd vpnsecretpass *
" >> /etc/ppp/chap-secrets

echo "
ms-dns 8.8.8.8
ms-dns 8.8.4.4
" >> /etc/ppp/pptpd-options

echo "
net.ipv4.ip_forward=1
" >> /etc/sysctl.conf

echo 1 > /proc/sys/net/ipv4/conf/all/forwarding

iptables -t nat -A POSTROUTING -s 10.176.0.0/24 -j MASQUERADE

service pptpd restart

Pay attention to the following line :

echo "
vpn pptpd vpnsecretpass *
" >> /etc/ppp/chap-secrets

It defines the user (vpn) and password (vpnsecretpass). It’s worth to use something personal here :)

Once it’s all set I tested the Vagrant by issuing vagrant up. Once the server has booted I was able to conenct to it using my ipad providing the servrer’s IP address and the user and password in VPN configuration. I was happy to watch the movies but I was not happy with the procedure to start it up. Moreover I had to vagrant -f destroy once I was done with watching. I couldn’t stand that. :)

NodeJS

To overcome the need to log in via ssh and bring the vpn server up and down I created the web server  using NodeJS so I could invoke the vagrant up via a browser. First I installed nodejs:

apt-get install nodejs
ln -sf /usr/bin/nodejs /usr/bin/node
apt-get npm
npm init
npm install --save express

Then I wrote following supersimple server:

var express = require('express');

var app = express();

app.set('port', 3000);

function registerCall(url,command,args)
{
	app.get(url,function(req,res) {
		var spawn = require('child_process').spawn;
		var process = spawn(command, args);

		res.setHeader('Connection', 'Transfer-Encoding');
		res.setHeader('Content-Type', 'text/html; charset=utf-8');
		res.setHeader('Transfer-Encoding', 'chunked');
		res.write(url+"");

		writeData=function (data) {
			var str = data.toString();
			console.log(str);
			str = str.replace(/[\n\r]/gm,"");
			res.write(str);
		}

		process.stdout.setEncoding('utf8');
		process.stdout.on('data',writeData);

		process.stderr.setEncoding('utf8');
		process.stderr.on('data', writeData);

		process.on('close',function(code) {
			console.log('process exit code ' + code);
			res.setTimeout(1);
		});
	});
}

registerCall('/vagrantUp', 'vagrant', ['up']);
registerCall('/vagrantStatus', 'vagrant', ['status']);
registerCall('/vagrantDestroy', 'vagrant', ['destroy', '-f']);

app.get('/',function(req,res) {
	res.writeHead(200, {'Content-Type': 'text/plain'})
	res.write('GO AWAY!\n');
	res.end('AWAY!');
});

app.use(function(req, res) {
	res.type('text/plain');
	res.status(404);
	res.send('404 - Not Found');
});

app.use(function(err, req, res, next) {
	console.error(err.stack);
	res.type('text/plain');
	res.status(500);
	res.send('500 - Server Error');
});

app.listen(app.get('port'),function() {
	console.log('Started on port '+app.get('port')+'.');
});

Now I was able to start and stop my droplet using just a web browser and invoking http://MY_SERV_IP:3000/vagrantUP or http://MY_SERV_IP:3000/vagrantDestroy.

NodeMCU

For the last part I used the NodeMCU board because it has a build in LED and a button. LED is useful to show some status beside transferring the data while for the button I planed very important function to start (and stop) my server.

IMG_1246-0

Advertisements