I have a small homelab and I was looking into some sort of KVM console to be able to access them both locally and remotely instead of moving around VGA cables/serial cables.

Those are rather expensive so I opted to build my own remote access system. Since all my servers and switch(es) have a serial console that should not be to hard.

I ended up using:

For the software I ended up using conserver. Below is a very brief tutorial on how to set everything up. I assume you have basic unix skills.


Preparing the microSD

At the time of writing there were no Raspberry Pi 3+ images…

  1. download and extract the Raspberry Pi 3 image from
  2. copy the image to a microSD card using either dd or pv.
  3. grab bcm2710-rpi-3-b-plus.dtb, bootcode.bin, fixup.dat, fixup_cd.dat, fixup_cd.dat fixup_cd.dat, start.elf, start_cd.elf, start_db.elf, start_x.elf, and u-boot.bin from github
  4. mount the msdos partition from the microSD card and copy over the new dtb, bin, and elf files.

Preparing the hardware

If you have a head-sink kit only install the larger one that goes on the SoC, the smaller one for the chip near the USB ports will prevent the micro POE HAT from being seated properly.

  1. install the micro POE HAT
  2. (Optionally) install a heat-sink kit, I ended up adding the smaller one to the chip on the micro POE HAT as it get rather hot.
  3. place the Raspberry Pi + HAT inside the case and assemble it

Novalabs micro POE HAT Raspberry Pi 3+ with micro POE HAT and heat-sink kit Fully assembled case

Configuring FreeBSD

Because I did not want to mess with HDMI and a keyboard I used a USB-to-TTL adaptor to configure the rPI. Both a monitor and keyboard should work equally well.

  1. set a root password
  2. create one or more accounts (and add ssh public keys to them)
  3. configure your network and firewall
  4. install conserver-com there is another one with -com and that is the wrong one for this tutorial.
  5. install additional software e.g. ipmitool, minicom, …
  6. update /boot/loader.conf to load the required drivers
## Raspberry Pi 3+ USB Ethernet
## Load USB Serial support
## Load FTDI driver
  1. enable both sshd and conserver
sysrc sshd_enable="YES"
sysrc conserver_enable="YES"
  1. create /usr/local/etc/conserver.passwd so that our users we created earlier can use conserver
  1. create /usr/local/etc/ (use the correct cuaU and ipmitool settings)
### access
config * {
	defaultaccess allowed;
access localhost {
	admin usera;
	trusted localhost;

### consoles
## defaults
default * {
	# master server
	master localhost;
	# timestamps
        # NOTE:  every hour with activity and break logging
	timestamp 1hab;
	# enable writing
	rw *;
        # enable logging
        logfile /var/log/console_&.log;
## switch
console switch {
	motd "Ubiquiti ES-48-500W (serial)";
	type device;
	device /dev/cuaU0; parity none; baud 115200;
## computenode 1
console cn1 {
	motd "SmartOS Node 1 (serial)";
	type device;
	device /dev/cuaU1; parity none; baud 115200;
console cn1_ipmi {
	motd "Compute Node 1 (IPMI)";
	logfile "";
	type exec;
	exec /usr/local/bin/ipmitool -I lanplus -C 3 -L OPERATOR -H -U consoleuser -P consolepassword shell;
## computenode 2
console cn2 {
	motd "SmartOS Node 2 (serial)";
	type device;
	device /dev/cuaU2; parity none; baud 115200;
console cn2_ipmi {
	motd "Compute Node 2 (IPMI)";
	logfile "";
	type exec;
	exec /usr/local/bin/ipmitool -I lanplus -C 3 -L OPERATOR -H -U consoleuser -P consolepassword shell;
  1. drop in a newsyslog configuration file to rotate the logs console session logs
# logfilename           [owner:group]    mode count size when   flags [/pid_file] [sig_num]
/var/log/console_*.log                      644  4     *    $W0D23 GZ    /var/run/
  1. restart conserver and test if consoles work
usera@hydra:~ # console -u
usera@hydra:~ # console c

Screenshot showing a terminal running conserver


A small bonus script I wrote to turn on the 2nd LED on the rPI once the system is booted, it will then blink the LED if someone is connected to any of the consoles.


## variables

## functions
# NOTE: turn on/off led
led_on() {
    echo "$LED_STATE" > "$LED"
led_off() {
    echo "$LED_STATE" > "$LED"
led_swap() {
    case "$LED_STATE" in
        1) led_off ;;
        *) led_on  ;;
led_state() {
    case "$LED_STATE" in
        1) echo "on"  ;;
        *) echo "off" ;;

# NOTE: check if conserver has active connections
has_conns() {
    local num_act_conns="$("$CON" -u | grep -v -c "")"
    if [ "$num_act_conns" -gt "0" ]; then
        return 0
    return 1

## main
main() {
    echo "Enabling conserver status indicator ..."
    while true; do
        if has_conns; then
            sleep 2
            if [ "$(led_state)" != "on" ]; then
            sleep 1