Set Up a Linux Serial Login Safely with agetty

A serial console with no login prompt is almost always an agetty problem. This guide gets one running on a chosen device with an explicit speed and terminal type, and shows you how to preview the prelogin banner without starting a second login service by accident.

Allow about 15 minutes for a local console and longer if you are testing a remote serial adapter. You need root access, a serial device such as /dev/ttyS1, a terminal or terminal server wired to it, and the agetty command from util-linux. The examples below describe util-linux 2.41.3, installed on this machine.

1. Identify the line before changing it

Confirm the device and the installed implementation.

ls -l /dev/ttyS1
agetty --version
man agetty

Swap /dev/ttyS1 for the device actually wired to your terminal. A path existing under /dev is not proof the port is connected, and starting agetty on the wrong tty can make the real console look broken instead. The agetty and getty names refer to the same util-linux implementation here.

2. Choose the agetty arguments

Choose a descending list of baud rates and a terminal type.

agetty 115200 ttyS1 vt100

The synopsis is agetty [options] port [baud_rate...] [term]. The port is relative to /dev, so ttyS1 means /dev/ttyS1. For a serial terminal, agetty defaults to keeping the current speed and only falls back to 9600 if that fails. Giving the speed explicitly makes the setup far easier to inspect and reproduce later.

If the device gets used at more than one speed, list them highest to lowest. Each BREAK steps through the list as a circular sequence:

agetty --timeout 60 ttyS1 115200,38400,9600 vt100

The timeout stops agetty if no login name shows up within 60 seconds. Handy on dial-in lines, but the local manpage does not recommend it for hardwired terminals. A virtual terminal needs no baud rate at all; its default terminal type is linux. Otherwise agetty defaults to vt100 unless you supply something else.

3. Force the line local when carrier detect is absent

Use --local-line only when the wiring does not provide carrier detect.

agetty --local-line=always 115200 ttyS1 vt100

Leave this option off and the default mode is auto, following the kernel's CLOCAL setting. Give the option with no mode and the default becomes always; spelling it out makes the intent obvious to the next person reading the unit file. Use --local-line=never when carrier detect must be present. A directly connected terminal that waits forever for a prompt often means missing carrier detect, but check the wiring and tty first before you chase software.

4. Preview the issue message without launching a login

Preview the message that agetty would print on the current terminal.

agetty --show-issue

The normal source is /etc/issue. If it exists, agetty also reads /etc/issue.d and prints files ending in .issue in version-sort order. Newer util-linux systems can fall back to /run/issue and then /usr/lib/issue when the default file is missing. Use --issue-file for a colon-separated list of files or directories, or --noissue to suppress the message entirely.

Warning: keep the banner free of secrets. It shows before authentication and can carry escape sequences such as \n for the host name, \l for the tty line, \r for the kernel release and \t for the current time. The issue(5) page covers the general file, while agetty documents the Linux escape sequences it expands.

To make a small change, save a backup first, then edit as root:

sudo cp -p /etc/issue /etc/issue.bak
sudoedit /etc/issue
agetty --show-issue

Recovery: undo that example with sudo cp -p /etc/issue.bak /etc/issue. Do not overwrite an existing backup without checking it first, or your recovery path disappears along with the mistake.

5. Start one test instance

Stop any existing getty on the test line, then start agetty once in the foreground.

sudo systemctl stop [email protected]
sudo agetty --local-line=always 115200 ttyS1 vt100

Warning: this step disrupts the service. The first command is only an example for systemd hosts; inspect the actual unit before stopping anything. The second occupies the terminal until it exits, so run it from another administration path entirely. Connect the terminal at 115200 8N1 unless told otherwise, press Enter, and expect a login: prompt. Ctrl-C ends the foreground test.

Prompt unreadable? Check both ends agree on speed, character size, parity and stop bits. agetty adapts several tty settings while reading the login name, but it cannot fix a physically wrong connection or a mismatched terminal emulator for you.

6. Run it under the service manager

Install the tested command in the service manager's configuration, then verify its state.

sudo systemctl enable --now [email protected]
systemctl status [email protected] --no-pager
journalctl -u [email protected] -b --no-pager

Never run a second agetty on the same port. Two readers fighting over one tty just produces confusing prompts and lost input. Distribution unit templates vary, so check the unit and its generated command with systemctl cat [email protected] before adding overrides. On SysV-style init, agetty is normally started from an /etc/inittab entry like the examples in its manpage; keep the exact baud rate, port and terminal type in that one entry, nowhere else.

After changing /etc/issue, agetty --reload asks running instances to refresh their displayed prompts, but only for lines where nobody has started logging in yet. If that feature is not available on your system, restart the relevant service during a proper maintenance window instead.

Where ttytype fits

/etc/ttytype is not agetty's login configuration, and mixing the two up wastes time. It just maps a terminal type to a tty name without the /dev/ prefix, for example:

vt100 ttyS1

The tset command uses that mapping to pick the TERM environment value for the current tty. For an agetty-managed line, supplying vt100 as the final argument is the direct, visible choice; reach for /etc/ttytype only if a later shell environment needs its traditional mapping.

Security boundaries and failure recovery

Security boundary: agetty normally invokes /bin/login as root. Treat --autologin, --login-program and --login-options as security-sensitive: the last one can pass user-controlled login text straight into another program. If a custom login program supports it, put -- before the username placeholder so later text cannot be parsed as options, and confirm that program's own argument rules before you enable the service.

Test left the line occupied? Press Ctrl-C. Stopped a systemd unit? Restore it with sudo systemctl start [email protected]; if it was enabled and should no longer start at boot, use sudo systemctl disable --now [email protected]. Keep an out-of-band root session open the whole time you are changing serial console services.

Done means