Preface

If you haven’t read part 1, you should go there first. That clocked in at just over a thousand words, and I didn’t want to seem like I was going on and on, so I decided to make this a 2 parter.

Requirements

Copied and pasted from part 1.

  • Something to act as a webserver (Raspberry Pi in this example)
  • A wee bit of money for a domain ( £/$/€ 0.99 for 1st year if you choose a shitty one, but who cares!)
  • Basic networking knowledge will help

MBTODO:

  • Create no-ip hostname
  • Create GoDaddy domain
  • Make domain point towards hostname correctly
  • Access the server even if it’s behind a router
  • Install necessary stuff i.e. node, npm, etc.
  • Create a simple proof of concept server
  • Allow the server to communicate of HTTPs correctly

No ticket!

noticket

That’s right Indy. That nazi didn’t have a ticket, so sock him in the jaw and toss him off that zeppelin! This is what happens when you try to communicate over HTTPs without a valid certificate. The bad guy is (potentially) you, the ticket is the certificate which you don’t have (or you have one that’s self-signed/expired) and Indiana Jones is the HTTPs protocol. Finally, Henry Sr. is proud of his son for keeping the internet safe. You’ve seen it a million times, and you just click Advance, continue, fuck you chrome I wanna go there anyway.

2016-10-14-08_51_22

Look, the thing makes sense. You wouldn’t trust someone who clearly has a phony ID. And by phony I mean the thing says it was issued by “The office of anal retardation”. #AnalogyKing.

Tutorial

Router configuration

Let’s start off with a little router set up. If you’re not behind a router, good for you, skip this. If you are behind a router, you’re gonna wanna forward some ports.

In order to know which device we need to forward to, we need to get our Pi’s router assigned IP. So on the Pi, run ‘ifconfig’. Which gives you the screen below.

mark_—_pi_raspberrypi____—_ssh_pi_delta25er_ddns_net_—_80×24.png

You’re going to want to identify which interface is being used for data transfer. Lo is loopback, so it’s not that, and there’s only one other interface…en1. Take that thing’s inet addy, write it down, and go back to your regular machine.

Typically you’d forward 80, which is where HTTP runs, but we’re gonna do 443, which is where HTTPs runs. You could optionally do both, but I’m not doing that. Proof of concept stuff remember!

Jump to 192.168.0.x (where x is usually 0 or 1) or however you access your router, log in, and find the port-forwarding options.

Port_Range_Forwarding.png

Create a rule. Simple, we want to take communication coming in on port 443, to go to my Raspberry Pi, which has the router assigned IP 192.168.0.17, and for the data to be sent over for 443 as well. You could technically make that last one whatever you want. It’s shouldn’t matter.

These menus change from router to router, but the overall idea should be similar.

Installing Nodejs, NPM, and the necessary node modules

Where you do do your coding is your choice. I usually code on my MacBook and then SCP stuff onto my Pi. I’ll include the one liner that it takes to do that somewhere below. But this means that I need to install that stuff on both machines. Preferably with the same versions.

On Mac

If you don’t have MacPorts, find a tutorial somewhere that tells you how to set that up. Pretty straightforward.

In the terminal: ‘sudo port install nodejs’

let that finish

In the terminal: ‘sudo port install npm’

DONE

On your server (linux in my case)

Look, this destroyed me. I was on the verge of tears trying to get this to work. I have a Master’s degree in computer science, and this is the one thing that almost destroyed me from the inside out.

Using ‘sudo apt-get install nodejs’ wasn’t cutting it. I was getting an older version, npm didn’t work (correctly) and I just understand what the hell was going on. 2 stackoverflow answers later, and I was worse off. Finally, I asked my own question, and a certain Luis González became my absolute hero when he recommended using NVM to aid the installation process.

If you’ve tried doing this by yourself already, remove them… ‘sudo apt-get purge nodejs npm’

#Install NVM
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.3/install.sh | bash

Restart your terminal so stuff can take effect. I just go for the good old ‘sudo reboot’, because I aint afraid of you.

Now, we’re gonna see what versions are available, and install one of them. Since I had 4.6 on my Mac, I wanted to install that to keep everything in sync, but do whatever makes you happy.

nvm ls-remote
nvm install 4.6.0

And done.

However, since we’re going to be using ports which are under 1024, and therefore require SU access, we need to change the access permissions to some stuff. Run this:

n=$(which node)
n=${n%/bin/node}
chmod -R 755 $n/bin/*
sudo cp -r $n/{bin,lib,share} /usr/local

Ok, now we’re done. If you’re having problems, look at my question here or the NVM wiki here.

Initiating the node project

You do this on both of your machines, but especially on your server, because that’s where we’re running the actual server.

Go to your directory, and run ‘npm init’.

Go ahead and open up your package.json file and set some stuff. Self explanatory. Here’s mine as a guide.

mark_—_pi_raspberrypi____NFLScoresServer_—_ssh_pi_delta25er_ddns_net_—_136×48.png

That easy. NEEEEXT

Installing the necessary node modules

You do this on both of your machines, but especially on your server, because that’s where we’re running the actual server (copy and paste because time is money). There is a wee bit of duplication happening below, and I ran into one pesky error. One at a time…

The duplication isn’t something I give much thought to. We’re going to use the github project letsencrypt-express, which also includes the necessary letsencrypt modules for HTTPs challenges and whatnot (I don’t explain this here…google does a good job). For some reason, when I was running my project, it couldn’t find them. So i just re-downloaded what I needed. I have to reiterate and re-stress my philosophy about some stuff. If it works, it works. I know it might not be perfect, but this isn’t an exam. Improving it all comes later.

The second and more serious issue, was that I’m running a rather old version of Debian, and I had no interest in upgrading. However, this also meant that I was running an old version of the GCC compiler, and was getting quite a few errors.

(This blog post is now longer than last week’s)

This gentleman here, helped me fix that.

A third minor issue, is that you require Python 2. I have 2.7.

In this tutorial I’m merely creating something that returns hello world, but in the next blog post we’ll be creating the REST endpoints to go with it. So I go ahead and include those here, marked optional. This is the list of stuff which I installed:

For each of those, you’re going to want to run:

sudo npm install --save module_name_here

And the setup is all done as well. WONDERFUL!

Creating a simple webserver

Here’s a block of code that creates the simple server. You can just copy and paste this, but please remember to set your domains (array of strings) and your email address (string).
P.s. This went in my index.js file.

var lex = require('letsencrypt-express').create({
  // NOTE, server should be set to 'https://acme-v01.api.letsencrypt.org/directory' for production
  server: 'staging'
, challenges: { 'tls-sni-01': require('le-challenge-sni').create({ webrootPath: '/tmp/acme-challenges' }) }
, challengeType: 'tls-sni-01'
, store: require('le-store-certbot').create({ webrootPath: '/tmp/acme-challenges' })
, approveDomains: approveDomains
});

function approveDomains(opts, certs, cb) {
  if (certs) {
    opts.domains = certs.altnames;
  }
  else {
    opts.domains = [domain];
    opts.email = email;
    opts.agreeTos = true;
  }

  cb(null, { options: opts, certs: certs });
}

var app = require('express')();
app.use('/', function (req, res) {
  res.end('Hello, World!');
});

require('https').createServer(lex.httpsOptions, lex.middleware(app)).listen(443, function () {
  console.log("Listening for ACME tls-sni-01 challenges and serve app on", this.address());
});

As I’ve been saying, I only want this to work over HTTPs, so there’s only functionality for that. Additionally, it works in such a way that ACME challenges (for certificates) only come in over port 443, since I’m using port 80 for something else, messing up the entire process. Some additional reading for you about my situation here.

The code is somewhat self explanatory, We’re setting the settings for the letsencrypt module, using letsencryt-express to give us a little help. Then (in the very last bit) we use the HTTPs module, to create a server and listen over 443, printing a fancy message when this works.

You need to know 3 things in order for that code to work for you.

  1. You need to set your domain where I have domain. Like this ‘[‘www.example.com’](that subdomain www is important)
  2. You need to set your email where I have email. Like this ‘myemail@gmail.com’
  3. This is currently using the staging server. Why? Because if you constantly ping the production one you’ll get blocked for a while (whoops). So make sure everything’s working before you switch that over. Everything you need is in that code block (lines 2 and 3).

If you want to SCP your index.js over to your Pi, you can use this:

scp index.js pi@delta25er.ddns.net:TargetDirectory/index.js

Alright, so now back on the Pi, you want to navigate to that directory, and run ‘sudo npm start’. Sudo because of port 443. This is going to run the script start which we had defined in our package.json. And you should be good to go!

Brief recap.

You also have a domain which points to another host (which handles your dynamic IP) which points to your IP. Your router’s gonna receive data (over port 443) and forward it to your PI (also on port 443), where you have a server listening on port 443, which may or may not have certificates that say it’s legit.

So technically, going to https://www.yourdomain.com (replacing stuff accordingly) should bring it up! It might fail the first time, but that’s because the certificates are being created. Refresh. You should get the this site is not safe screen. Click on the crossed out HTTPs and access the certificate. You should at least have one, and it should have an issuer. This is what we want, because we’re using the staging server.

About this staging stuff. When you use it, you’ll still get the warning that the certs are invalid. But you’ll be given something nonetheless, so you’ll know that it (your setup) is working at least. So once you do that, AND IT WORKS, delete the fake stuff the staging sent you by running the command below.

sudo rm -fr /etc/letsencrypt

Change to the production URL, run it again (sudo npm start), and access it again. Now you’ll be given actual certificates and that beautiful green padlock.

https___api_delta25_xyz.png

FIN

Advertisements