Linux-based serial console server


Serial links certainly aren’t as common as they once were. They used to be used for long-haul networking, connecting a modem to a PC or router, accessing a management interface, and I’m sure there are many other things that I can’t think of.

These days there are still several devices that use serial ports for various applications. Just to be clear – I’m not talking about USB, or RS-422/485. I’m talking about good old fashioned TIA-232 (formerly known as RS-232). These ports topped-out at around 256kbps. The most common speed that I see in the networking realm is still good old 9600bps.

I recently wanted to setup a serial console server while spending minimal cash in the process. I found that some of the documentation that used to be readily available (late 1990’s) has since disappeared. This post summarizes the steps I took to get a serial console server operational under Unbuntu 10.4 LTS.

What is a serial console?  Rather than using a keyboard and monitor to interact with a device (in this case, a computer), it is sometimes possible to send and receive data from a device over a single serial connection.  This is a fantastic option when high-throughput, low-latency connections are not available.  In fact, it’s possible to configure Linux, Solaris, OpenBSD and many other platforms to use a serial console instead of, or in addition to, the normal keyboard & monitor.

Serial consoles are still used for managing many routers and switches (Cisco, HP).  Some hardware manufacturers equip their gear with only a serial port to act as a console – thus saving cost on video ports (Soekris).

In my case, I often find myself managing a rack or two of switches and routers that are all capable of using a serial console.  The problem is that many new servers don’t come with a serial port – let alone eight.  Cash was tight for this project, so I didn’t opt for a pre-built multiport serial console server and instead decided to build my own.  Here’s how I did it.


I’ve used equipment from Axxeon before.  I’ve been pretty happy with it.  If you’re in need of reasonably priced switching gear for harsh environments, they can help.  It also turns out that they sell multiport serial cards for a PCI-e bus:
Eight ports was all I needed for this particular application, and the price was reasonable.

This card uses the very well supported “Oxford” serial chipset.  Drivers exist for this chipset natively in Ubuntu 10.4.

Be careful not to over-tighten the thumbscrews on the breakout cable.  They are *tiny* and can’t handle much torque.  I managed to snap one on a previous install while tightening by hand.

I used a small PC for this particular setup.  The low-profile PCI-e back plate made install a breeze.

No other changes were required to get this card to work.

Linux Distribution

For a base OS, like I said, I used Ubuntu 10.4 LTS.  You may notice that the current version of LTS is 12.  I’m a little late in doing this writeup.  I would assume that not much would need to change between 10.4 and 12.  If I setup another with 12, I’ll try to remember to update this post.


Ubuntu’s kernel isn’t configured to natively handle more than four serial ports.  There are two ways to fix this:

  1. adjust and re-compile the kernel
  2. pass the kernel a parameter that enables it to use more

I opted for the second option.  It’s been a long time since I built a kernel, and I’d rather not get into that.  All that was necessary was another line in /boot/grub/grub.conf:

# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.

GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`

Hint – it was the last line in the above output.  The “8250” was a common serial chipset back in the day.  This line tells the kernel to work with up to 16 serial ports.

After running ‘update-grub’ and rebooting, dmesg had the appropriate information:

tpb@serial:~$ dmesg | grep ttyS
[    0.770319] serial8250: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A
[    0.770410] serial8250: ttyS1 at I/O 0x2f8 (irq = 3) is a 16550A
[    0.770826] 00:06: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A
[    0.770948] 00:07: ttyS1 at I/O 0x2f8 (irq = 3) is a 16550A
[    0.771645] ttyS4: detected caps 00000700 should be 00000100
[    0.771650] 0000:08:00.0: ttyS4 at MMIO 0xd5efd000 (irq = 17) is a 16C950/954
[    0.771716] ttyS5: detected caps 00000700 should be 00000100
[    0.771720] 0000:08:00.0: ttyS5 at MMIO 0xd5efd200 (irq = 17) is a 16C950/954
[    0.771782] ttyS6: detected caps 00000700 should be 00000100
[    0.771786] 0000:08:00.0: ttyS6 at MMIO 0xd5efd400 (irq = 17) is a 16C950/954
[    0.771847] ttyS7: detected caps 00000700 should be 00000100
[    0.771851] 0000:08:00.0: ttyS7 at MMIO 0xd5efd600 (irq = 17) is a 16C950/954
[    0.771912] ttyS8: detected caps 00000700 should be 00000100
[    0.771916] 0000:08:00.0: ttyS8 at MMIO 0xd5efd800 (irq = 17) is a 16C950/954
[    0.771977] ttyS9: detected caps 00000700 should be 00000100
[    0.771981] 0000:08:00.0: ttyS9 at MMIO 0xd5efda00 (irq = 17) is a 16C950/954
[    0.772042] ttyS10: detected caps 00000700 should be 00000100
[    0.772046] 0000:08:00.0: ttyS10 at MMIO 0xd5efdc00 (irq = 17) is a 16C950/954
[    0.772108] ttyS11: detected caps 00000700 should be 00000100
[    0.772112] 0000:08:00.0: ttyS11 at MMIO 0xd5efde00 (irq = 17) is a 16C950/954

A couple things to notice:

  1. There is a gap in numbering between the on-board serial and the first PCI-e serial port.
  2. There is no guarantee that the first PCI-e serial port will align with the first port on the break-out cable.  You will need to do some trial-and-error testing to map the logical ports to the physical ports.


There are two “conserver” packages in Ubuntu. The conserver-server package includes the client and the daemon.

tpb@serial:/etc$ apt-cache search conserver
conserver-client - connect to a console server
conserver-server - connect multiple user to a serial console with logging

Rather than using an /etc/init.d/ script to start and stop the daemon, I opted to just throw the command into /etc/rc.local:

tpb@serial:/etc$ cat rc.local

conserver -C /etc/conserver/

Conserver Configuration

The config is fairly straight forward. I used the Alias directive to match the tty number to the octopus cable port number. Because this is a serial console server in a lab, I opted to allow all local users full access to all ports.

tpb@serial:/etc/conserver$ cat
# The character '&' in logfile names are substituted with the console
# name.
config * {
        logfile /data/conserver.log;
        sslrequired off;
        daemonmode yes;
        primaryport 3109;

access * { trusted localhost; }

default * {
        master localhost;
        type device;
        baud 9600;
        parity none;
        logfile /data/console/&.log;
        timestamp "";
        rw *;

console c2950 {
        #alias on-board
        device /dev/ttyS0;
console c2960 {
        #alias P1
        device /dev/ttyS4;
console c2800-bottom {
        #alias P2
        device /dev/ttyS5;
console c3825 {
        #alias P3
        device /dev/ttyS6;

Tab Completion

To finish things off nicely, I decided to configure BASH tab completion for the “console” command:

tpb@serial:/etc/bash_completion.d$ cat console
complete -W "`cat /etc/conserver/ | grep ^console | sed -e "s/^[^ ]* //" -e "s/ .*//"`" console


Setting up a serial console isn’t too rough. There are ways to improve the setup:

  • Use RADIUS authentication rather than allowing all users to have access
  • Allow remote telnet connections in so that users don’t need local accounts

Hopefully this will help either myself or some other future admin do things a little faster and a little less painfully.  If you have any suggestions for how to improve this serial console server, please let me know!