I must admit, I was pretty amazed when I stumbled across m0n0wall back in 2006 and discovered how easy its developers had made it to take an armful of marginally useful computer equipment and turn it into a feature-filled powerhouse of a router.  Granted, people have been building their own PC-based routers on top of Linux distributions like Debian and Slackware since this side of forever.  That said, however, I’m of the opinion that there just isn’t enough time in a given day to sit down and dig through a mess of conf files so I can give the roommate’s new Xbox a static DHCP assignment and give it permission to punch holes in my firewall with uPNP.  In the home environment, a router is very much an appliance; it is designed for a fairly specific purpose, and the functionality it provides doesn’t really change much over time.  Also, like most other appliances, after getting it all set up you just want to put it in a corner and leave it to it’s own devices (doh ho ho…) as it unobtrusively does what it’s supposed to do.

pfSense lets you throw a couple of network adapters in a regular PC and do just that, all while giving you an extraordinarily rich feature set compared to the typical home/small office fare.  While some consumer routers seem to be flaky, full of firmware bugs and prone to overheating, pfSense (and its parent software, m0n0wall) is built on FreeBSD, and is as stable as the hardware you run it on.  Granted, setup isn’t quite as simple as pulling a new Linksys out of a box, and you’ll have to provide your own network switch, but the flexibility and functionality you gain makes it well worth the effort.

(A quick note: this tutorial mainly covers pfSense, but the installation process for m0n0wall is nearly identical, since pfSense is actually developed into a separate project from m0n0wall’s codebase.  I recommend pfSense because of its richer feature set, and one of the primary reasons I switched to it is because of its uPNP support, which is required for Xbox Live connectivity.  If you want to rid yourself of the excess features, or if you have to run your router with a very small flash disk, take a look at m0n0wall, as it is also excellent software.)

I’ve had pfSense running on a standard 700MHz Celeron-based computer for a couple of years now, and while this runs perfectly fine as it is, I’ve wanted to move it to a more conservative platform, mainly due to the amount of power it consumes and the noise it generates.  While a P6-based (Pentium III class) Celeron is about as power conscious as you can get in a desktop machine, one can only get so far with an 8 year old desktop motherboard.  My interest in miniaturizing and simplifying has turned me to thin clients as of late, and the ‘bare-bones’ hardware that thin clients are generally composed of makes for a good foundation to build a custom router platform with.  Many thin clients only come with a single network adapter though, with their minimalist hardware designs, which obviously would be unsuitable for a typical router.  Fortunately, there are a decent number of models out there from a few years ago with a PCI expansion slot built in.  In this article, I will look at the Neoware CA10 in particular.  This thin client provides an 800MHz VIA processor on a system board that will accept two standard 184-pin DDR1 RAM modules, and one standard PCI expansion card, all in a fanless package about the size of a single volume of the Encyclopedia Britannica.  Better yet, they are frequently available on ebay for small change, since a thin client is only as useful as the server it connects to.  (But we’re about to change that!)

Neoware CA10 thin client

The front of the Neoware CA10. Not much to it.

What you’ll need

If you’re looking at building one of these yourself, here’s a basic shopping list of sorts detailing what you’ll need.  You may happen to have some of this stuff laying around, but it is all otherwise easily obtained on the internets, most of it probably second-hand.

  • the Thin Client itself — while there are a ton of them out there, many of them do not have PCI slots, so keep that in mind if you’re not buying a Neoware model.  If you are, the models I’m aware of that include the PCI slot are the CA2, CA10, and EON models.  While the CA2 and CA10 are based on processors in the neighborhood of 800MHz, the EON units are older designs based around old AMD Geode processors around 166-300MHz.  The EON uses less electricity (and probably generates less heat) than the CA2/CA10 models, but the slower processor also means it may not be able to keep up with higher speed network throughput.  For more details, check out the “Sizing” page on the pfSense website.
    Personally, I picked up the CA10 because it supports standard DDR RAM, and the DC power connector on the back is a standard barrel connector, instead of some wonky DIN-style.  Many of these units sell on ebay sans their long-lost power adapters, so it’s something to consider.  I picked my CA10 up on ebay for $19.99 shipped.
  • A right-angle PCI slot adapter — in the case of the Neoware thin clients, they didn’t all ship from the factory with a PCI adapter fitted on the system board.  Fortunately, a standard 1U right-angle PCI adapter does the trick just fine, albeit without the completely unnecessary metal bracket that Neoware sold them with.  Be sure to get one with the smaller grouping of pins on the left-hand side of the female end of the connector (click the image below for a closeup.)  Like many other cheaply-produced electronics widgets that are produced in China by the truckload, one of these can be had on ebay for next to nothing.  I wanted mine sooner than the 3-week delivery time promised on the “shipped from China” listings, so I paid $5 for one that was already in the Continental 48.
  • Thin Client parts

    CA10 disassembled with dual-port Intel Ethernet adapter, and 1U right-angle PCI adapter

    A dual-port (or more) Ethernet adapter — If you read my article about building a server out of used parts, you already know that I like Intel ethernet adapters.  They just make good stuff.  Also, the driver support in any operating system tends to be phenomenal for Intel devices, so I suppose there are a lot of people who agree with me.  Anyways, you don’t have to use an Intel adapter, but I do recommend getting a dual-, triple- or quad-port adapter of some kind.  Your mileage may vary, but my experience with the CA10′s onboard VIA network adapter under linux was, well, less than encouraging.  (More on that later.)
    I scavenged this particular Intel Pro/100 dual-port card out of a decommissioned Dell Poweredge, but an ebay search for “dual port intel pro 100″ turned up a handful of cards in the $15-30 range.  Just be sure to buy a card that is 32-bit PCI, and no more than half-length.  A full-length PCI card will definitely not fit in this enclosure.

  • A 44-pin IDE Disk-on-Module (DOM) — By this point, you may be wondering where the heck the software goes if all that’s inside that machine is a system board, processor, some RAM and one measly PCI slot.  Fortunately, Neoware already thought of that for us.  These units (and many other thin clients) have a 44-pin laptop IDE connector on the board, onto which plugs a small board with a chunk of Flash RAM soldered to it.  The great part about this is that the BIOS (and the OS) sees this board as a regular old hard disk drive, so using this kind of setup is completely transparent.  If you really wanted to, you could connect up a laptop hard drive with the appropriate female-female cable, but that’s no fun.  We want this to be a true embedded device, hard drives are just something else to make noise or break.
    Disk on Module

    44-pin horizontal Disk-on-Module. Click to see a closeup of the header it plugs into.

    My particular unit came with a 64MB DOM already installed, and it had some Neoware-custom linux distribution installed that provided an outdated RDP client and a telnet client.  While 64MB would actually be perfectly comfortable for m0n0wall, which is an even slimmer firewall distribution that pfSense grew out of, pfSense’s extra goodies and fault-tolerant backup partition require a minimum of 512MB, as of version 1.2.2.  (As of this writing, the pfSense Minimum Requirements page lists the old minimum requirement of 128MB, this was applicable for 1.21 and older, before they added the fault-tolerant backup partition.)  They can be had pretty cheaply on ebay (search “disk on module 44″) or elsewhere online, just make sure you buy the 44-pin version.  Also, given the option, buy the one with an exposed circuit board that is designed to sit parallel to the board it plugs into.  I’m not sure how much space the vertical ones take up, but it plugs in underneath the area the ethernet card will occupy, so take that for what it’s worth.

  • A power adapter — as I briefly mentioned above, a lot of these used thin clients are sold as surplus, and have long since been separated from their power adapters.  Depending on the thin client you buy, you may have better or worse luck at cobbling something together yourself, or finding an equivalent that is sufficient.  The CA10 has a standard barrel connector on the back, and is labeled as requiring 12 volts DC at 4 amps.  The polarity (positive center pin) of the connector is also marked near the connector itself.  Mine didn’t have a power adapter, so I cut the end off of a 12VDC 3A Dell LCD power adapter, and soldered on a connector that happened to fit the plug on the thin client.  While I didn’t buy one, I also saw someone selling power adapters on ebay advertised for use with the CA10 for around twenty dollars.  For a new 12VDC 4A power adapter, that sounds like a decent deal if you don’t have something to cobble together.
  • A null-modem serial cable — pfSense and m0n0wall take different approaches here, but with pfSense the “Embedded” distribution of the software, which we will be using, does not output boot information or accept console input from the integrated video out and keyboard input.  To do the initial setup, you’ll need to connect a null-modem serial cable between the COM1 port on the thin client and a serial port on your PC, and use PuTTY or another telnet client to tell pfSense which ethernet port is LAN, which is WAN, and some other basic stuff.
    On the other hand, if you’re deciding to go with m0n0wall, for which the installation process is otherwise identical, you can just hook a VGA monitor and keyboard up, and you’ll be all set.
  • Some more RAM — this really depends on what your thin client comes with, and how much RAM you really need.  pfSense requires at least 128MB, m0n0wall requires at least 64MB.  Either way, more is better — the “state table” the router uses to track individual connections will be larger with more RAM, and many of the advanced features and plugins pfSense offers will use RAM up as well.  Plus, old RAM is generally pretty easy to get one’s hands on, so bump it to at least 256MB if you can.

Putting it all together

PCI card installed, with right-angle adapter (green) and rear expansion slot face bracket (rear) attached.

Now that you have gathered all of your parts, by all means put it all together and test everything out.  When installing the ethernet card in the CA10, I found it was easiest to unscrew the metal expansion slot face bracket from the back of the case, then hold it on the PCI card and tighten down the screw that holds down the top of the PCI card’s faceplate.  Then, slap your 1U right-angle PCI adapter on the side of the card, plug the whole thing in at once, then screw the metal expansion slot bracket back to the back of the case (click the image at the right for a closer look at what I’m referring to here.)

Once you’ve got everything put together, leave the top casing off and connect the power adapter, a VGA monitor and a keyboard.  Go ahead and turn it on — if you bought a Transcend DOM, try to avoid blinding yourself with the DOM’s needlessly bright blue power LED.  If all is well so far, you should see a green “Neoware” boot splash screen.  Mash the Delete key, and you should be able to get into the BIOS.  It’s a standard Award BIOS, so the usual menus and options are present.  Open “Standard CMOS Options” and make sure your DOM shows up as the Primary IDE device.  If it doesn’t, make sure the jumper on the DOM is set to “Master”.  Also, while you’re in there, set the “Halt on” option to “No errors”, so the unit doesn’t complain when there’s no keyboard attached.  Go to “Advanced BIOS Options”, and set the first boot device to “USB-HDD”, and the second one to “USB-FDD”.  This is so we can boot from a flash drive to get the image installed on the DOM.  Then open the “Integrated Peripherals” menu, and disable the on-board Audio and LAN.  When the onboard LAN in my unit was enabled, trying to do anything networking-related on any network interface under Ubuntu Mini caused the system to lock up.  You may have better luck, but I just disabled it and moved on with things.  (After booting into pfSense, the VIA adapter seems to behave normally, but I haven’t bothered testing it at all yet, so I can’t say if the behavior was restricted to Ubuntu’s drivers or not.)

Writing the pfSense software to the flash module

Next, grab a a flash drive (at least 512MB), and head to your nearest internet-connected Windows box.  First, download the i386 version of Ubuntu Mini Remix, which is a minimal, command-line only Linux live distribution.  If you already happen to have another live distribution on a flash drive, it will likely do the trick as well, provided it’s for the i386 architecture.  I just googled for a command-line only live distro and found this one first.  It’s only 160-someodd megabytes, and there isn’t much stuff to load that you’ll have to wait for.  While you’re waiting for that ISO to download, pick up UNetbootin as well.  UNetbootin is a small utility that creates a bootable flash drive from an ISO image — pretty handy.  While you’re waiting on that ISO, format your flash drive, preferably as FAT, but FAT32 should work as well.  After the ISO is done downloading, open up UNetbootin, select the “Diskimage” option, then click the “…” browse button and open up that ISO you just fetched.  Select the drive letter that your flash drive is currently mounted as at the bottom, then click “OK”.  UNetbootin will chug for a little while, and write the contents of the ISO to the flash drive.  After it’s done, click “Exit” to close UNetbootin.  Now, head over to the pfSense or m0n0wall website to download the latest embedded image, and save it straight to that flash drive.  If you’re using pfSense, make sure you get the appropriate image for the size of your DOM — 512MB if you have the 512MB DOM, 2GB if you have the 2GB, and so on.  If you have some obnoxiously large disk module, just use the largest one listed (which at the time of this writing, is 4GB.)  Finally, eject the flash drive from My Computer or from the “Safely Remove Hardware” tray icon.  If you don’t, the flash drive may not boot properly.

Plug your bootable flash drive into the thin client, and boot that sucker up.  Provided you set the first and second boot choices to USB-HDD and USB-FDD, you should see Ubuntu Mini Remix booting up after a short time.  If you don’t, go back into the BIOS and try USB-CDROM and USB-ZIP instead.  For whatever crazy reason, some flash drives present themselves as something besides the first two options, but generally one of the four will be successful.

After you’re all booted, go ahead and switch yourself to the root user, so you don’t have to preface all your commands with “sudo” (ugh, that’s so linuxy!):

$ sudo su

After that’s been taken care of, the shell prompt should change to indicate you’re root.  After you’ve done that, let’s take a look at which drives the computer is seeing:

# ls /dev | grep sd

This should print out a list of all of the drives and partitions that linux is seeing.  You should see two distinct disks, which will show up as “sda” and “sdb”.  You should also see some partitions, which will have a number at the end, like “sda1″ and “sdb1″.  If you bought a new flash DOM, you’ll probably only see one partition.  This is handy, because whichever disk (e.g., “sda”) doesn’t have an associated partition (e.g., “sda1″) is more than likely your DOM.  We’ll need to know the designation for later, so keep it in mind.

To make sure that the designation you saw above is actually your DOM, we’ll narrow things down through process of elimination.  Enter this command:

# mount | grep sd

And you should get a response sort of like this:

/dev/sdb1 on /cdrom type vfat...

Now we know that “sdb” is your flash drive, because that’s what is mounted at /cdrom.  This leaves “sda” as your DOM, and that’s where we’ll want to write the embedded image to.  So go ahead and navigate to the /cdrom directory, and list the directory contents:

# cd /cdrom
# ls

You should see the file you downloaded in there somewhere, with a crazy filename like “pfSense-1.2.3-RELEASE-1g-nanobsd.img.gz”.  Now that you see it, copy that filename into the following command to write the image out to your DOM:

# gunzip -c pfSense-1.2.3-RELEASE-1g-nanobsd.img.gz | dd of=/dev/sda bs=16k

m0n0wall does not distribute compressed images, so if you’re using m0n0wall, the command is slightly different:

# dd if=embedded-1.32.img of=/dev/sda bs=16k

What this does is reads the embedded image, 16 kilobytes at a time, and writes it out to the disk identified by /dev/sda, 16 kilobytes at a time.  For the pfSense command, we’re un-gzipping the compressed image and feeding it straight into the dd command, which is what actually writes to the disk.  After several seconds, you’ll see some output like this:

60858.0 records in
60858.0 records out
997097472 bytes (997MB) copied

#

At that point, you’re done in linux.  Go ahead and enter “reboot” to restart, then go into the BIOS and set your boot devices back to “HDD-0″ and “disabled”, but don’t save and restart yet.  With that done, go ahead and connect your null-modem cable to COM1 on the thin client, and to a serial port on your desktop computer.  (If you’re using m0n0wall, simply keep using your monitor and keyboard.)

Booting pfSense for the first time

To communicate over the serial cable with your pfSense box, download PuTTY and open it up.  Select “Serial” as the connection type, and make sure the correct Serial line is specified in the textbox.  If your computer only has one serial port, chances are good it is COM1.  The other defaults are fine (including 9600 speed), so go ahead and click the “Open” button.  After you’ve done this, go ahead and save your changes in the thin client’s BIOS, and reboot it.  If all goes well, you should see this text appear on the thin client’s monitor:

BTX loader 1.00  BTX version is 1.02

…and that’s it.  It looks like something just crashed, but FreeBSD has already switched over to outputting over the serial cable.  If PuTTY is properly configured, you should see the start of the boot process:

1  pfSense
2  pfSense

F6 PXE
Boot:  1

And after a brief timeout, it continues:

/boot.config: -h
Consoles: serial port
BIOS drive C: is disk0
BIOS 639kB/252928kB available memory

FreeBSD/i386 bootstrap loader, Revision 1.1
(sullrich@FreeBSD_8.0_pfSense_2.0-snaps.pfsense.org, Thu Dec 30 02:59:41 EST 2010)
Loading /boot/defaults/loader.conf
/boot/kernel/kernel text=0x89052c data=0x3c9934+0x9b6a0 |
\
Hit [Enter] to boot immediately, or any other key for command prompt.
Booting [/boot/kernel/kernel]...
Copyright (c) 1992-2010 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
 The Regents of the University of California. All rights reserved.
FreeBSD is a registered trademark of The FreeBSD Foundation.
FreeBSD 8.1-RELEASE-p2 #0: Thu Dec 30 03:30:42 EST 2010
(.....)

And so on.  Provided nothing goes wrong, you should eventually be presented with the setup menu:

Network interface mismatch -- Running interface assignment option.
fxp0: link state changed to DOWN
fxp1: link state changed to UP

Valid interfaces are:

fxp0  00:03:47:96:03:87   (up)  Intel 82558 Pro/100 Ethernet
fxp1  00:03:47:96:03:88   (up)  Intel 82558 Pro/100 Ethernet

Do you want to set up VLANs first?

If you are not going to use VLANs, or only for optional interfaces, you should
say no here and use the webConfigurator to configure VLANs later, if required.

Do you want to set up VLANs now [y|n]?

Go ahead and select no, then get a live ethernet cable ready.  Anything connected to a switch, or a crossover cable connected to a PC, is fine.  pfSense will first ask which interface should be the WAN interface, but it’s tough to tell what’s what since both ports are on one card.  So when asked, enter ‘a’ for autodetection:

Enter the WAN interface name or 'a' for auto-detection: a

Connect the WAN interface now and make sure that the link is up.
Then press ENTER to continue.

Plug your live ethernet cable into whichever port you want to be the WAN port.  Wait for the following to appear on the screen, then press enter:

fxp1: link state changed to UP

Assuming you only have two valid ethernet interfaces as seen at the start of the setup menu, you can just type in the name of the other interface for the LAN (fxp0 in this example) then just press enter when asked for the optional interface:

Detected link-up on interface fxp1.

Enter the LAN interface name or 'a' for auto-detection
NOTE: this enables full Firewalling/NAT mode.
(or nothing if finished): fxp0

Enter the Optional 1 interface name or 'a' for auto-detection
(or nothing if finished): <enter>

Once you confirm your choices, pfSense will finish configuring itself:

The interfaces will be assigned as follows:

LAN  -> fxp0
WAN  -> fxp1

Do you want to proceed [y|n]?y

Writing configuration...done.
Updating configuration..........done.
Cleaning backup cache...done.
Setting up extended sysctls...done.
(.....)

Once that’s all finished, you’ll arrive at the main configuration menu.  Among other things, from here you can adjust the default IP range of the LAN interface if you don’t like the default of 192.168.1.x.  Also, in the future, if you happen to forget the web interface password, you can hook the serial cable back up and reset it from here:

FreeBSD/i386 (pfSense.localdomain) (console)

*** Welcome to pfSense 2.0-BETA5-nanobsd (i386) on pfSense ***

 WAN (wan)                 -> fxp1       -> 72.185.138.51 (DHCP)
 LAN (lan)                 -> fxp0       -> 192.168.1.1

 0) Logout (SSH only)                  8) Shell
 1) Assign Interfaces                  9) pfTop
 2) Set interface(s) IP address       10) Filter Logs
 3) Reset webConfigurator password    11) Restart webConfigurator
 4) Reset to factory defaults         12) pfSense Developer Shell
 5) Reboot system                     13) Upgrade from console
 6) Halt system                       14) Enable Secure Shell (sshd)
 7) Ping host

Enter an option:

Once you’ve made it to this point, you should be able to connect a switch up to the LAN interface, connect computers to that switch, and access the web interface at http://192.168.1.1/ .  If you happen to be using pfSense 2.0 (still in beta as of this writing), this will redirect to an SSL-secured connection, which uses a self-signed security certificate that your browser will complain about.  Accept the warning, save the exception and log in using the default username “admin” and default password “pfsense”.   Also, if you’re using 2.0, you should be sent straight to the webgui’s setup wizard, which walks you through configuring WAN connection settings and other basic settings.  If you’re using 1.2x, just point to the “System” menu at the top and select “Setup Wizard” to get started.  After that, be sure to poke around through all of the menu options, and get a feel for what’s there.  Much of the interface is self-explanatory, but pfSense documentation is also available online, at http://doc.pfsense.org/.  pfSense’s documentation is still evolving, however, so if you don’t find something there, be sure to check the pfSense forums, or even the m0n0wall documentation site.  m0n0wall’s documentation is very thorough, and several parts of the online interface contain identical configuration options.