Six years ago, I was inspired to buy a DEC serial terminal. Since then, my collection has grown to include several DEC models, an IBM 3151, a Wyse WY-55, a Televideo 990, and a few others.
When you are running a terminal program on Linux or MacOS, what you are really running is a terminal emulator. In almost all cases, the terminal emulator is emulating one of the DEC terminals in the vt100 through vt520 line, which themselves use a command set based on an ANSI standard.
In short, you spend all day using a program designed to pretend to be the exact kind of physical machine I’m using for this experiment!
I have long used my terminals connected to a Raspberry Pi 4, but due to the difficulty of entering a root filesystem encryption password using a serial console on a Raspberry Pi, I am switching to an x86 Mini PC (with a N100 CPU).
While I have used a terminal with the Pi, I’ve never before used it as a serial console all the way from early boot, and I have never installed Debian using the terminal to run the installer. A serial terminal gives you a login prompt. A serial console gives you access to kernel messages, the initrd environment, and sometimes even the bootloader.
This might be fun, I thought.
I selected one of my vt510 terminals for this. It is one of my newer ones, having been built in 1993. But it has a key feature: I can remap Ctrl to be at the caps lock position, something I do on every other system I use anyhow. I could have easily selected an older one from the 1980s.
Kernel configuration
To enable a serial console for Linux, you need to pass a parameter on the kernel command line. See the kernel documentaiton for more. I very frequently see instructions that are incomplete; they particularly omit flow control, which is most definitely needed for these real serial terminals.
I run my terminal at 57600 bps, so the parameter I need is console=ttyS0,57600n8r. The “r” means to use hardware flow control (ttyS0 corresponds to the first serial port on the system; use ttyS1 or something else as appropriate for your situation). While booting the Debian installer, according to Debian’s instructions, it may be useful to also add TERM=vt102 (the installer doesn’t support the vt510 terminal type directly). The TERM parameter should not be specified on a running system after instlalation.
Booting the Debian installer
When you start the Debian installer, to get it into serial mode, you have a couple of options:
- You can use a traditional display and keyboard just long enough to input the kernel parameters described above
- You can edit the bootloader configuration on the installer’s filesystem prior to booting from it
Option 1 is pretty easy. Option 2 is hard mode, but not that bad.
On x86, the Debian installer boots in at least two different ways: it uses GRUB if you’re booting under UEFI (which is most systems these days), or ISOLINUX if you are booting from the BIOS.
If using GRUB, the file to edit on the installer image is boot/grub/grub.cfg.
Near the top, add these lines:
serial --unit=0 --speed=57600 --word=8 --parity=no --stop=1 terminal_input console serial terminal_output console serial
Unit 0 corresponds to ttyS0 as above.
GRUB’s serial command does not support flow control. If your terminal gets corrupted during the GRUB stage, you may need to configure it to a slower speed.
Then, find the “linux” line under the “Install” menuentry. Edit it to insert console=ttyS0,57600n8r TERM=vt102 right after the vga=788.
Save, unmount, and boot. You should see the GRUB screen displayed on your serial terminal. Select the Install option and the installer begins.
If you are using BIOS boot, I’m sure you can do something similar with the files in the isolinux directory, but haven’t researched it.
Now, you can install Debian like usual!
Configuring the System
I was pleasantly surprised to find that Debian’s installer took care of many, but not all, of the things I want to do in order to make the system work nicely with a serial terminal. You can perform these steps from a chroot under the installer environment before a reboot, or later in the running system.
First, while Debian does set up a getty (the program that displays the login prompt) on the serial console by default, it doesn’t enable hardware flow control. So let’s do that.
Configuring the System: agetty with systemd
Run systemctl edit serial-getty@ttyS0.service. This opens an editor that lets you customize the systemd configuration for a given service without having to edit the file directly. All you really need to do is modify the agetty command, so we just override it. At the top, in the designated area, write:
[Service] ExecStart= ExecStart=-/sbin/agetty --wait-cr -8 -h -L=always %I 57600 vt510
The empty ExecStart= line is necessary to tell systemd to remove the existing ExecStart command (otherwise, it will logically contain two ExecStart lines, which is an error).
These arguments say:
- –wait-cr means to wait for the user to press Return at the terminal before attempting to display the login prompt
- -8 tells it to assume 8-bit mode on the serial line
- -h enables hardware flow control
- -L=always enables local line mode, disabling monitoring of modem control lines
- %I substitutes the name of the port from systemd
- 57600 gives the desired speed, and vt510 gives the desired setting for the TERM environment variable
The systemd documentation refers to this page about serial consoles, which gives more background. However, I think it is better to use the systemctl edit method described here, rather than just copying the config file, since this lets things like new configurations with new Debian versions take effect.
Configuring the System: Kernel and GRUB
Your next stop is the /etc/default/grub file. Debian’s installer automatically makes some changes here. There are three lines you want to change. First, near the top, edit GRUB_CMDLINE_LINUX_DEFAULT and add console=tty0 console=ttyS0,57600n8r. By specifying console twice, you allow output to go both to the standard display and to the serial console. By specifying the serial console last, you make it be the preferred one for things like entering the root filesystem password.
Next, towards the bottom, make sure these two lines look like this:
GRUB_TERMINAL="console serial" GRUB_SERIAL_COMMAND="serial --unit=0 --speed=57600 --word=8 --parity=no --stop=1"
Finally, near the top, you may want to raise the GRUB_TIMEOUT to somewhere around 10 to 20 seconds since things may be a bit slower than you’re used to.
Save the file and run update-grub.
Now, GRUB will display on both your standard display and the serial console. You can edit the boot command from either. If you have a VGA or HDMI monitor attached, for instance, and need to not use the serial console, you can just edit the Linux command line in GRUB and remove the reference to ttyS0 for one boot. Easy!
That’s it. You now have a system that is fully operational from a serial terminal.
My original article from 2019 has some additional hints, including on how to convert from UTF-8 for these terminals.