Building a TCP console server for Windows and FreeBSD

25 Jul 2021 - tsp
Last update 25 Jul 2021
Reading time 7 mins

A common problem: Sharing a single physical serial port on multiple machines - or having to access a remote serial port for example for a machine interface, laboratory equipment, etc. from a remote machine. Or having some annoying Windows (or some Linux version) only Software required for some FPGAs or microcontrollers that should be used to flash from a host running some sane open operating system while running the tools on some isolated virtual machine on one of the XEN VM hosts. It’s also a nice utility for small datacenter management in case one has old machines that don’t offer more sophisticated remote management solutions and wants to access the serial terminals of the machines via the network for manual setup (like for example when renting root servers, etc.)

The solution: Running a console server that’s reachable via the network. In this blog post a solution is described that builds on a set of software:

Server configuration (FreeBSD)

The server in this case is the host offering the physical serial ports. These might be RS232 ports, RS485 interfaces or simple USB to TTL/CMOS serial converters.

Hardware (example)

The latest host I personally built consisted of (note: Links are Amazon affiliate links, this pages author profits from qualified purchases):


First one has to install the ser2net service. On FreeBSD this is pretty easy:

pkg install comms/ser2net

On Linux ser2net is included in many package repositories. It’s configured via the /usr/local/etc/ser2net.conf file (/etc/ser2net.conf on Linux). Usually there is a sample configuration file that’s also deployed. The configuration basically includes a list of ports that are exposed on dedicated ports. A typical configuration line looks like:

7000:telnet:3600:/dev/ttyU0:57600 8DATABITS NONE 1STOPBIT remctl

This line would expose the device /dev/ttyU0 with a default BAUD rate of 57600 bits per second on port 7000 with 8 bits per byte, no parity and one stop bit. It would also allow remote control using RFC2217 which allows the remote to set BAUD rate, byte size, parity and stop bits itself. ser2net would also allow a raw mode instead of telnet which is even more easy when one develops own software - but telnet mode is supported by the Windows software mentioned later on.

The third value in the configuration file specifies a timeout value - if no traffic is routed over the given port for the specified amount of seconds it gets disconnected automatically.

One might also specify a custom banner that’s displayed on connection:

BANNER:banner:Serial host server

This might be interesting in case there are multiple devices in use to allow easier manual identification.

After configuration one can auto-start ser2net on every boot by adding the setting to /etc/rc.conf:


Since new rc.init script system one might also simply use /usr/local/etc/rc.d/ser2net enable.

After that one can manually start the service:

/usr/local/etc/rc.d/ser2net start

Client side

FreeBSD / Linux

This is rather simple - there is a utility called socat. On FreeBSD this is available at net/socat and can simply be installed using pkg install net/socat. It’s also available in most Linux package repositories and preinstalled on many systems.

To establish a serial port connection one simply executes socat with the desired port name:

socat pty,link=/dev/ttyS0,raw,echo=0 tcp:

In this case it will create the device /dev/ttyS0 on a pseudo terminal and connect to on port 7000

Microsoft Windows

As usual client configuration on Microsoft Windows is more cumbersome than on more sane platforms. One first has to install the virtual null modem driver com0com which requires one to disable driver signature checking at first:

After reboot you will be able to install com0com that’s available on SourceForge. The installer usually already creates a pair of COM ports for you. After that one also required hub4com that’s available at the same location. This program just has to be unpacked into any desired location.

After the virtual COM port is available one can use the command line (cmd.exe) and establish a connection using the hub4com utility:

com2tcp-rfc2217 \\.\COM4 7000

In this case the COM port name specifies one of the previously generated virtual ports, the IP address (or hostname) is the name or address of the server exposing the port and the last argument the port number.

C:\tools\hub4com>"hub4com"  --create-filter=escparse,com,parse   --create-filter=pinmap,com,pinmap:"--rts=cts --dtr=dsr" --create-filter=linectl,com,lc:"--br=local --lc=local" --add-filters=0:com --create-filter=telnet,tcp,telnet:" --comport=client"   --create-filter=pinmap,tcp,pinmap:"--rts=cts --dtr=dsr --break=break" --create-filter=linectl,tcp,lc:"--br=remote --lc=remote" --add-filters=1:tcp --octs=off "\\.\COM4" --use-driver=tcp "*"
Open("\\.\COM4", baud=19200, data=8, parity=no, stop=1, octs=off, odsr=off, ox=off, ix=off, idsr=off, ito=0) - OK
Route data COM4(0) --> TCP(1)
Route data TCP(1) --> COM4(0)
Route flow control COM4(0) --> TCP(1)
Route flow control TCP(1) --> COM4(0)
COM4(0) |     /

TCP(1) |     /

Socket( = 188
TCP(1): Connect(188, ...
Started COM4(0)
Started TCP(1)
TCP(1): Connected
TCP(1) SEND: SB 44
  1 0 0 4 176 SE
TCP(1) SEND: SB 44
  2 7 SE
TCP(1) SEND: SB 44
  3 1 SE
TCP(1) SEND: SB 44
  4 1 SE
TCP(1) SEND: SB 44
  5 9 SE
TCP(1) SEND: SB 44
  5 12 SE
TCP(1) SEND: SB 44
  5 6 SE
TCP(1) RECV: SB 44
  107 0 SE
TCP(1) RECV: DO 44
TCP(1) RECV: SB 44
  101 0 0 4 176 SE
TCP(1) RECV: SB 44
  102 7 SE
TCP(1) RECV: SB 44
  103 1 SE
TCP(1) RECV: SB 44
  104 1 SE
TCP(1) RECV: SB 44
  105 9 SE
TCP(1) RECV: SB 44
  105 12 SE
TCP(1) RECV: SB 44
  105 6 SE

A quick note on security

Note that there is no authentication and no encryption done. The traffic is open and the ports can be used by anyone who’s able to reach the service so:

I’m personally using ser2net on machines that are either running on a separate virtual network using VLANs or as a service that’s isolated using proper dynamic OpenFlow configuration when assigning a port to a machine inside the cluster.

This article is tagged:

Data protection policy

Dipl.-Ing. Thomas Spielauer, Wien (

This webpage is also available via TOR at http://jugujbrirx3irwyx.onion/

Valid HTML 4.01 Strict Powered by FreeBSD IPv6 support