telnet登录虚拟机Linux:配置、避坑与自动化实战

发布时间:2026/10/5 7:11:29
telnet登录虚拟机Linux:配置、避坑与自动化实战
简介PDF文档面向Linux初学者和VMware虚拟化实验用户系统讲解从Windows主机远程登录虚拟机Linux的telnet配置方法覆盖服务安装、网络连通、防火墙放行和root登录限制四个关键环节。文档为pdf格式共1个文件大小34KB内容紧凑可对照步骤直接操作。目前已有150人学习参考。文档从检查telnet服务是否安装入手依次介绍rpm查询、telnet-server包安装、/etc/xinetd.d/telnet配置修改以及host-only、bridge、NAT三种虚拟机网络模式下的IP设置与ping测试随后说明防火墙安全级别调整、iptables规则添加与关闭防火墙等排错思路并补充SSH Secure Shell Client远程连接操作。读者按图索骥即可完成telnet环境搭建理解常见登录失败问题的处理方式尤其适合课程实验、毕业设计或自学Linux远程管理。1. 用telnet远程登录虚拟机里的Linux最该避的坑不是命令是两侧配置用telnet远程登录虚拟机下的Linux看起来是个老掉牙的操作一条命令、两个密码、一个回车。可真正上手你会发现坑全在看不见的地方——虚拟机的网卡模式决定了你能不能“找到”那台机器Linux侧有没有人监听23端口决定了你连上后收到的到底是login:还是Connection refused而root登录秒断这种玄学问题往往折腾一晚。telnet比SSH老得多它把用户名和密码按明文从宿主机一路送到虚拟机但这恰恰让它在实验环境里成了最直观的连通性试金石只要屏幕上出现login:网络链路就是通的。这篇笔记适合刚装完VMware或VirtualBox、想在宿主机上直接敲Linux命令的初学者也适合那些已经在用telnet调试网络设备、顺手拿虚拟机练手的人。我会按“环境搭建→连接操作→避坑→选型→自动化”的顺序把这条路走通每个命令都给你能直接复制的版本。2. 先把两侧配置对齐虚拟机网卡模式与 Linux 侧 telnet 服务telnet连接失败十次有八次不是命令敲错而是“两侧配置没对齐”宿主机和虚拟机不在同一网络或者虚拟机里压根没有服务在听23端口。所以动手之前先把两件事钉死虚拟机网络模式选对、telnet服务端装好并确认监听。这两步做完后面所有调试都会变得很干净。2.1 虚拟机网络模式选型NAT、桥接还是仅主机telnet的连通性规则和物理网络完全一致客户端要能通过IP访问服务端。虚拟机的三张网卡模式恰好对应三种拓扑选错就会出现在宿主机上ping得通却连不上23端口的情况。网络模式虚拟机IP特点宿主机能否访问典型用途NAT由虚拟网卡分配的私有IPVMware常见192.168.x.0/24VirtualBox固定10.0.2.15能走VMnet8虚拟网卡单机实验最省事桥接和宿主机在同一局域网IP由路由器分配能像一台独立主机需要局域网内其他设备访问虚拟机仅主机私有网络宿主机可见但虚拟机不能访问外网能隔离性最好练习网络配置不碰外网常见做法是选NAT。VMware安装Ubuntu或CentOS时默认就是NAT宿主机通过虚拟网卡VMnet8和虚拟机保持在同一个网段telnet天然可达。很多人翻车的原因是后来手动把网络改成了桥接但虚拟机里忘了重新配IP或者路由器开了AP隔离宿主机和虚拟机虽然在一个Wi-Fi下却互相看不见。先把虚拟机的IP确认下来登录Linux后在虚拟机里执行# 查看网卡IPens33/ens160这类名字随发行版和虚拟化平台变化 ip addr show # 只看IPv4地址更方便定位 ip -4 addr show输出里inet 192.168.30.128/24这种行就是虚拟机的实际IP。记下这个地址后面telnet连的就是它。注意/24表示同网段宿主机VMnet8的IP如果也是192.168.30.x链路就通。如果不通回到虚拟机网络编辑器里看NAT模式的网段是多少别凭记忆猜。2.2 在 Linux 虚拟机里把 telnet 服务装起来telnet客户端太多机器自带但telnet服务端不是。以CentOS/RHEL 7及以上为例telnet-server在现代版本里走的是systemd socket激活不是老教程里的xinetd。安装并启动# CentOS / Rocky / AlmaLinux 等 RHEL 系 yum install -y telnet-server telnet # 启用并立即启动 telnet.socket23端口由 systemd 监听 systemctl enable --now telnet.socket # 确认 socket 已经处于 listening 状态 systemctl status telnet.socketDebian/Ubuntu系则用inetd方式管理# Debian / Ubuntu 系 apt update apt install -y telnetd # openbsd-inetd 服务负责拉起 telnetd systemctl restart openbsd-inetd systemctl status openbsd-inetd参数说明RHEL系的telnet.socket是systemd的socket单元它先占用23端口有连接进来再拉起telnetd进程这样不连接时不消耗常驻进程资源Debian系则靠inetd超级服务统一管理多个小服务。装完后在虚拟机里自己连自己一次确认服务端本身没毛病# 在本机测试能出现 login: 就说明服务端可用 telnet 127.0.0.1 23如果遇到linux离线安装telnet这种场景——内网环境没法用yum或apt——提前在有网的机器上下载好telnet-server和telnet的rpm或deb包拷进虚拟机后用rpm -ivh telnet-server*.rpm或dpkg -i telnetd*.deb逐个安装缺依赖就按提示补齐。国产Linux系统比如银河麒麟多数基于RHEL或Debian改造命令基本通用但systemd的unit文件名偶尔有差异装完先执行systemctl list-units | grep telnet看看实际服务名叫什么。2.3 验证 23 端口真的在听ss 与防火墙的三种状态服务装好不等于端口开放防火墙和SELinux都可能把23端口摁住。用ss看监听状态# 查看 23 端口是否 LISTEN-l 只看监听-t 只看 TCP-n 不做域名解析 ss -lntp | grep 23有输出形如LISTEN 0 128 0.0.0.0:23就说明socket已起来。如果什么都没打印先回2.2查服务状态。端口在听之后处理防火墙。RHEL系用firewalld的常见做法是# 临时放行 23 端口 firewall-cmd --add-port23/tcp # 永久放行重启不丢 firewall-cmd --permanent --add-port23/tcp # 重载配置并确认 firewall-cmd --reload firewall-cmd --list-ports防火墙有三种容易混淆的状态端口没放行时telnet连接会卡住直到超时或者直接被拒放行后立刻可连如果是默认zone里压根没启用firewalld服务那防火墙根本没生效问题就得往别处找。Debian/Ubuntu上常见的是ufw对应命令是ufw allow 23/tcp。我一般会再叠加一条SELinux检查在RHEL系上执行getenforce输出Enforcing的话先别急着改继续往下排查等出现具体故障再处理——SELinux的事放到第4章避坑清单里讲别在一开始就把自己绕进安全策略的黑匣子。3. 连上虚拟机telnet 最小命令、登录信息流与退出姿势两侧配置对齐后真正的telnet命令反而没什么花样。这一章把连接、验证、退出三个动作讲透顺便把telnet命令怎么用这条链路里最容易误解的部分——交互回显和转义字符——解释清楚。3.1 最小连接命令telnet 192.168.x.x 与登录信息流在宿主机命令行里执行# 用虚拟机的实际IP替换下面的地址 telnet 192.168.30.128连接成功后屏幕会先出现Trying 192.168.30.128...和Connected to 192.168.30.128.然后看到login:提示符。整个信息流是客户端TCP连接到23端口→服务端发送登录横幅→客户端输入用户名→服务端提示Password:→输入密码→进入shell。telnet协议本身有回显协商输入用户名时字符会回显输入密码时回显会自动关闭所以密码敲进去屏幕上什么都没有是正常现象不是卡死。连接命令还有几个参数实验环境里常用到参数作用示例目标IP要连接的虚拟机地址telnet 192.168.30.128端口默认23可指定其他端口telnet 192.168.30.128 2323-l 用户名连接时直接指定登录名telnet -l testuser 192.168.30.128-e 字符自定义转义字符默认是Ctrl]telnet -e ^Q 192.168.30.128指定-l可以省掉登录时输用户名的步骤但后面仍要输密码。改端口通常用于测试环境里23被占用或不想用特权端口的情况Linux侧需要同步修改telnet.socket监听的端口。至于-e当默认的Ctrl]被终端软件抢占时换一个转义字符能救命普通场景不用动。3.2 登录成功后先做三个确认身份、网络、命令通道看到shell提示符不等于环境正常。我习惯登录后先跑三条命令——这三条也是linux常用命令里最该形成肌肉记忆的# 1. 确认当前身份知道自己是普通用户还是 root whoami id # 2. 确认网卡和路由核对是不是当初要连的那台机器 ip addr show ip route show # 3. 确认命令通道没有异常顺手看下系统信息 hostnamectl逻辑说明whoami和id防止登错账户——telnet默认很可能给了你普通用户后续执行特权命令会到处碰壁ip addr show和ip route show用来核对IP因为虚拟机用DHCP时重启后IP可能变化宿主机连的是旧地址就会张冠李戴hostnamectl确认主机名多台虚拟机场景下靠这个区分到底进了哪一台。做完这三个确认才算是真正“接管”了这台虚拟机。3.3 退出与转义Ctrl] 不只是结束会话telnet会话里Ctrl]会从远程shell退到telnet自己的命令行提示符变成telnet。这是telnet和SSH体验差异最大的地方。在telnet下可以执行quit # 真正关闭连接并退出 telnet close # 关闭当前连接回到 telnet 继续输入 z # 把 telnet 挂起到后台回到宿主机 shell用 fg 恢复 ? # 查看 telnet 命令行支持的命令常见操作是先Ctrl]再quit完整退出Ctrl] telnet quit逻辑说明直接关掉终端窗口当然也能结束会话但服务端可能会把连接断开当成异常留下残留进程用quit走正常关闭流程服务端那边日志干净虚拟机里的用户进程也不会被意外挂起。如果只是想临时回宿主机查个东西用z挂起比整体断开省事回到宿主机shell查完执行fg就能回到telnet会话远程shell里的状态一点不丢。这个习惯在长任务调试时特别有用不用反复登录。4. telnet 登录避坑5 个高频故障的排查路径这一章把我见过的高频故障按“现象→原因→解决”拆开。telnet的坑基本集中在端口、登录控制、回显和客户端四类照着路径走能省下大量试错时间。4.1 Connection refused服务没起或防火墙把 23 端口 drop 了现象宿主机执行telnet 192.168.30.128屏幕很快出现Connection refused而不是Trying之后卡住。这说明对方的IP存在且网络可达但23端口主动拒绝了连接。原因最常见的是telnet.socket没启动其次firewalld默认drop了入站23端口。RHEL系装了telnet-server但没执行systemctl enable --now telnet.socket时端口根本没监听内核直接回RST表现为秒拒。解决在虚拟机里按顺序查三层# 第一层端口有没有听 ss -lntp | grep 23 # 第二层systemd 单元状态 systemctl status telnet.socket # 第三层防火墙规则 firewall-cmd --list-ports firewall-cmd --list-all哪一层异常就修哪一层端口没听就启动socket防火墙没有23/tcp就按2.3的命令放行。注意firewall-cmd --list-ports只能看到显式放行的端口如果输出为空但连接还是被拒确认firewalld服务本身在运行systemctl status firewalld。4.2 root 登录秒断securetty 不认 pts 伪终端现象在login:处输入root密码输完回车屏幕直接跳Connection closed by foreign host.或者提示Login incorrect但同一个密码用普通用户登录就一切正常。原因RHEL/CentOS的PAM栈里有pam_securetty模块它规定root只能在/etc/securetty文件里列出的终端上登录。telnet分配的伪终端是pts/0这类而RHEL默认的securetty只列了本机tty和console没有pts所以root从telnet进不来。这是安全设计不是故障。解决最省事的做法是绕开root——先用普通用户登录再执行su -切换root# 普通用户登录后切 root su -如果实验场景必须root直登把pts设备追加到securetty文件# 追加伪终端设备允许 root 通过 pts/0 登录 echo pts/0 /etc/securetty echo pts/1 /etc/securetty # 重启 telnet.socket 让 pam 配置重新加载 systemctl restart telnet.socket注意Debian/Ubuntu默认没有/etc/securetty没有这个文件时pam_securetty一般直接放行所以Ubuntu上少见root秒断。改成的话提醒自己root直登telnet意味着root密码按明文在网络上跑实验虚拟机无所谓连到任何重要机器上都是事故这一点第5章还会强调。4.3 连上后不显示任何数据多半是卡在密码输入不是卡死现象login:出现输入用户名回车屏幕黑着什么都不显示敲键盘也没反应很多人第一反应是“telnet测试不显示数据是不是卡死了”直接关窗口。原因两个。一是密码输入阶段回显本来就被服务器关闭屏幕上不显示任何字符光标也不动但输入是有效的二是telnet在启动时做过echo协商有些终端实现和服务器协商的结果是“本端不回显”后面命令的输出也看不到产生假死感。解决先别关窗口。在空白处直接输入密码回车如果登录成功进入shell说明刚才是密码等待状态。如果仍然没反应再尝试盲输一个命令回车然后观察屏幕——只要命令输出冒出来就说明只是回显被关了会话本身是活的。应急做法是退出重连并把终端的本地回显改成“always”模式。真要确认会话状态可以在宿主机另开一个终端执行tcpdump -i any port 23看流量看有没有互动数据在走。4.4 普通用户也被 Connection closed by foreign host查 SELinux 与 /etc/nologin现象普通用户登录时用户名密码都对但验证通过的一瞬间连接被关闭日志里又没有明显的认证失败记录看起来像是telnetd进程崩了。原因在RHEL系上最隐蔽的是SELinux的Enforcing模式拦了telnetd的某些动作表现为连上就断另一个可能是系统里存在/etc/nologin文件——系统维护期间管理员创建了这个文件PAM的pam_nologin模块会拒绝所有非root用户登录。解决先确认SELinux状态并临时放低限制做对照实验# 看当前 SELinux 模式 getenforce # 临时切换成 Permissive重启后恢复 Enforcing setenforce 0 # 再试一次登录若正常则问题在 SELinux 策略如果切到Permissive后连接恢复那就不用怀疑应用层了。别急着永久关闭SELinux一个更干净的出路是查audit日志grep telnet /var/log/audit/audit.log找到具体被拦的操作再对症处理。同时检查ls -l /etc/nologin文件存在的话删掉或等维护结束它自动消失。用tail -f /var/log/secure另开一个窗口边登录边看是最快的定位手段。4.5 宿主机提示“不是内部或外部命令”Windows 的 Telnet 客户端默认没开现象Windows 10/11宿主机上执行telnet 192.168.30.128cmd直接提示telnet 不是内部或外部命令但这台Windows本身没毛病。原因微软从Windows Vista开始默认不安装Telnet客户端这个功能作为“Windows功能”存在但默认关闭。很多教程默认读者有telnet客户端直接跳过了这一层。解决管理员权限的cmd或PowerShell里执行# 启用 Windows 自带的 Telnet 客户端 dism /online /enable-feature /featurename:TelnetClient执行完重开cmdtelnet就能用了。不想装系统组件的话用PuTTY的telnet模式也一样Host填虚拟机IPConnection type选Telnet点Open效果和命令行完全一致。Linux和macOS宿主机一般自带telnet客户端没有就用yum install telnet或apt install telnet补上。5. telnet 在虚拟机场景的真实边界什么时候必须换 SSHtelnet能连上、能敲命令但我不建议你把所有远程登录都押在telnet上。这一章不劝退而是把价值边界划清楚实验环境里它足够好用生产环境里它有几个硬伤你必须知道什么时候该换SSH。5.1 telnet 的价值边界实验环境、网络设备、最小依赖telnet在虚拟机场景的价值不是性能是简单。它不需要生成密钥对不需要审核证书指纹不用装额外的服务端组件——RHEL系一个telnet-serverDebian系一个telnetd装完就能用。对刚接触Linux的人telnet把“远程登录”这件事拆到最薄一个TCP连接、一个登录提示、一个shell中间没有任何加密协商的黑匣子网络通不通一眼就能判断。它还有一个不可替代的场景网络设备调试。大量交换机、路由器、光猫的管理口至今保留telnet服务很多网络工程师的日常就是telnet 192.168.1.1然后输admin和密码。在虚拟机里搭一个telnet服务端本质上就是复现这套网络设备的登录链路练手价值很高。另外在最小化安装的发行版上telnet客户端体积小、依赖少离线环境里用rpm包装起来比SSH工具链省事得多。5.2 明文传输的代价抓包能看到完整密码telnet的硬伤是它对整个会话的内容不做任何加密用户名和密码在网络上等于裸奔。在虚拟机环境里演示一下你会记得非常牢。在虚拟机里开终端跑抓包然后在宿主机上重新telnet登录一次# 在虚拟机里抓取所有 23 端口流量并逐字节以 ASCII 打印 tcpdump -i any -A port 23宿主机登录时敲入的login:和Password:在tcpdump的输出里会直接以明文显示包括完整的用户名和密码序列。这个演示不是理论恐吓是telnet协议设计如此——它的RFC诞生于加密还没普及的年代。所以血泪经验只有一条telnet只适合隔离的实验网络、虚拟机互连、网络设备管理口这类可信环境任何跨越公网、办公网、生产环境的登录都要用SSH或加密隧道。这不是技术洁癖是密码落到明文抓包里只要一次就足够让你后悔。5.3 迁移到 SSH 的成本openssh-server 一条命令如果评估下来场景敏感换成SSH的成本低得惊人。绝大多数Linux发行版都预装了OpenSSH服务端或可以用一条命令装好# RHEL 系 yum install -y openssh-server systemctl enable --now sshd # Debian 系 apt install -y openssh-server systemctl enable --now sshd客户端连接变成ssh 用户名192.168.30.128默认端口22。telnet和SSH的对比一目了然对比项telnetSSH端口2322传输加密无明文全链路加密认证方式用户名密码密码或密钥登录控制securetty/PAMsshd_config PAM适用环境实验/可信内网任何环境尤其公网配置成本低低一条命令迁移时的注意点SSH默认也禁止root密码登录但可以通过/etc/ssh/sshd_config显式控制PermitRootLogin比securetty直观密钥登录用ssh-copy-id 用户名IP一次搞定之后连密码都不用输。迁移完成后把telnet的socket停掉一是少一个明文入口二是少一个监听端口攻击面更小# 确认不需要 telnet 后将其停用 systemctl disable --now telnet.socket6. 让 telnet 自动化expect 脚本和 Python 封装手里有多台虚拟机要批量登录检查时手工输密码会让人崩溃。telnet协议简单自动化反而容易——expect和Python都能把“等待提示符→发送用户名→发送密码→执行命令”这套交互固化下来。6.1 用 expect 自动登录并执行命令expect是专门干这活的工具它模拟人的交互过程。RHEL系装一下yum install -y expect。脚本如下#!/usr/bin/expect # 脚本参数第一个是虚拟机IP第二个是用户名第三个是密码 set ip [lindex $argv 0] set user [lindex $argv 1] set pass [lindex $argv 2] # spawn 启动 telnet 客户端 spawn telnet $ip # 等待 login: 提示出现超时 10 秒 expect login: { send $user\r } expect Password: { send $pass\r } # 登录成功后等待 shell 提示符$ 要转义 expect \$ { send hostname whoami\r } expect \$ { send exit\r } # 会话结束 expect eof逻辑说明expect的匹配是按字符串出现的顺序推进的每一步都要先等到上一动作的结果再发下一步否则容易把后续命令误发给服务端。\$是转义后的shell提示符telnet会话里普通用户提示符是$root是#脚本里要按实际用户调整。执行方式./telnet_auto.exp 192.168.30.128 testuser 123456。6.2 用 Python 脚本把 telnet 交互封装成工具Python的telnetlib标准库能做同样的事情它更适合后续接上采集、告警逻辑import telnetlib import time host 192.168.30.128 user testuser password 123456 # 建立连接读取直到出现 login: 提示 tn telnetlib.Telnet(host) tn.read_until(blogin:, timeout10) tn.write(user.encode(ascii) b\n) # 读取直到出现 Password: 提示发送密码 tn.read_until(bPassword:, timeout10) tn.write(password.encode(ascii) b\n) # 等进入 shell然后执行命令并读取结果 time.sleep(1) tn.write(bip addr show | head -5\n) time.sleep(2) output tn.read_very_eager() print(output.decode(utf-8, errorsignore)) # 正常退出 tn.write(bexit\n) tn.close()逻辑说明read_until按标识符阻塞等待服务器提示字符串必须精确write方法接收的是字节串所以用户名密码要encode。实验环境里用time.sleep等待命令输出是常见做法如果是正式工具应该用第二次read_until匹配命令输出结束的标志字符串。注意一点telnetlib在Python 3.13已从标准库移除如果你的Python版本新直接把6.1的expect脚本拿来用或改用第三方库telnetlib3。6.3 自动化脚本的验证方法脚本写完先不急着大批量跑用一条最稳的命令验证链路tn.write(bwhoami\n)然后读取输出确认结果里包含预期的用户名。批量场景下让脚本把每台机器的输出写到独立文件再用grep -L找没执行成功的机器比人盯屏幕高效得多。还有千万别把密码硬编码进仓库——脚本里用环境变量或运行时提示输入否则一次泄露所有机器都得改密码。我第一次写这类脚本时忘了securetty里的pts列表root一登录就被PAM踢出expect一直等不到shell提示符脚本整个卡死。后来老老实实改用普通用户加su脚本才真正稳定下来。希望帮到你。本文还有配套的精品资源点击获取