A DEC VT520 as a Linux Writing Terminal (with german umlauts)
Using a VT520 on a Utilite Pro over a Zimodem Wi-Fi modem — with working German umlauts, UTF-8 files, and nano.
This guide describes a working setup and explains how to rebuild it. It covers the two problems that cost the most time:
- German umlauts are garbled or missing because the VT520 speaks ISO-8859-1 / DEC character sets, while modern Linux and Hugo expect UTF-8.
- Typed characters are invisible because
netkit-telnetdand the Zimodem negotiate the TelnetECHOoption incorrectly.
The solution keeps the host fully UTF-8, transcodes only inside GNU screen, and explicitly re-enables terminal echo for VT520 logins.
1. Result
After following this guide:
- You log in as
vtat the VT520 and land in ascreensession automatically. nanodisplaysÄÖÜäöüßcorrectly.- Files written from the VT520 are stored as UTF-8 on the host, so Hugo and every other modern tool work normally.
- SSH sessions from a PC (kitty, xterm, etc.) are completely unaffected.
- If the Zimodem link drops, logging in again reattaches the existing
screensession, including the opennanobuffer.
Tested environment:
| Component | Version / value |
|---|---|
| Host | CompuLab Utilite Pro, armv7l |
| OS | Ubuntu 22.04.5 LTS |
| Kernel | 4.1.15-cm-fx6-8.0 |
| Host locale | de_DE.UTF-8 |
| Terminal | DEC VT520, 80x24 |
| Modem | Zimodem (Wi-Fi serial modem), 9600 8N1 |
| Telnet server | netkit-telnetd 0.17-44build1 via inetd |
| screen | GNU screen 4.09.00 |
| Editor | GNU nano 6.2 |
| terminfo | ncurses-term (infocmp vt520 works) |
2. Topology
DEC VT520 Zimodem Utilite Pro (Linux)
ISO-8859-1 Wi-Fi bridge de_DE.UTF-8
80x24, 9600 8N1 ---> telnet client ---TCP/23--> inetd -> telnetd
XON/XOFF ATDT"host:port" -> login -> bash
-> screen
-> UTF-8 apps
(nano, shell)
The Zimodem is a serial-to-Telnet bridge. The VT520 thinks it is talking to a modem; the Linux host sees an ordinary Telnet login on port 23. No special terminal server or serial cable to the host is involved.
In the reference setup:
- Utilite Pro:
192.168.178.169 - Zimodem:
192.168.178.25 - Login user:
vt
Substitute your own addresses and user name where they appear.
3. Why umlauts break
3.1 Two incompatible encodings
Modern Linux uses UTF-8. In UTF-8, ä is two bytes:
ä -> C3 A4
ö -> C3 B6
ü -> C3 BC
ß -> C3 9F
The VT520 does not support UTF-8. It uses ISO-8859-1 (plus DEC supplemental character sets), where each character is one byte:
ä -> E4
ö -> F6
ü -> FC
ß -> DF
If you send UTF-8 bytes straight to the VT520, it prints two wrong characters (ä) or nothing useful. If you switch the whole host to ISO-8859-1, the VT520 looks fine but Hugo, Git, and every modern tool receive Latin-1 files and break.
3.2 The design decision
Keep the host in UTF-8. Transcode only on the VT520 connection.
GNU screen can translate between an inner and an outer encoding. The host applications keep talking UTF-8; screen converts to ISO-8859-1 for the VT520 and back again for keyboard input.
This has three benefits:
- Hugo and all files stay UTF-8.
- The VT520 gets the single-byte characters it understands.
- SSH sessions are untouched because the translation only exists inside the VT520’s
screen.
4. Prerequisites on the Linux host
Install the terminal definitions, screen, nano, and a Telnet server:
sudo apt update
sudo apt install screen nano ncurses-term telnetd
Make sure the German UTF-8 locale exists:
locale -a | grep -i de_DE.utf8
# if missing:
sudo locale-gen de_DE.UTF-8
sudo update-locale LANG=de_DE.UTF-8
Check that the VT520 terminal description is available:
infocmp vt520 >/dev/null && echo "vt520 terminfo OK"
Check that the Telnet server is listening:
ss -ltnp | grep ':23'
The reference host runs telnetd from inetd. Any working Telnet daemon on port 23 is fine; the ECHO bug described below is a netkit-telnetd behaviour and may differ on other implementations.
Security note: Telnet is unencrypted. Use this only on a trusted LAN, or put the VT520 connection behind a VPN. Do not expose port 23 to the Internet.
5. Step-by-step setup
All files live in the home directory of the login user, here /home/vt.
5.1 Create ~/.screenrc.vt520
This is the heart of the encoding fix:
# ~/.screenrc.vt520
# Outside (VT520): ISO-8859-1. Inside (applications): UTF-8.
# screen translates in both directions.
startup_message off
vbell off
defscrollback 1000
shell /bin/bash
defencoding utf8
screen -t shell
encoding utf8 iso8859-1
What the lines do:
| Line | Purpose |
|---|---|
startup_message off |
No copyright banner on a slow 80x24 screen. |
vbell off |
The VT520 has no useful visual bell. |
defscrollback 1000 |
Keep scrollback for reconnecting. |
shell /bin/bash |
Always run bash inside the window, independent of the account’s login shell. |
defencoding utf8 |
Default encoding for new windows is UTF-8. |
screen -t shell |
Create the first window and name it shell. |
encoding utf8 iso8859-1 |
Window (applications) = UTF-8, connected terminal (VT520) = ISO-8859-1. |
The argument order is defined by man screen: the first encoding is the window, the optional second one is the connected terminal.
5.2 Add the VT520 block to ~/.bashrc
Insert this block after the standard “if not running interactively, return” check and before the color/prompt setup. It must run for the outer Telnet login, before screen starts.
# ---------------------------------------------------------------------------
# VT520 via Zimodem (Telnet). The Zimodem reports TERM=zimodem, for which no
# terminfo exists. This applies only to that access path; SSH is untouched.
# ---------------------------------------------------------------------------
case "$TERM" in
[Zz]imodem|vt520|vt525)
if [ -z "${SSH_CONNECTION:-}" ] && [ -t 0 ] && [ -t 1 ]; then
export TERM=vt520
export VT520=1
export LANG=de_DE.UTF-8
export MANOPT="-E ascii"
unset LC_ALL
# The Zimodem does not negotiate NAWS, so the pty would be 0x0.
# The VT520 cannot do UTF-8 -> keep the outer side ISO-8859-1.
#
# netkit-telnetd offers DO ECHO; the Zimodem answers WONT ECHO.
# telnetd then offers WILL ECHO; the Zimodem answers DONT ECHO.
# Result: the pty starts with -echo, so input is invisible
# (but still works). Re-enable echo explicitly. VT520 only.
stty rows 24 cols 80 cs8 -parenb -istrip -ixon -iutf8 echo 2>/dev/null
# Reset the VT520 state on every login: SGR, margins, origin,
# character set, cursor. Otherwise a state left behind by nano or
# screen can make the prompt invisible while the keyboard works.
printf '\033[!p' # DECSTR soft reset
printf '\033[?4l' # jump scroll instead of smooth scroll
printf '\033[?6l' # origin mode off
printf '\033[?7h' # autowrap on
printf '\033[?25h' # cursor visible
printf '\033[0m' # attributes off
printf '\033[1;24r' # full scroll region
printf '\033[H\033[2J' # home and clear
fi
;;
esac
# Inside screen windows the pty is UTF-8 (screen translates to the outside).
if [ -n "${STY:-}" ]; then
stty iutf8 2>/dev/null
export MANOPT="-E ascii"
# The VT520 has no ANSI color support. Drop color aliases that may come
# from /etc/bash.bashrc; the color aliases below are not defined at all
# when VT520=1.
if [ -n "${VT520:-}" ]; then
unset LS_COLORS
unalias ls grep fgrep egrep 2>/dev/null
fi
fi
Then make the existing color block conditional, so the VT520 never receives --color=auto:
if [ -x /usr/bin/dircolors ] && [ -z "${VT520:-}" ]; then
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
alias ls='ls --color=auto'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'
fi
Two details matter:
[Zz]imodemhandles bothZimodem(the Zimodem default) andzimodem.-iutf8on the outer pty is correct: the VT520 sends ISO-8859-1 bytes. Insidescreen, theSTYbranch setsiutf8again for UTF-8.
5.3 Add auto-start to ~/.profile
Append this after the normal PATH setup:
# ---------------------------------------------------------------------------
# VT520 via Zimodem: start screen automatically.
# screen translates UTF-8 <-> ISO-8859-1 so nano writes UTF-8 files (Hugo)
# while the VT520 still shows umlauts. SSH sessions (kitty) are untouched.
# ---------------------------------------------------------------------------
if [ -z "${SSH_CONNECTION:-}" ] && [ -z "${STY:-}" ] && [ -t 0 ] && [ -t 1 ] \
&& [ ! -e "$HOME/.no-screen" ]; then
case "$TERM" in
vt520|vt525|[Zz]imodem)
if command -v screen >/dev/null 2>&1; then
exec screen -dRR -c "$HOME/.screenrc.vt520"
fi
;;
esac
fi
Why the guards matter:
SSH_CONNECTIONempty: never touch SSH logins.STYempty: do not nestscreeninside an existing session.-t 0and-t 1: only run for interactive terminals..no-screen: escape hatch for a plain shell.screen -dRR: detach a stale attachment, resume the newest session, or create one. This is what makes reconnect after a Zimodem drop work.
Order note: .profile sources .bashrc first. That is why the VT520 block sets TERM=vt520; by the time the auto-start check runs, the original Zimodem value may already be gone. The case therefore accepts vt520, vt525, and both spellings of Zimodem.
5.4 Optional helper scripts
These are not required, but they make life much easier.
~/vt520-check.sh — self-test
Run it at the VT520 after login. It checks the display, the keyboard byte encoding, and the encoding of a written file.
#!/bin/bash
# Check the VT520 session (run as user vt at the VT520).
printf 'TERM=%s LANG=%s Screen=%s Size=%s\n' \
"$TERM" "$LANG" "${STY:+yes}" "$(stty size 2>/dev/null)"
printf 'Display: ÄÖÜäöüß <-- must look exactly like this\n'
printf '\nType an ä and press Enter: '
IFS= read -r x
hex=$(printf '%s' "$x" | od -An -tx1 | tr -d ' \n')
printf '\nKeyboard sends: %s\n' "$hex"
case "$hex" in
c3a4) echo 'OK: keyboard sends UTF-8.' ;;
e4) echo 'ERROR: keyboard sends Latin-1 -> screen transcoding is missing.' ;;
*) echo "Unexpected: $hex" ;;
esac
printf '\nWrite a test file and check its encoding:\n'
printf 'äöüß ÄÖÜ\n' > /tmp/vt520-test.md
file -i /tmp/vt520-test.md
printf 'Bytes: '
od -An -tx1 /tmp/vt520-test.md
printf '\nExpected: charset=utf-8 and bytes c3a4 c3b6 c3bc c39f (not e4 f6 fc df).\n'
~/vt-reset.sh — reset from SSH
When the VT520 display is wedged but the host is reachable, run this from an SSH session. It finds the Telnet login’s pty and writes a clean DEC reset to it.
#!/bin/bash
# Send a clean reset to the VT520 console.
# Usage (from kitty/SSH when the VT520 display is stuck): ~/vt-reset.sh
set -u
pts="${1:-}"
if [ -z "$pts" ]; then
pts=$(ps -eo tty=,args= | awk '/login -h 192\.168\.178\.25/ {print $1; exit}')
fi
if [ -z "$pts" ]; then
echo "No VT520 session (login -h 192.168.178.25) found."
echo "Are you logged in at the VT520?"
exit 1
fi
dev="/dev/$pts"
if [ ! -w "$dev" ]; then
echo "Cannot write to $dev (permission denied?)."
exit 1
fi
{
printf '\033[!p' # DECSTR soft reset
printf '\033[?4l' # jump scroll
printf '\033[?6l' # origin off
printf '\033[?7h' # autowrap on
printf '\033[?25h' # cursor visible
printf '\033[0m' # attributes off
printf '\033[1;24r' # full scroll region
printf '\033[H\033[2J' # home and clear
} > "$dev"
echo "Reset sent to $dev."
echo "If the display is still stuck: at the VT520 press '+++' (2 s pause), then"
echo 'ATF4 / AT&W / ATDT"192.168.178.169:23".'
The IP in the awk pattern must match your Zimodem address.
~/vt520-da.sh — terminal identification
A Python script that sends DEC DA, DECRQM, and DECRQSS queries and stores the raw answers. Useful when a VT520 behaves unexpectedly. It must run outside screen, directly on /dev/tty. See the deployed file for the full query list; it is a diagnostic tool, not part of normal operation.
5.5 Make the scripts executable
chmod +x ~/vt520-check.sh ~/vt-reset.sh ~/vt520-da.sh
5.6 Test from a PC first
Before reconnecting the VT520, verify that SSH is still normal:
ssh vt@192.168.178.169
echo "$TERM" # should be xterm-256color or similar
echo "$STY" # should be empty
locale # UTF-8
If screen starts over SSH, one of the guards is wrong. Check that SSH_CONNECTION is set and that TERM is not Zimodem.
6. Logging in and writing
-
Wake the VT520 and press Enter, or dial from the Zimodem:
+++ (three plus signs, then wait 2 seconds, no Enter) ATDT"192.168.178.169:23" -
At
login:, typevtand press Enter. The user name is not echoed — this is the Telnet ECHO bug, not a fault. Type it blind. -
At
Password:, type the password. Passwords are never echoed. -
After login,
.bashrcfixes the pty, resets the VT520, and.profilestartsscreen. The prompt appears with visible input. -
Edit a post:
nano content/posts/my-post.md -
Save with
Ctrl-O,Enter, exit withCtrl-X.
Because screen translates, nano sees a UTF-8 terminal and writes UTF-8. The VT520 sees ISO-8859-1 and displays umlauts correctly.
Reconnecting after a dropped link
If the Zimodem connection drops, the screen session keeps running on the host. Dial in again and log in; screen -dRR reattaches the same session, including the open nano buffer.
Plain shell without screen
touch ~/.no-screen # next VT520 login: no screen
rm ~/.no-screen # back to automatic screen
Use this only for testing. Without screen, umlauts will break again.
7. The invisible-input bug (Telnet ECHO)
7.1 Symptom
The prompt is visible and commands execute, but typed characters never appear. This is especially confusing at the login prompt, where the user name is also invisible.
7.2 Root cause
netkit-telnetd and the Zimodem disagree about who echoes:
telnetd -> IAC DO ECHO
Zimodem -> IAC WONT ECHO
telnetd -> IAC WILL ECHO
Zimodem -> IAC DONT ECHO
The pty is left in -echo. Input reaches the shell, but the terminal driver does not echo it back.
This was confirmed by reading the Zimodem source (pet2asc.ino, handleAsciiIAC) and by reproducing the negotiation locally. It is not an XOFF problem and not a VT520 fault.
7.3 Immediate fix
At the VT520, type blind and press Enter:
stty echo
Input becomes visible immediately.
7.4 Permanent fix
The stty ... echo line in the ~/.bashrc VT520 block re-enables echo on every VT520 login. It is gated on TERM=Zimodem/vt520 and on SSH_CONNECTION being empty, so SSH sessions are unaffected.
The login prompt itself remains blind because ~/.bashrc runs only after authentication. That is expected. Just type vt and Enter.
8. The frozen-display problem (flow control)
This is a different failure from the ECHO bug.
8.1 Symptom
No new text appears at all, not even a prompt. The keyboard may still send bytes, but the screen does not update.
8.2 Cause
The VT520 uses XON/XOFF flow control. It sends XOFF when its buffer is full or when it enters Hold. The Zimodem pauses host-to-terminal output until it sees XON again. If that XON is lost, the display stays frozen forever.
8.3 Recovery
-
Press a bare
Ctrl-Q. Do not pressCtrl-A q— insidescreenthat would quit screen. -
Alternatively press the Hold key:
F1on a VT keyboard,Scroll Lockon a PC keyboard. -
If that does not help, reset the modem blindly at the VT520:
+++ (three plus, 2 second pause, no Enter) Enter ATZ Enter reset the Zimodem ATF4 Enter disable flow control AT&W Enter save the setting ATDT"192.168.178.169:23" Enter dial again -
Log in again.
ATF4 makes the Zimodem ignore XOFF and keep sending. At 9600 baud with jump scroll this is safe and is the most robust setting for this terminal.
8.4 Missing prompt but working keyboard
If commands execute but the prompt is invisible, the VT520 state was left inconsistent by a full-screen program. Every login resets it (DECSTR, jump scroll, full scroll region, clear). From SSH you can trigger the same reset without logging in at the VT520:
~/vt-reset.sh
9. Verification
Run at the VT520:
~/vt520-check.sh
Expected output:
TERM=screen LANG=de_DE.UTF-8 Screen=yes Size=24 80
Display: ÄÖÜäöüß <-- must look exactly like this
...
Keyboard sends: c3a4
OK: keyboard sends UTF-8.
...
/tmp/vt520-test.md: text/plain; charset=utf-8
Bytes: c3a4 c3b6 c3bc c39f ...
Also check:
stty -a | grep -o '\becho\b' # must print echo
echo "$STY" # non-empty inside screen
locale | head -1 # LANG=de_DE.UTF-8
From SSH, confirm that nothing changed:
echo "$TERM" # xterm-256color or similar, not vt520
echo "$STY" # empty
alias ls # may contain --color=auto
10. Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Typed characters invisible, commands run | Telnet ECHO negotiation leaves pty at -echo |
Blindly type stty echo; permanent fix in ~/.bashrc |
| Login name invisible | .bashrc has not run yet; echo is off before authentication |
Expected; type vt and Enter |
ä instead of ä |
UTF-8 bytes reaching the VT520; no screen transcoding | Check echo $STY; start screen with ~/.screenrc.vt520 |
Umlauts appear as ? or boxes |
Outer encoding or iutf8 wrong |
Check locale, stty -a, and the screenrc encoding line |
| Colors, inverse text, escape garbage | ANSI color aliases active on a monochrome terminal | Ensure VT520=1; disable LS_COLORS and color aliases |
| Screen freezes completely | XOFF / Hold / Zimodem flow control | Bare Ctrl-Q, Hold key, then ATZ + ATF4 + AT&W |
| Prompt missing but input works | VT520 state corrupted by a full-screen app | Log out and in, or run ~/vt-reset.sh from SSH |
| PTY is 0x0 or 1x1 | Zimodem does not negotiate NAWS | stty rows 24 cols 80 (already in .bashrc) |
screen starts over SSH |
Missing SSH_CONNECTION / STY guard |
Check ~/.profile conditions |
screen does not start at VT520 |
~/.no-screen exists, or TERM does not match |
rm ~/.no-screen; check echo $TERM |
| Screen session lost after reconnect | screen was not used, or host rebooted |
Use screen -dRR; screen survives link drops, not reboots |
Manual escape from a wedged session
If screen itself is unresponsive but the shell works, detach with Ctrl-A d. If even that fails, disconnect at the modem and dial in again; screen -dRR reattaches.
11. Character-set limitations
The VT520 in ISO-8859-1 mode handles the German basics:
Ä Ö Ü ä ö ü ß § ° µ ± ² ³
It cannot display characters that do not exist in ISO-8859-1, notably:
„ “ ” ‚ ‘ ’ – — … € Œ œ Š š Ž ž
For Hugo posts this matters. The host file is still UTF-8, so such characters are preserved if they are inserted from another machine. But they cannot be typed or displayed at the VT520. Practical rules:
- Write typographic quotes, en/em dashes, ellipses, and the euro sign from a PC, or
- use ASCII substitutes at the VT520 (
",-,...,EUR), or - keep them out of the body text and add them during a later editing pass.
MANOPT="-E ascii" reduces the chance that man pages send characters the VT520 cannot show.
12. Why SSH stays unaffected
All VT520 logic is guarded by two independent conditions:
$TERMmust beZimodem,zimodem,vt520, orvt525.SSH_CONNECTIONmust be empty.
An SSH login from kitty reports TERM=xterm-256color and has SSH_CONNECTION set, so neither the reset block nor the screen auto-start runs. Color aliases remain active, the locale stays UTF-8, and the pty is a normal UTF-8 pty.
This was verified explicitly:
TERM=xterm-256color
STY= (empty)
LANG=de_DE.UTF-8
alias ls ls --color=auto
13. File overview and backups
| Path | Purpose |
|---|---|
~/.screenrc.vt520 |
UTF-8 ↔ ISO-8859-1 translation, bash inside windows |
~/.bashrc |
VT520 reset, stty echo, VT520=1, color guard |
~/.profile |
guarded screen -dRR auto-start |
~/.no-screen |
if present: no screen (test/escape hatch) |
~/vt520-check.sh |
display, keyboard, and encoding self-test |
~/vt-reset.sh |
reset the VT520 pty from SSH |
~/vt520-da.sh |
DEC identification and keyboard diagnostic |
~/VT520-HILFE.txt |
short German recovery guide |
Before changing these files, back them up:
for f in ~/.bashrc ~/.profile ~/.screenrc.vt520 ~/VT520-HILFE.txt; do
[ -e "$f" ] && cp -a "$f" "$f.bak-$(date +%Y%m%d-%H%M%S)"
done
To undo everything, restore the backups and remove ~/.screenrc.vt520 and ~/.no-screen.
14. Adapting to your own network
Change these values:
- Zimodem address in
~/vt-reset.shand in anyATDTcommand. - Host address in the Zimodem dial string (
ATDT"192.168.178.169:23"). - Login user if not
vt. - Locale if not German: adjust
LANGand the outer encoding. For a US setup,en_US.UTF-8withISO-8859-1still works for Western European characters; for other scripts you need a terminal that supports UTF-8. - Baud rate and flow control to match your VT520 and Zimodem configuration. If flow control causes trouble,
ATF4+AT&Wis the reliable choice at 9600 baud.
If your Telnet daemon negotiates ECHO correctly, the stty echo line is harmless. If it does not, the line is essential.
15. Short version
If you only remember five things:
- Keep the host UTF-8.
- Run
screenwithencoding utf8 iso8859-1. - Auto-start
screen -dRRonly forTERM=Zimodem/vt520and only outside SSH. - Put
stty ... echoin the VT520 login block; the Telnet ECHO negotiation is broken. - Frozen display is flow control: bare
Ctrl-Q, thenATZ/ATF4/AT&Wif needed.
That is the whole setup.
Webmentions
Reaktionen aus dem IndieWeb (Replies, Likes, Reposts).
- Lade Webmentions …
Noch keine Webmentions.
Jan Montag