Situation: you live in a one-room appartment and receive Internet through a single RJ45 plug in the wall. How do you extend it to all devices in the room for the cheapest price?
Objective: provide WiFi connectivity on a dedicated LAN where users can see each other and share files easily. The system should be easy to repair or upgrade. Bonus points for extra functionalities like VPN provided to the whole WiFi LAN, ad filtering, or shared folders on Samba.
My first go-to for anything cheap related to computing is the RaspberryPi. How can you beat it? For 35 euros (amazon.fr in December 2015) you get a full-powered Linux box with RJ45 and enough USB ports to power an external disk and a WiFi dongle. I gave it a try and came to the conclusion that the result would probably be a little too expensive and probably brittle. I have several WiFI USB adapters lying around and none of them was able to create a WiFi Access Point on a RPi, though they do work flawlessly as WiFi clients. They almost got there but not completely. You need to recompile your own WiFi access point software, and taking care of my own iptables rules is just beyond my patience.
Better option: Openwrt! This open-source Linux distribution is not meant for your average PC but to run on screen-less network appliances. You won't find desktop apps or anything related to X11 but you have all possible network daemons and tools running there. Openwrt runs on low-power processors like ARM, MIPS, and x86 too of course. It comes bundled with its own package distribution tools (opkg) making administration relatively easy. It is really meant for tinkerers, people who like to open the box and modify what's inside to do different stuff.
Obvious applications for Openwrt are of course network-related. Build your home router for 25 euros supporting IPv6, customized firewalling, guest WiFi, kid protection, quality of service, network monitoring, Virtual Private Networks, or file sharing, to name a few. A popular application is PirateBox: start the box, create a local WiFi network, all clients connected to it can easily share files through the local access point. Other cool projects include running your own home telephony over the Internet (asterisk), making a sound box or an Internet radio.
There are also thousands of cool projects if you are so inclined and ready to take your soldering iron out of the dust. Most router hardware parts have hackable GPIO ports you can connect to a breadboard to pilot a 0-5V trigger or even read signals at a reasonable frequency. Check out the DIY section at the bottom of this page to get a few ideas:
Note that the WR703N is a 10-20 euro piece of hardware so it is about half of the retail price of an Arduino with Ethernet shield, or a RaspberryPi. Sure, you get less hardware, but if your project is purely network-oriented this is by far a better alternative.
Back to our task: find cheap hardware that gets Internet from an RJ45 plug and offers decent WiFi for a few devices. I set my limit to 25 euros and chose the TP-Link MR3020. It has the minimal 4MB of internal storage needed to install Openwrt. You read that right: 4 megabytes of persistent storage, in an era where your average smartphone sports several gigabytes of RAM.
There are several ways to obtain an Openwrt image for a given piece of hardware. First and simplest one is to download it directly off openwrt.org. That does not always fit the bill though, because the team had to make choices about the packages that are present in each image. If space is tight (4 megs is kind of narrow) you may not be able to install anything more than was pre-bundled already. That is actually the case for the MR3020. Solution: extend the local storage. So I plugged in an 8GB USB dongle (5 euros).
Plug the USB in, wait, and... nothing. 'dmesg' shows the kernel recognized something USB but did not offer to mount the filesystem. Of course: the kernel modules have been trimmed down to a minimum and USB storage was not in. Quick install with opkg? No way. There is not enough space left to install a mere kernel module for USB storage so the default image falls a bit flat. Removing packages also does not work. I first tried to trim down all un-needed packages until I realized that every time I uninstalled something, space was running even lower on the root filesystem. How comes?
To understand why, you need to know that the default firmware image is built on top of squashfs, a read-only compressed filesystem. On top of that, openwrt adds an overlay filesystem, an image that registers all changes from the underlying read-only partition. When you delete a file from such a setup you actually write on top of it in the overlay filesystem a mention that this file should not appear any more. There is another option using a read-write filesystem (jffs2) for the firmware but apparently it can get into trouble on many routers so I did not even try.
One solution is to build your own openwrt image and embed only the modules you need. That one is tough. You need to dedicate an x64 machine for that, download a million source files, prepare all the compilers and build tools you ever heard of, fine tune the package configuration, press make, and wait for a few hours. You end up with an image a bit smaller than the four dreaded megabytes with a build system taking about 3GB of space on the build host.
To be fair, the openwrt build system is a wonderful thing. It starts by creating its own toolchain for cross-compilation for your target hardware, then builds up a whole Unix from scratch and ends up packaging everything into this tiny image. Very impressive. I have seen very few professional build systems that are as clean as this one. Congratulations to the Openwrt for working out such a beautiful system!
If you are not into compiling your own stuff, you have another option:
This method uses pre-built components which you assemble into a minimal firmware image. That goes a lot faster (a matter of seconds) and does not eat up gigabytes of disk space. Select the few minimal modules you need to at least boot up the router on the network, and be able to mount USB storage. That is what I ended up doing.
I flashed an image that contained just enough software to run a kernel with network support (duh), USB storage support, package management, and some basic utilities. Plugging the USB storage worked immediately. Yay!
Let's start again: I have 8GB of space on USB dongle, far more than I will ever need for the router itself. I created a first ext4 partition for 700 megs, which should be enough to hold every possible package, configuration files, and even log files if needed. I added a second 128 meg partition for swap space, and left the rest as a single ext4 partition.
The router was booted again with USB dongle plugged in. Let it boot, log onto it as root, and set up the root filesystem as an overlay from the USB first partition. Reboot the router and there you go: your router space has grown from 4 megs to 700.
This brilliant howto explains exactly how to do it:
Once you have enough space you can start adding back all the packages you need. Just to give you an idea, I have there:
- A web interface to set everything up
- Tools to monitor the device and display nice graphs on the web interface
- DNS server, WiFi Access Point, Firewall
- Development tools: gcc, git, python, lua, strace, screen, vim
- A Samba server
- sshfs to mount remote filesystems locally
- OpenVPN either as client or server
After that it is a matter of taking time to configure each service specifically. The Openwrt wiki pages are a real treasure in this respect. Everything you need is there, together with additional ideas for cool stuff to do. One hour later I was done adding VPN support, Samba service for the remaining of the USB dongle space, an ad blocker, a local web site, and a local fixed address for administration (an alias on eth0).
There is one point really worth mentioning about the Openwrt philosophy. If you have some Unix experience, you know that every piece of server software you install comes with its own system of configuration directories and files with a specific new syntax to learn, a different place to find log files, and another way to handle PID files. Sure there is some standardization on the way with most config files under /etc and logs under /var/log, but it seems everybody needs to invent a new syntax for configuration and logging.
Openwrt places all configuration files in a single place and they all respect the same key/value syntax. It is straightforward to understand, edit, diff, store in version control, or pretty-print. That alone helps smooth out the learning curve every step of the way. Gives you a definite feeling of things done in a proper, consistent, and very clean manner. So there you go: for all your network-y things, you know where to look. The Internet of things starts right here with these boxes, guys.
My next endeavours with OpenWRT will probably need my soldering iron. Those GPIOs on the board look tempting...