Wednesday, September 24, 2014

Unprivileged servers over standard ports on the Raspberry Pi

Sometimes you want to be able to run network services on standard ports, but as unprivileged users. I encountered this while attempting to configure my Raspberry Pi as an easy-to-use checkers game server. The following describes how I used port forwarding via iptables to achieve this.

I wanted users to be able to access a HTML5 checkers game client simply by entering just the host name of the server into a web browser, and not hostname:port-number. This meant I needed my nodejs server to accept and serve connections on TCP port 80. However, code running as unprivileged users can only bind to ports above 1024. Rather than running the nodejs server as a privileged user, and opening the server up to more security vulnerabilities, I decided to use iptables to redirect traffic from the standard port (80) to my non-standard one (3000).

To do this on the pi, you need to:
  • Add the following to the bottom of /etc/network/interfaces:
  • Add our rules to /etc/network/iptables:
The above filter rules are minimal, and you'll probably need to augment them with additional services like ssh (port 22).

The *filter and *nat sections are actually different tables. The filter rules are intended for packet filtering, and the nat rules are for doing Network Address Translation (or NAT). The rule that rewrites the network packets, effectively redirecting the traffic for port 80 to port 3000 and back again is:

A number of articles say that you need to enable IP forwarding for the network interfaces, either via the proc filesystem or by using sysctl. However, I did not find this necessary. Despite sysctl and proc net forwarding being disabled, this iptables redirect functioned properly.

Also, it is worth noting that by default the iptables commands only show rules in the *filter table. This lead me to believe that my rules were not applied when they were. To see rules in tables other than *filter, you need to use the -t <table> option. For example, to list all rules in the nat table, you would issue:

Running a recent version of nodejs on the Raspberry Pi

While attempting to get my checkers network server and the accompanying nodejs-based web application for spectating and playing checkers games running on the Raspberry Pi, I quickly ran into trouble. My Raspberry Pi is running Raspbian, and the nodejs package delivered through APT is ancient 0.6.x.

I developed against nodejs 0.10.25, since that is the latest version of the package for Ubuntu 14.04.1 LTS, the OS I'm running on my laptop. I tried porting the application to the earlier versions, but it quickly turned into a nightmare with library dependencies constantly breaking. I decided it would be better if I could just install the same version of nodejs I developed on.

I found many instructions for how to install nodejs on the Raspberry Pi, but a number of them had you adding third-party APT repositories or grabbing third-party package files. These instructions may, and probably do, work just fine. However, I wanted to skip all the third-parties and get nodejs from the source. Fortunately, this was extremely simple.

Nodejs distributes builds for the Raspberry Pi. Installing the exact version I developed on was as simple as:

The only difference I found, once installed, is that the node executable is called node and not nodejs. However, the NPM executable is still named npm.