Skip to main content
  1. Linux Articles/
  2. Ubuntu 26.04 LTS Server/

Setting Up a telnet Server on Ubuntu 26.04 LTS Server

Table of Contents

Before using a telnet server

telnet sends user names, passwords and everything you type without encryption. Do not use it on a server exposed to the internet. For remote login, use an SSH server instead.

It only makes sense in a closed test environment, or when you have to talk to equipment that speaks nothing but telnet. Besides the setup steps, this article uses a packet capture to show that the password really does travel in readable form.

File to editPurpose
/etc/inetd.confThe telnet line (switching it on and off)
/etc/hosts.denyRestricting where connections may come from

Checking what is installed

The client is installed from the start; the server is not.

On the server side (sv1) - example
kazulog@sv1:~$ apt list --installed 2>/dev/null | grep -E "telnet|inetd" | cat
inetutils-telnet/resolute-updates,resolute-security,now 2:2.7-2ubuntu1.1 amd64 [installed,automatic]
telnet/resolute-updates,resolute-security,now 0.17+2.7-2ubuntu1.1 all [installed,automatic]
kazulog@sv1:~$ apt-cache policy inetutils-telnetd | head -3
inetutils-telnetd:
  Installed: (none)
  Candidate: 2:2.7-2ubuntu1.1
On the client side (sv2) - example
kazulog@sv2:~$ which telnet ssh
/usr/bin/telnet
/usr/bin/ssh
PackageRole
inetutils-telnetThe client (the telnet command), installed by default
inetutils-telnetdThe server. The package named telnetd is only a dummy that installs this one

Installing the telnet server

Installation command
sudo apt install -y inetutils-telnetd

The telnet server does not listen by itself; the super-server inetutils-inetd accepts the connection and starts it, so it is installed too. How that works is covered in Configuring inetd.

Installation - example
kazulog@sv1:~$ sudo apt install -y inetutils-telnetd | cat
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

Reading package lists...
Building dependency tree...
Reading state information...
Solving dependencies...
Installing:
  inetutils-telnetd

Installing dependencies:
  inetutils-inetd  tcpd  update-inetd

Summary:
  Upgrading: 0, Installing: 4, Removing: 0, Not Upgrading: 96
  Download size: 153 kB
  Space needed: 546 kB / 63.1 GB available

Get:1 http://archive.ubuntu.com/ubuntu resolute/universe amd64 tcpd amd64 7.6.q-36build2 [24.6 kB]
Get:2 http://archive.ubuntu.com/ubuntu resolute/main amd64 update-inetd all 4.54build1 [23.0 kB]
Get:3 http://archive.ubuntu.com/ubuntu resolute-updates/universe amd64 inetutils-inetd amd64 2:2.7-2ubuntu1.1 [45.2 kB]
Get:4 http://archive.ubuntu.com/ubuntu resolute-updates/universe amd64 inetutils-telnetd amd64 2:2.7-2ubuntu1.1 [60.6 kB]
Preconfiguring packages ...
Fetched 153 kB in 2s (85.3 kB/s)
Selecting previously unselected package tcpd.
(Reading database ... 91400 files and directories currently installed.)
Preparing to unpack .../tcpd_7.6.q-36build2_amd64.deb ...
Unpacking tcpd (7.6.q-36build2) ...
Selecting previously unselected package update-inetd.
Preparing to unpack .../update-inetd_4.54build1_all.deb ...
Unpacking update-inetd (4.54build1) ...
Selecting previously unselected package inetutils-inetd.
Preparing to unpack .../inetutils-inetd_2%3a2.7-2ubuntu1.1_amd64.deb ...
Unpacking inetutils-inetd (2:2.7-2ubuntu1.1) ...
Selecting previously unselected package inetutils-telnetd.
Preparing to unpack .../inetutils-telnetd_2%3a2.7-2ubuntu1.1_amd64.deb ...
Unpacking inetutils-telnetd (2:2.7-2ubuntu1.1) ...
Setting up update-inetd (4.54build1) ...
Setting up tcpd (7.6.q-36build2) ...
Setting up inetutils-inetd (2:2.7-2ubuntu1.1) ...
Created symlink '/etc/systemd/system/inetd.service''/usr/lib/systemd/system/inetutils-inetd.service'.
Created symlink '/etc/systemd/system/multi-user.target.wants/inetutils-inetd.service''/usr/lib/systemd/system/inetutils-inetd.service'.
Setting up inetutils-telnetd (2:2.7-2ubuntu1.1) ...

Installing it is not enough. Line 23 of /etc/inetd.conf gets the telnet entry, but it starts with #<off># and is inactive. With no active line, inetd skips starting, and port 23 stays closed.

/etc/inetd.conf and inetd right after installation - example
kazulog@sv1:~$ grep -n telnet /etc/inetd.conf
23:#<off># telnet	stream	tcp	nowait	root	/usr/sbin/tcpd	/usr/sbin/telnetd
kazulog@sv1:~$ systemctl status inetutils-inetd --no-pager | head -9 | cat
○ inetutils-inetd.service - GNU Network Utilities internet superserver
     Loaded: loaded (/usr/lib/systemd/system/inetutils-inetd.service; enabled; preset: enabled)
     Active: inactive (dead) (Result: exec-condition) since Sat 2026-09-12 09:08:41 JST; 7s ago
 Invocation: 5197dfcb6b574992b9abab5f7049d3a7
  Condition: start condition unmet at Sat 2026-09-12 09:08:41 JST; 7s ago
       Docs: man:inetutils-inetd(8)
             https://www.gnu.org/software/inetutils/manual/
    Process: 2629 ExecCondition=grep -qr ^[0-9A-Za-z/] /etc/inetd.conf /etc/inetd.d/ (code=exited, status=1/FAILURE)
   Mem peak: 1.7M
kazulog@sv1:~$ sudo ss -tlnp 'sport = :23'; echo "ss rc=$?"
State                  Recv-Q                  Send-Q                                   Local Address:Port                                   Peer Address:Port                 Process
ss rc=0

Enabling telnet (/etc/inetd.conf)

Remove the leading #<off># from line 23 of /etc/inetd.conf. Use the dedicated command update-inetd for this line (editing by hand also works, but update-inetd reloads inetd as well).

Command to enable it
sudo update-inetd --enable telnet
Line 23 of /etc/inetd.conf (after the change)
telnet	stream	tcp	nowait	root	/usr/sbin/tcpd	/usr/sbin/telnetd

With an active line, inetd starts and listens on port 23. The protocol field says tcp, so it listens on IPv4 only.

Enabling it - example
kazulog@sv1:~$ sudo update-inetd --enable telnet
kazulog@sv1:~$ grep -n telnet /etc/inetd.conf
23:telnet	stream	tcp	nowait	root	/usr/sbin/tcpd	/usr/sbin/telnetd
kazulog@sv1:~$ systemctl is-active inetutils-inetd
active
kazulog@sv1:~$ sudo ss -tlnp 'sport = :23'
State              Recv-Q             Send-Q                          Local Address:Port                           Peer Address:Port             Process
LISTEN             0                  10                                    0.0.0.0:23                                  0.0.0.0:*                 users:(("inetutils-inetd",pid=3120,fd=4))             

Connecting

Create a test user. This password exists to show that it travels in readable form; do not use it in production.

Creating the test user - example
kazulog@sv1:~$ sudo useradd -m -s /bin/bash telnetdemo
kazulog@sv1:~$ echo 'telnetdemo:TelnetIsPlaintext' | sudo chpasswd
kazulog@sv1:~$ id telnetdemo
uid=1001(telnetdemo) gid=1001(telnetdemo) groups=1001(telnetdemo)

Connect from another server, log in and run w.

Logging in over telnet - example
kazulog@sv2:~$ telnet 192.168.100.10
Trying 192.168.100.10...
Connected to 192.168.100.10.
Escape character is '^]'.

Linux 7.0.0-30-generic (ubuntu) (pts/0)

sv1 login: telnetdemo
Password: 
Welcome to Ubuntu 26.04 LTS (GNU/Linux 7.0.0-30-generic x86_64)

 * Documentation:  https://docs.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

 System information as of Sat Sep 12 09:09:13 JST 2026

  System load:  0.4               Processes:             108
  Usage of /:   3.5% of 60.93GB   Users logged in:       0
  Memory usage: 12%               IPv4 address for ens2: 10.19.12.11
  Swap usage:   0%


Expanded Security Maintenance for Applications is not enabled.

101 updates can be applied immediately.
91 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status



The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

telnetdemo@sv1:~$ w
 09:09:14 up 7 min,  1 user,  load average: 0.40, 0.25, 0.14
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU  WHAT
telnetde pts/0    192.168.100.20   09:09    1.00s  0.04s   ?    w
telnetdemo@sv1:~$ exit
logout
Connection closed by foreign host.

Confirming the password travels in the clear

The login above was done while capturing on the link between sv1 and the switch. Extracting what the client sent shows exactly what was typed.

Data sent by the client - example
$ tshark -r ubuntu-telnet.pcap -n -Y 'ip.src==192.168.100.20 && telnet.data' -T fields -e frame.number -e telnet.data
22	telnetdemo\r
27	TelnetIsPlaintext\r
40	w\r
45	exit\r

The user name (No.22), the password (No.27) and the commands (w in No.40, exit in No.45) are all readable. The password packet in hex contains the string as typed.

Contents of No.27 - example
$ tshark -r ubuntu-telnet-no27.pcap -n -x
0000  52 54 00 9b cb ec 52 54 00 3b a6 5b 08 00 45 00   RT....RT.;.[..E.
0010  00 46 39 44 40 00 40 06 b7 fe c0 a8 64 14 c0 a8   .F9D@.@.....d...
0020  64 0a 8a e4 00 17 8d 63 fa f2 92 5d 74 f7 80 18   d......c...]t...
0030  00 fb 8d 50 00 00 01 01 08 0a 33 01 40 c2 2e be   ...P......3.@...
0040  78 34 54 65 6c 6e 65 74 49 73 50 6c 61 69 6e 74   x4TelnetIsPlaint
0050  65 78 74 0d                                       ext.
Download the pcap of the packet in the tshark output above (No.27)

Comparing with SSH

Do the same thing as the same user, over SSH with password authentication.

Logging in over SSH - example
kazulog@sv2:~$ ssh -o PubkeyAuthentication=no -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null telnetdemo@192.168.100.10
Warning: Permanently added '192.168.100.10' (ED25519) to the list of known hosts.
telnetdemo@192.168.100.10's password:
Welcome to Ubuntu 26.04 LTS (GNU/Linux 7.0.0-30-generic x86_64)

 * Documentation:  https://docs.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

 System information as of Sat Sep 12 09:11:17 JST 2026

  System load:  0.13              Processes:             109
  Usage of /:   3.5% of 60.93GB   Users logged in:       0
  Memory usage: 12%               IPv4 address for ens2: 10.19.12.11
  Swap usage:   0%


Expanded Security Maintenance for Applications is not enabled.

101 updates can be applied immediately.
91 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


telnetdemo@sv1:~$ w
 09:11:17 up 9 min,  1 user,  load average: 0.13, 0.18, 0.12
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU  WHAT
telnetde pts/0    192.168.100.20   09:11    0.00s  0.05s   ?    w
telnetdemo@sv1:~$ exit
logout
Connection to 192.168.100.10 closed.

In the same capture, not a single SSH packet contains the password string.

No password in the SSH traffic - example
$ tshark -r ubuntu-telnet.pcap -n -Y 'tcp.port==22 && frame contains "TelnetIsPlaintext"' | wc -l
       0

The only readable part is the version string exchanged at the start.

SSH version strings - example
$ tshark -r ubuntu-telnet.pcap -n -Y 'ssh.protocol' -T fields -e frame.number -e ip.src -e ssh.protocol
62	192.168.100.20	SSH-2.0-OpenSSH_10.2p1 Ubuntu-2ubuntu3.5
64	192.168.100.10	SSH-2.0-OpenSSH_10.2p1 Ubuntu-2ubuntu3.5

An encrypted packet from the client shows no readable string in hex either.

Contents of an encrypted packet - example
$ tshark -r ubuntu-telnet-no74.pcap -n -x
0000  52 54 00 9b cb ec 52 54 00 3b a6 5b 08 00 45 b8   RT....RT.;.[..E.
0010  00 88 97 ae 40 00 40 06 58 9a c0 a8 64 14 c0 a8   ....@.@.X...d...
0020  64 0a 80 bc 00 16 50 bf 95 d5 93 3b 05 b2 80 18   d.....P....;....
0030  01 01 94 85 00 00 01 01 08 0a 53 3a 79 f6 5c c6   ..........S:y.\.
0040  25 61 00 00 00 0c 0a 15 00 00 00 00 00 00 00 00   %a..............
0050  00 00 01 28 41 dc e0 7e 4d fe c6 7e 1a e2 a3 3a   ...(A..~M..~...:
0060  d0 52 39 09 3e af 3c 1f 14 8e d1 bd 1c 2d 65 e4   .R9.>.<......-e.
0070  1f 90 c9 75 3f f2 fb b7 cc 2e 36 04 61 b9 37 6e   ...u?.....6.a.7n
0080  45 25 45 53 ed 1c e9 76 9b 09 5f 15 90 ea 48 72   E%ES...v.._...Hr
0090  85 22 04 a7 dc 9b                                 ."....
Download the pcap of the packet in the tshark output above (No.74)
ItemtelnetSSH
User name and passwordReadableEncrypted
Commands typedReadableEncrypted
What is readableEverythingOnly the initial version string

Restricting where connections come from (/etc/hosts.deny)

The registered line goes through /usr/sbin/tcpd, so /etc/hosts.deny can refuse a source. The daemon name is telnetd.

File to edit
sudo vi /etc/hosts.deny
Appended to /etc/hosts.deny
telnetd: 192.168.100.20
/etc/hosts.deny after the change - example
kazulog@sv1:~$ cat /etc/hosts.deny
# /etc/hosts.deny: list of hosts that are _not_ allowed to access the system.
#                  See the manual pages hosts_access(5) and hosts_options(5).
#
# Example:    ALL: some.host.name, .some.domain
#             ALL EXCEPT in.fingerd: other.host.name, .other.domain
#
# If you're going to protect the portmapper use the name "rpcbind" for the
# daemon name. See rpcbind(8) and rpc.mountd(8) for further information.
#
# The PARANOID wildcard matches any host whose name does not match its
# address.
#
# You may wish to enable this to ensure any programs that don't
# validate looked up hostnames still leave understandable logs. In past
# versions of Debian this has been the default.
# ALL: PARANOID
telnetd: 192.168.100.20

Only telnetd is named, so other services such as SSH are unaffected. The refused side is disconnected right after connecting.

On the refused side - example
kazulog@sv2:~$ timeout 8 telnet 192.168.100.10 < /dev/null
Trying 192.168.100.10...
Connected to 192.168.100.10.
Escape character is '^]'.
Connection closed by foreign host.
The refusal in the log - example
kazulog@sv1:~$ sudo journalctl --since "-5 min" --no-pager | grep "refused connect" | cat
Sep 12 09:14:42 sv1 telnetd[4642]: refused connect from 192.168.100.20 (192.168.100.20)

The evaluation order of hosts.allow and hosts.deny, and the warning about writing ALL: ALL, are covered in the inetd article.

Final state of the configuration files

This is the state with everything above applied. Only two files were touched: /etc/inetd.conf and /etc/hosts.deny.

Configuration files and service state
kazulog@sv1:~$ grep -n telnet /etc/inetd.conf
23:telnet	stream	tcp	nowait	root	/usr/sbin/tcpd	/usr/sbin/telnetd
kazulog@sv1:~$ cat /etc/hosts.deny
# /etc/hosts.deny: list of hosts that are _not_ allowed to access the system.
#                  See the manual pages hosts_access(5) and hosts_options(5).
#
# Example:    ALL: some.host.name, .some.domain
#             ALL EXCEPT in.fingerd: other.host.name, .other.domain
#
# If you're going to protect the portmapper use the name "rpcbind" for the
# daemon name. See rpcbind(8) and rpc.mountd(8) for further information.
#
# The PARANOID wildcard matches any host whose name does not match its
# address.
#
# You may wish to enable this to ensure any programs that don't
# validate looked up hostnames still leave understandable logs. In past
# versions of Debian this has been the default.
# ALL: PARANOID
telnetd: 192.168.100.20
kazulog@sv1:~$ systemctl is-enabled inetutils-inetd; systemctl is-active inetutils-inetd
enabled
active
kazulog@sv1:~$ sudo ss -tlnp 'sport = :23'
State              Recv-Q             Send-Q                          Local Address:Port                           Peer Address:Port             Process
LISTEN             0                  10                                    0.0.0.0:23                                  0.0.0.0:*                 users:(("inetutils-inetd",pid=3120,fd=4))             
kazulog@sv1:~$ dpkg -l | grep -E "inetutils|tcpd|update-inetd" | cat
ii  inetutils-inetd                         2:2.7-2ubuntu1.1                           amd64        internet super server
ii  inetutils-telnet                        2:2.7-2ubuntu1.1                           amd64        telnet client
ii  inetutils-telnetd                       2:2.7-2ubuntu1.1                           amd64        telnet server
ii  tcpd                                    7.6.q-36build2                             amd64        Wietse Venema's TCP wrapper utilities
ii  tcpdump                                 4.99.6-1                                   amd64        command-line network traffic analyzer
ii  telnet                                  0.17+2.7-2ubuntu1.1                        all          transitional dummy package for inetutils-telnet default switch
ii  update-inetd                            4.54build1                                 all          inetd configuration file updater
FileChange
/etc/inetd.confRemove #<off># from line 23 (update-inetd --enable telnet)
/etc/hosts.denyAppend telnetd: 192.168.100.20
Packagesinetutils-telnetd, plus inetutils-inetd / tcpd / update-inetd pulled in with it

Stopping and removing

To stop it temporarily, switch the line back off. The #<off># prefix returns to line 23 and port 23 closes.

Command to disable it
sudo update-inetd --disable telnet

Removing the package also removes the telnet line from /etc/inetd.conf. The packages pulled in with it go with autoremove, but inetutils-inetd and update-inetd stay in the rc state with their configuration files, and /etc/inetd.conf remains.

Disabling and removing - example
kazulog@sv1:~$ sudo update-inetd --disable telnet
kazulog@sv1:~$ grep -n telnet /etc/inetd.conf
23:#<off># telnet	stream	tcp	nowait	root	/usr/sbin/tcpd	/usr/sbin/telnetd
kazulog@sv1:~$ sudo ss -tlnp 'sport = :23'; echo "ss rc=$?"
State                  Recv-Q                  Send-Q                                   Local Address:Port                                   Peer Address:Port                 Process
ss rc=0
kazulog@sv1:~$ sudo apt purge -y inetutils-telnetd | cat
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

Reading package lists...
Building dependency tree...
Reading state information...
Solving dependencies...
The following packages were automatically installed and are no longer required:
  inetutils-inetd  tcpd  update-inetd
Use 'sudo apt autoremove' to remove them.

REMOVING:
  inetutils-telnetd*

Summary:
  Upgrading: 0, Installing: 0, Removing: 1, Not Upgrading: 96
  Freed space: 184 kB

(Reading database ... 91438 files and directories currently installed.)
Removing inetutils-telnetd (2:2.7-2ubuntu1.1) ...
Processing triggers for man-db (2.13.1-1build1) ...
(Reading database ... 91429 files and directories currently installed.)
Purging configuration files for inetutils-telnetd (2:2.7-2ubuntu1.1) ...
kazulog@sv1:~$ sudo apt autoremove -y | cat
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

Reading package lists...
Building dependency tree...
Reading state information...
Solving dependencies...
REMOVING:
  inetutils-inetd  tcpd  update-inetd

Summary:
  Upgrading: 0, Installing: 0, Removing: 3, Not Upgrading: 96
  Freed space: 361 kB

(Reading database ... 91429 files and directories currently installed.)
Removing inetutils-inetd (2:2.7-2ubuntu1.1) ...
Removing tcpd (7.6.q-36build2) ...
Removing update-inetd (4.54build1) ...
Processing triggers for man-db (2.13.1-1build1) ...
kazulog@sv1:~$ dpkg -l | grep -E "inetd|telnet|tcpd" | cat
rc  inetutils-inetd                         2:2.7-2ubuntu1.1                           amd64        internet super server
ii  inetutils-telnet                        2:2.7-2ubuntu1.1                           amd64        telnet client
ii  tcpdump                                 4.99.6-1                                   amd64        command-line network traffic analyzer
ii  telnet                                  0.17+2.7-2ubuntu1.1                        all          transitional dummy package for inetutils-telnet default switch
rc  update-inetd                            4.54build1                                 all          inetd configuration file updater
kazulog@sv1:~$ ls -l /etc/inetd.conf 2>&1
-rw-r--r-- 1 root root 1062 Sep 12 09:15 /etc/inetd.conf

Test environment and session logs

Two Ubuntu 26.04 LTS Servers on CML. The disks were wiped immediately beforehand, because packages left over from earlier testing would stop the procedure from reproducing.

Test topology
  sv1                             sv2
  ens3 192.168.100.10/24          ens3 192.168.100.20/24
  inetutils-telnetd (23/tcp)      telnet / ssh
   |                               |
   +----------- LAB-SW ------------+
   ^ captured on this link (ports 23 and 22)

The full capture, with both the telnet and the SSH login in one file:

Capture of the telnet and SSH logins (ubuntu-telnet.pcap)
Stepsv1sv2
Initial state (just wiped)show / conf / logshow / conf / log
Installing inetutils-telnetdshow / conf / log
Enabling telnetshow / conf / log
Creating the test usershow / conf / log
Logging in over telnettelnet
Logging in over SSHssh
Analysing the capturetshark
Refusing a sourceshow / conf / log
Checking the refusalshow / conf / logshow / conf / log
Final state of the filesshow / conf / log
Disabling and removingshow / conf / log

Reference

GNU Inetutils manual

Related articles

Ubuntu official pages