Archive for the Home Server Category

Dynamic DNS IP updating with node.js

November 25, 2011

My situation isn’t an unusual one – I’ve got a server at home that I want to expose to the internet, but my ISP provides me with a dynamic IP address that changes every time my router reconnects. This doesn’t happen often (maybe once a month or so), but if it does change I still want to be able to access my machine remotely.

The usual course of action is to use a free service such as DynDNS – you choose a subdomain on one of the many domain names they have, and using any one of a number of software tools, you ping them whenever your IP changes. This works pretty well – in fact, my router (like many) has built-in support for DynDNS so the router itself will notify DynDNS when the IP address changes.

So why am I doing something different? Well, I’ve actually been using DynDNS for a few years, and there are a couple of downsides (all of these apply to their free service, and I’m sure you can remove these limitations by paying, but I’m too tight to do that):

  1. You have to use one of their subdomains, and then CNAME your DNS to it – actually there’s not much wrong with this, but I’d rather not have their subdomain in my DNS resolution track;
  2. You can’t ping them too frequently or they get sad (and cut you off), so you need to be sure you can tell when your IP has changed;
  3. If you don’t ping them often enough, you risk your account being suspended until you manually log in and reactivating it – this happened to me recently when my IP hadn’t changed for a few months.

But actually, none of the things I’ve just listed are persuasive enough to not use it. So again, why am I doing something different?

  1. I want my server, not my router, to be in charge of updating the DNS – no concrete reason for this, other than that I feel it’s logic that ought to be on my server where I can track/monitor/etc it more easily;
  2. I run my own DNS service on my VPS anyway, so I want to have control over all of it, not just all except the dynamic IP bit;
  3. Because I can.

And that’s pretty much the main reason – simply because I can. I just fancy having a go at it myself. Oh, and it’s another excuse to use node.js.

So, let’s set the scene:

  • Both my home server and VPS run node.js and nginx;
  • My VPS is using named/bind9 for DNS;
  • I want my home server to use a subdomain of the VPS domain, but with its own zone file so it can have “sub-subdomains” (e.g. *.home.matt-knight.co.uk).

There are loads of ways to do this, but I’ve been meaning to have a play around with is SSL client certificates, so I’m going to use them for this. I’ve looked at using SSL client certification for API authentication in the past, but never got round it it. Basically, when a client makes an HTTPS request, it provides a certificate and key to identify (authenticate and authorize) itself.

The plan is as follows:

  1. Create an SSL CA certificate, a server certificate and a client key;
  2. Set up a new SSL host in nginx on the VPS using the aforementioned SSL certificate;
  3. Enable (and enforce) client SSL certificate authentication in nginx;
  4. Expose a node.js app on the VPS running an HTTP server which will update the bind zone file and reload it;
  5. Write a node.js app to run on my home server and ping the VPS SSL endpoint at regular intervals – for example, once a minute.

As I say, there are probably certainly easier ways to do this (well, ultimately just use DynDNS!) but this should be fun! We’ll start with the SSL certificates.

SSL Certificates & Keys

A quick search on Google found Nathan Good’s web page: Client Side Certificate Auth in Nginx

Combining that with the nginx documentation on the HTTP SSL module, I created my certificates and removed the passphrase (this is important, otherwise you’ll have to enter the passphrase every time nginx is started). The code snippets below are copied from Nathan’s site, but also include extra steps to remove the passphrases – I also changed the signing to last for 10 years (3650 days) not 1 year (365 days) because it’s fine in this case.

Note, when you’re creating the server certificate, you should set the Common Name (CN) to the SSL host you’re going to use in nginx (e.g. dnsping.example.com). When you’re creating the client certificate, you should set the Common Name (CN) to the hostname you want to set an IP for (e.g. home.matt-knight.co.uk in my case) – you’ll see why later on.

# Create the CA Key and Certificate for signing Client Certs
openssl genrsa -des3 -out ca.key 4096
openssl req -new -x509 -days 365 -key ca.key -out ca.crt

# Remove the passphrase from the CA key
cp ca.key ca.key.org
openssl rsa -in ca.key.org -out ca.key
unlink ca.key.org

# Create the Server Key, CSR, and Certificate
openssl genrsa -des3 -out server.key 1024
openssl req -new -key server.key -out server.csr

# Remove the passphrase from the server key
cp server.key server.key.org
openssl rsa -in server.key.org -out server.key
unlink server.key.org

# Self-sign the server certificate
openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

# Create the Client Key and CSR
openssl genrsa -des3 -out client.key 1024
openssl req -new -key client.key -out client.csr

# Remove the passphrase from the client key
cp client.key client.key.org
openssl rsa -in client.key.org -out client.key
unlink client.key.org

# Sign the client certificate with our CA cert.  Unlike signing our own server cert, this is what we want to do.
openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt

Now we’ve got our certificates and keys. The client certificate/key need to be on my home server, and the server certificate/key and CA certificate need to be on my VPS. Obviously all of the keys need to be kept safe. Next, it’s time to set up nginx.

Configuring nginx

All we really need to do here is to create a new SSL host.

upstream dnsping {
    server unix:/tmp/dnsping.socket; # our node.js app will listen on this socket - /tmp/dnsping.socket is just an example
}

server {
    listen 443 ssl;

    server_name dnsping.example.com; # change this to your real hostname

    access_log /var/log/nginx/access.log; # change this to wherever you want to store access logs
    error_log /var/log/nginx/error.log;   # change this to wherever you want to store error logs

    ssl_certificate        /etc/nginx/ssl/server.crt;
    ssl_certificate_key    /etc/nginx/ssl/server.key;
    ssl_client_certificate /etc/nginx/ssl/ca.crt;
    ssl_verify_client      on; 

    location / {
        include proxy_params;

        proxy_pass http://dnsping/; # this references the upstream defined above

        proxy_set_header X-Verified $ssl_client_verify;
        proxy_set_header X-DN $ssl_client_s_dn;
    }
}

You can run nginx -t to make sure it is all valid, and then tell nginx to reload the config:

kill -HUP `cat /var/run/nginx.pid`

So, what is nginx going to do?

  1. It will listen for requests to https://dnsping.example.com;
  2. It will check for the presence of a valid SSL client certificate and reject the request if not found;
  3. It will set a header of X-Verified: SUCCESS if all is good;
  4. It will set the SSL Distinguished Name (DN) into a X-DN header;
  5. It will then forward the request to a UNIX socket at /tmp/dnsping.socket

That wasn’t too hard was it! Now onto the node.js app that will run on the VPS and listen to /tmp/dnsping.socket.

Next time….

Tags: , , ,

Graphite, nginx and supervisord

November 20, 2011

In case you haven’t met it before, Graphite is a really nice real-time graphing tool. It’s simple to add data into it, and it has a nice web-interface for viewing the graphs. Think Cacti, but 10x easier to use and prettier. Graphite uses a custom data store called Whisper (rather than RRDTool which Cacti is based on) which makes it really easy to just push data into it whenever you want. Installation it is also fairly easy – just follow the (recently much improved) documentation on the Graphite site.

It comes with a development server that you can use to play around with the web interface, although it is stressed in the documentation that it is only a development server, and you really should be using Apache and mod_python. And that’s a bit annoying, because I wanted to use nginx for some other things on my system, so I don’t want Apache stealing port 80.

Read the remainder of this entry »

Eos is Born

November 20, 2011

Having been thinking about doing it for a number of years but never getting round to it, I’ve finally gone and bought myself a home server – an HP ProLiant Microserver. For £250 (and then £100 cashback from HP as well), the specification is pretty good:

  • Dual Core AMD Turion II Neo N40L @ 1.5 GHz
  • 2GB RAM
  • 250GB Seagate Barracuda HDD
  • 3 free 3.5″ S-ATA bays
  • 1 free 5.25″ optical bay

I’ve put 2 Samsung Spinpoint F3 1TB drives in it (just over £100 each), in a RAID 1 (mirrored) array. My plan was to put an DVD drive from an old machine into it, but it turns out that it doesn’t have an IDE connector for an optical drive – an oversight on my part there! I installed the 64-bit version of Ubuntu Server 11.10 from a USB drive and that was all I really planned to use the DVD drive for anyway.

I hadn’t really thought about a name for it, but my naming convention for boxes so far has been Roman or Greek deities. I fancied something quite grand for this one, since I hope it will become the computing-cornerstone in my house. I decided to call  it Eos, the Titan goddess of the dawn – seems quite fitting for a new server. So in the style of Mark Evans, Eos is born!

Read the remainder of this entry »