
先问一句你现在的状态到底是“ping 不通 CentOS 7 主机”还是“ping 得通但 SSH 连不上 22 端口”这两个问题的排查路径完全不一样但很多人在提问时报错信息只写了“centos7的22端口无法访问”这就把故障范围拉得很大。我刚处理过一台 CentOS 7.9 的虚拟机客户机同网段能 ping 通但ssh root一直卡在连接超时最后定位到是 firewalld 默认 zone 被改成了 drop。这种场景太典型了值得把整套排查思路完整过一遍。这篇文章按真实排障顺序展开网络层判断、端口监听、防火墙、sshd 服务、SELinux、资源问题、客户端干扰以及虚拟机特殊场景。不管你是刚装完 CentOS 7 连不上还是服务器跑着跑着突然 22 端口进不去都可以按这个路线逐层定位。1. 22端口连不上的故障全景与排查路线1.1 先分清三种截然不同的故障现象“无法访问”这个词概括了至少三种完全不同的现象我建议你先把现象确认清楚后面才不会白忙活。第一种是连接被拒绝客户端秒弹Connection refused。说明网络路径是通的但目标机器的 22 端口没有进程在监听或者防火墙直接回了 RST。第二种是连接超时客户端卡在那里直到Connection timed out。说明 SYN 包发出去之后石沉大海通常是被防火墙 DROP 了也可能是路由不可达。第三种是认证失败Permission denied或者密码错这已经说明 22 端口通了只是卡在身份验证。这三种现象对应的排查方向完全不同。遇到过很多新手明明看到的是Connection refused还在拼命查防火墙和网络结果实际是 sshd 服务压根没起来。所以第一步永远是确认现象而不是凭经验乱猜。1.2 一条主线解决90%的问题对于 CentOS 7 上 22 端口无法访问核心排查主线就四个字通、听、挡、验。通指网络层是否可达包括 IP、网关、路由和 ARP。听指 sshd 有没有监听在 0.0.0.0:22 或者正确的网卡地址上。挡指 firewalld、iptables、SELinux 这些安全机制有没有把 22 端口拦下来。验指用客户端工具交叉验证确认是服务器问题还是客户端这边自己的环境问题。我在实际排障中习惯按这张表逐步推进。排查层级核心问题典型命令快速判断网络层IP和路由通不通ping、ip routeping 不通优先查网络配置传输层22端口有没有监听ss -tlnp、telnet无监听则查 sshd安全层防火墙/SELinux 拦没拦firewall-cmd、getenforce规则缺失则放行应用层sshd 配置和日志sshd -t、/var/log/secure配置错误则修正客户端软件、代理、known_hostsssh -vvv、换机器测试客户端问题则替换工具这篇文章后面所有内容都是围绕这条主线展开的。2. 先分清三层问题网络通不通端口听没听防火墙挡没挡2.1 第一板斧ping 和基础连通性先看最基本的。在客户端机器上执行ping 192.168.31.10如果 ping 不通有三种可能。第一种目标机器根本不在这个网段或者 IP 配置错了。第二种中间有防火墙禁 ping但注意很多云主机和服务器禁 ICMP 不等于禁 TCP所以 ping 不通不一定说明 SSH 也不通。第三种提示“无法访问目标主机”这类报错时通常是本机 ARP 缓存里找不到目标 MAC 地址说明目标主机不在当前链路内或者网关有问题。接下来看服务端自己ip addr ip routeip addr确认网卡有没有拿到 IP状态是 UP 还是 DOWN。ip route确认默认路由是否存在。如果发现default via这一行消失了跨网段访问基本没戏因为回包找不到路。我见过一台 CentOS 7 重启之后默认路由丢了外部 ping 不通SSH 自然也进不去重启 network 服务才恢复。ping 通是基础但很多人忽略了一个关键ping 通只代表 ICMP 可达不能代表 22 端口 TCP 可达。所以下一步必须直接测端口。2.2 第二板斧telnet/nc/nmap 探测22端口端口探测最直观的方式是 telnettelnet 192.168.31.10 22如果出现Connected to 192.168.31.10并显示SSH-2.0-OpenSSH_7.4之类的 banner说明 22 端口已经通了问题可能出在认证环节或客户端自身。如果出现Connection refused说明端口没监听或被 REJECT。如果一直卡住直到超时说明数据包被丢弃。在不方便装 telnet 的机器上可以用 ncnc -vz -w 3 192.168.31.10 22-v显示详细信息-z只扫描不发送数据-w 3设置 3 秒超时。有 nmap 的话更简单nmap -p 22 192.168.31.10nmap 会明确显示open、closed、filtered三种状态。其中filtered基本就是防火墙把包丢了这个信息和Connection timed out相互印证。我实测过一个很典型的案例同网段 ping 通telnet超时服务端ss -tlnp显示 sshd 正常监听 0.0.0.0:22最后发现是 firewalld 默认 zone 被设置成了drop。所有入站连接都被静默丢弃表现就是“看起来一切都正常但就是连不上”。2.3 第三板斧在服务端抓包确认是被丢还是没回包如果客户端探测超时下一步我建议直接在 CentOS 7 服务器上抓包这一步能区分“防火墙丢弃”和“回程路由不通”。tcpdump -i ens33 tcp port 22 -nn观察几秒钟。如果只看到SYN发进来但服务器没有回SYN-ACK那基本可以确定是防火墙拦了因为协议栈本身没有回包。如果看到服务器回了SYN-ACK但客户端依然超时那就是回程路由或客户端侧的问题。抓包这个操作看起来多余但在复杂网络里真的能救命。有一次我排查一台双网卡服务器发现抓包能看到请求进来但服务器从错误网卡回包客户端自然收不到。这个问题如果不抓包光靠看防火墙规则永远定位不到。3. 网卡与IP配置那些一眼看不出来的老坑3.1 ifcfg-xxx 和 ONBOOTno 这个经典问题CentOS 7 的网络配置文件和 CentOS 6 相比变化不大但坑一点都不少。最常见的是/etc/sysconfig/network-scripts/ifcfg-ens33里ONBOOTno导致开机后网卡没有自动启动IP 没配上去外部自然无法访问。修改方式很简单vi /etc/sysconfig/network-scripts/ifcfg-ens33确保以下几项正确TYPEEthernet BOOTPROTOstatic ONBOOTyes IPADDR192.168.31.10 NETMASK255.255.255.0 GATEWAY192.168.31.1 DNS1223.5.5.5改完执行systemctl restart network或者用 NetworkManager 的方式nmcli con reload nmcli con up ens33这里有个配置差异CentOS 7 同时存在 network 和 NetworkManager 两套管理工具。如果你改了配置文件但发现不生效检查一下 NetworkManager 是不是接管了这块网卡。我见过用户在/etc/sysconfig/network-scripts/下改了 IP结果 NM 自动覆盖了配置最后两条命令很快解决systemctl disable NetworkManager systemctl enable network systemctl restart network另外提醒一句很多从 CentOS 6 时代过来的老文档还在教改eth0但 CentOS 7 默认用ens33或ens192这类网卡命名。如果写的网卡名不对文档改得再对也等于白改。可以用ip addr先确认实际网卡名。3.2 路由表与多网卡的干扰单网卡配置不当导致问题相对好查。真正头疼的是多网卡服务器。有一次我在一台双网卡 CentOS 7 上部署服务外网网卡和内网网卡都配置了默认网关。重启后系统把默认路由指向了内网网卡结果从外网 SSH 22 端口进来的包回包却从内网网卡发出去了。客户端那边看到的全是连接超时。排查命令ip route正常情况下输出里应该只有一条default via。如果出现了多条默认路由或者默认网关指向了错误的网卡处理方式通常是把不需要的 GATEWAY 注释掉或者用策略路由ip rule控制源地址路由。对于只有一张网卡的读者这里也不可掉以轻心。CentOS 7 里 NetworkManager 有时候会动态修改路由表尤其是虚拟机环境里 DHCP 和静态配置混用的时候。配置完 IP 之后再执行一次ip route确认默认路由存在且指向正确这是成本最低的保险。4. firewalld 是 22 端口访问失败的头号嫌疑人4.1 先确认防火墙到底开没开CentOS 7 默认使用 firewalld但在很多装机教程和自定义镜像里可能同时存在 iptables 服务。所以排查时要先确认到底是谁在拦。systemctl status firewalld firewall-cmd --state如果输出running那防火墙就是主要嫌疑人。接着查看当前 zone 和已有规则firewall-cmd --get-default-zone firewall-cmd --list-all--get-default-zone输出通常是public但如果被改成了drop那所有入站流量都会被直接丢弃SSH 无论如何都连不上。--list-all里能看到当前 zone 放行了哪些服务和端口如果services: ssh不在列表里22 端口默认就被挡在外面。这里有个关键概念firewalld 的 zone 机制类似“不同信任级别的区域”。public区域默认只放行少量服务drop区域默认丢弃所有入站请求trusted区域默认接受所有流量。CentOS 7 安装完成后默认是public本来应当放行 ssh但很多人在配置过程中误改了默认 zone或者执行过一些第三方脚本导致 zone 变成了 drop。检查这一步一定要做。4.2 正确放行22端口的命令如果防火墙开着但规则里没有 ssh执行以下命令放行firewall-cmd --permanent --add-port22/tcp firewall-cmd --reload这里加不加--permanent是新手最容易踩的坑。--permanent表示写入永久配置重启后依然生效不带这个参数的话规则只对当前运行环境生效重启 firewalld 或重启机器后就没了。如果你想指定来源 IP而不是对所有 IP 开放可以用 rich rulefirewall-cmd --permanent --add-rich-rulerule familyipv4 source address192.168.31.0/24 port protocoltcp port22 accept firewall-cmd --reload执行完以后一定要复查firewall-cmd --list-all确认ports: 22/tcp或对应的 rich rule 已经出现。如果复查发现规则不在多半是刚才的命令没加--permanent重启后丢了。4.3 “重启失效”和 DOCKER 链的坑说一个很典型的现场故事。有人执行了firewall-cmd --add-port22/tcp当时测试 SSH 可以连接很高兴。结果第二天重启机器后又连不上了还非常困惑“我明明放行了”。原因就是上面说的--add-port没有加--permanent规则只存在于运行时配置里。重启后 firewalld 加载永久配置临时规则自然消失。正确的操作流程是先加--permanent再--reload最后用--list-all复核。另一个更隐蔽的坑和 Docker 有关。CentOS 7 上装了 Docker 之后Docker 会在 iptables 的 FORWARD 链中插入 DOCKER 规则。如果firewalld和 Docker 的启动顺序不对或者做了防火墙操作后没有重新初始化 Docker 链可能会导致整个网络转发异常表现之一就是 22 端口访问失败。排查方法iptables -L -n | grep 22 iptables -L FORWARD -n看到 DOCKER 链的规则覆盖了 FORWARD 行为但又不确定是不是它导致的可以临时验证systemctl stop firewalld然后立刻用客户端测试 22 端口。如果能连接了说明一定是 firewalld 的规则问题。确认后再把防火墙启动回来用最小化放行规则代替“一关了之”。5. sshd 服务本身与 SELinux 的隐形坑5.1 检查 sshd 是否在听、监听在哪当网络层和防火墙都排除后就要看 sshd 自己了。先检查服务状态systemctl status sshd如果显示active (running)再看监听地址ss -tlnp | grep :22正常情况应该看到类似下面的输出LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:((sshd,pid1234,fd3))注意0.0.0.0:22表示监听在所有 IPv4 地址上。如果看到的是127.0.0.1:22那问题就大了sshd 只监听在回环地址上外部流量根本无法到达。这种情况通常是因为/etc/ssh/sshd_config里配置了ListenAddress 127.0.0.1或者系统里其他配置文件覆盖了默认监听行为。解决方法把配置改为ListenAddress 0.0.0.0然后重启 sshd。这是“端口通但连不上”的经典原因之一排查时通过ss -tlnp一眼就能看出来。5.2 sshd_config 改错导致远程回不来另一种情况是服务端 sshd 没有在运行或者启动失败。看状态和日志systemctl status sshd journalctl -u sshd -n 50 tail -n 50 /var/log/secure如果有Failed to start OpenSSH server daemon之类的报错大概率是配置文件写错了。最稳的操作是执行配置语法检查sshd -t如果语法有误这里会直接报错。这个命令在远程维护场景下简直是救命绳。我自己的习惯是每次改完/etc/ssh/sshd_config先sshd -t通过再systemctl restart sshd。千万别直接 restart一旦语法错误服务起不来远程会话直接断开如果手头没有其他访问通道就只能去机房或者靠 IPMI 了。另外配置里几个常见项值得留意PermitRootLogin如果设为noroot 用户无法登录。PasswordAuthentication如果设为no密码登录会被拒绝。AllowUsers/DenyUsers指定用户白名单或黑名单如果配错了会把你自己挡在门外。UseDNS如果设为yes客户端连接时服务端会做反向 DNS 解析表现为连接建立很慢但最终能连上。对多数场景建议设置为no。排障时结合/var/log/secure最有效。看到Failed password是认证失败看到Connection closed by authenticating user说明认证流程被中断看到error: maximum authentication attempts exceeded说明客户端尝试认证次数太多被服务端断开。5.3 SELinux 拦截了 SSH 流量很多人在排查 22 端口时会把 SELinux 直接忽略但它确实会拦截 SSH而且表现形式很迷惑防火墙开了sshd 也在监听可外部就是连不上。先看状态getenforce输出Enforcing说明 SELinux 正在强制模式。为了快速定位可以临时关掉验证setenforce 0这时候如果客户端能连上了那基本可以确定是 SELinux 拦截。但注意setenforce 0只对当前运行环境生效重启后恢复 Enforcing不能作为长期解决方案。长期方案是用 semanage 命令放行对应端口。比如你把 sshd 改到了 9022 端口SELinux 默认只允许 22就需要执行semanage port -a -t ssh_port_t -p tcp 9022查看当前 SELinux 允许的 SSH 端口semanage port -l | grep ssh如果看到ssh_port_t tcp 22只有 22而你实际监听的是其他端口那 SELinux 一定会拦。新增放行后重启 sshd 即可。有人会问为什么只改了端口就要动 SELinux因为 SELinux 的端口类型标签和进程策略是绑定的sshd 进程被标记为ssh_t它只允许绑定到带有ssh_port_t标签的端口。你改了配置但没通知 SELinux它当然继续按旧策略拦截。这个逻辑理解透了以后遇到类似问题就不会一头雾水。6. 资源耗尽、客户端干扰与虚拟机场景6.1 磁盘满、日志刷爆、连接数耗尽有些 22 端口“无法访问”其实和设备资源有关这类问题表现得比较隐蔽因为看起来配置文件都对。第一个常见场景是根分区磁盘写满。用df -h看/的使用率如果 100%sshd 在写入 utmp、读取 authorized_keys、创建 session 文件时都会失败。表现可能是客户端输入密码后卡死或者连接直接被拒。处理方式就是清理磁盘通常先找/var/log下的大文件再用journalctl --vacuum-size200M收缩日志。第二个场景是/var/log/secure被刷爆。如果服务器暴露在公网被扫描器暴力破解日志文件可能涨到几个 GB。日志写不进去时sshd 的认证流程可能异常缓慢甚至无响应。处理方式是删掉旧日志并重启 rsyslog同时建议启用 fail2ban 或修改 SSH 端口降低被扫概率。第三个场景是文件描述符耗尽或进程数达到上限。查看ulimit -n cat /proc/sys/fs/file-nr如果已分配文件描述符接近系统上限sshd 无法 accept 新连接。表现是连接立即被拒或极慢。这种问题通常需要通过调大fs.file-max和进程的ulimit来解决但更重要的是先找到为什么会有这么多文件描述符被占。曾经遇到过 coredump 文件堆积把inode耗尽的案例df -i一看发现 inode 满删除大量临时文件后才恢复。6.2 客户端侧也有“假故障”有一种情况很气人服务器完全正常问题出在客户端自己身上。最常见的是 known_hosts 冲突。换过服务器系统或者恢复过快照后客户端的~/.ssh/known_hosts里还存着旧的指纹连接时会报WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!这时候很多人会不知所措实际上删除对应的 known_hosts 条目即可ssh-keygen -R 192.168.31.10另外一个隐蔽因素是客户端开了全局代理。我用 Windows 上某些 SSH 工具连接内网 Linux 服务器时只要系统代理开着连接就失败关了代理立刻恢复正常。这个原因在文档里很少被提及但真实场景遇到概率不小。多角度验证也很有用。如果服务器连不上拿另一台电脑、手机上的 Termius、或者换个网络环境试一试。如果其他设备能连只有你这台机器不能连那问题的范围基本锁定在客户端不必再折腾服务器。6.3 VMware 虚拟机网络模式的影响很多新手是在 VMware 里装的 CentOS 7然后发现 22 端口连不上。这时候要先看虚拟机的网络模式因为不同的模式决定了谁能访问这台虚拟机。VMware 三种网络模式的区别整理如下。模式虚拟机 IP 特征宿主机能否访问局域网其他机器能否访问NAT192.168.x.x由 VMnet8 分配能默认不能需端口转发桥接与宿主机同网段能能前提是 IP 配置正确仅主机192.168.x.x由 VMnet1 分配能不能最常见的坑是选 NAT 模式然后局域网里另一台电脑想 SSH 连这台虚拟机怎么都连不上。这不是 CentOS 7 的问题而是 NAT 模式本身就不允许外部主动访问。解决方式有两种要么改用桥接模式要么在 VMware 的 NAT 设置里添加端口转发把宿主机的某个端口转发到虚拟机的 22 端口。此外虚拟机内部网卡可能没有“已连接”。编辑虚拟机设置确认网络适配器那里已勾选“已连接”和“启动时连接”。我遇到过一台虚拟机关机后再次开机网卡连接状态丢失导致ip addr里根本没有 IP 地址这类问题不到虚拟机设置里看一眼很难发现。7. 排障速查表与几条实战体会7.1 常用排障命令速查表把多年积累的排查命令整理成一张表遇到问题可以按顺序来。现象可能原因先执行什么ping 报“无法访问目标主机”ARP 不通、目标不在链路内ip neigh、检查网段ping 超时ICMP 被禁或路由问题用nc -vz IP 22验证 TCPtelnet 显示 Connection refusedsshd 没监听或防火墙 REJECTsystemctl status sshdtelnet 超时防火墙 DROP 或回程路由错误firewall-cmd --list-all、tcpdump防火墙规则里有 22 端口仍连不上SELinux 拦截或 sshd 监听错误地址getenforce、ss -tlnp密码正确但认证失败磁盘满、authorized_keys 权限错、UseDNSdf -h、tail /var/log/secure换网络环境能连原网络不行客户端代理、IP 冲突、宿主机防火墙关闭代理、换 IP 测试这张表不能覆盖所有情况但能覆盖八成以上“22端口无法访问”的问题。剩下的就需要结合日志和抓包深入分析了。7.2 三条实战体会第一个体会是先用nc或telnet测端口别急着改服务器。命令结果直接告诉你问题是“拒绝”还是“超时”方向完全不一样。拒绝查服务和防火墙 REJECT超时查防火墙 DROP 和路由。第二个体会也是踩过坑才明白的不要为了方便直接永久关闭防火墙。见过太多人systemctl disable firewalld然后服务器被扫描爆破SSH 被塞满垃圾日志。正确做法是只放行必要端口能用 rich rule 限制来源 IP 就尽量限制。22 端口是登录入口安全等级本来就该比普通服务高。第三个体会和配置安全相关改 sshd 配置前先备份改完先sshd -t自检再重启服务。我唯一一次被锁在云主机外面就是深夜手滑把 Port 写错重启后 sshd 直接起不来。从那以后所有涉及 SSH 的改动都必须先跑语法检查。这个习惯救了我很多次也希望这次分享能帮到你。CentOS 7 已经服役多年这类端口访问问题本质都不难难的是被各种环境变量干扰。希望这篇排障记录能让你下次面对 22 端口问题时少走几步弯路。