SSD Nodes Learn 🎉 VPS $5.50/月起
指南 Matt Connor作者: Matt Connor · 更新于 2026-08-21

Linux 如何检查端口是否开放:ss、nc 与 nmap

用 ss 确认本机实际监听的端口,再用 nc 或 nmap 从外部测试。了解被阻断端口为何一直等待,而关闭端口会立即拒绝连接。

在 Linux 上检查端口是否开放:先确定正确的问题

要在 Linux 上检查端口是否开放,首先要确定你要回答的问题,因为站在不同位置时,“开放”的含义不同。在服务器本机上,开放表示某个进程已绑定该端口并正在等待连接。从另一台计算机检查时,开放表示数据包能够到达该进程,并收到返回的响应。如果没有响应,真正的问题是哪个设备丢弃了数据包。sudo ss -ltnp 可回答第一个问题。nc -znmap 可回答第二个问题。防火墙计数器和 tcpdump 可回答第三个问题。

执行错误的检查,往往会浪费整个下午。在服务器上运行的测试不会经过服务提供商的网络防火墙,因为该过滤器位于服务器外部。如果你还不熟悉端口号,Linux 上的端口和套接字工作原理介绍了本指南其余内容所采用的模型。

此主机上有哪些监听端口?读取 ss 输出

ss 随 iproute2 一起发布,因此当前所有发行版都已提供该命令。netstat 来自 net-tools,而 Ubuntu 多年来默认不再安装该软件包,因此 netstat -tulpn 通常会返回 netstat: command not found。请熟悉 ss,避免遇到这种问题。

sudo ss -ltnp

-l 仅显示监听套接字。-t 将列表限制为 TCP。-n 直接显示数字,而不是解析名称,因此命令会立即返回。-p 显示所属进程,但需要 root 权限:如果没有 sudo,对于不属于您的进程,Process 列都会为空。将 -t 替换为 -u 可查看 UDP。

State  Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
LISTEN 0      4096   127.0.0.53%lo:53    0.0.0.0:*   users:(("systemd-resolve",pid=612,fd=14))
LISTEN 0      128    0.0.0.0:22          0.0.0.0:*   users:(("sshd",pid=921,fd=3))
LISTEN 0      511    127.0.0.1:8080      0.0.0.0:*   users:(("node",pid=1442,fd=19))
LISTEN 0      128    [::]:22             [::]:*      users:(("sshd",pid=921,fd=4))

Local Address 列决定所有结果,但人们通常会略过这一列。

  • 0.0.0.0:22 表示计算机上的所有 IPv4 地址,因此只要防火墙允许,外部就可以访问。
  • [::]:22 对 IPv6 表示相同含义。
  • 127.0.0.1:8080 表示仅限 loopback。此计算机之外的任何主机都无法访问它。
  • 10.20.0.5:5432 表示仅绑定到一个接口地址,不绑定其他地址,这在私有网络配置中很常见。
  • Process 列为空通常表示缺少 sudo,而不是没有进程。

要查询某个端口,请在 ss 内部进行过滤,而不要对整个列表执行 grep:

sudo ss -ltnp 'sport = :8080'
sudo lsof -nP -iTCP:8080 -sTCP:LISTEN
sudo fuser 8080/tcp

三个命令都没有输出,表示没有任何进程占用该端口。服务可能已停止、启动失败,或正在其他地址上监听。在修改任何防火墙规则之前,先查看 systemctl status <unit>journalctl -u <unit> -n 50

Local Address 中的 127.0.0.1 为什么会让人排查一下午

绑定到 127.0.0.1 的套接字无法从其他主机访问,修改防火墙规则也无济于事。内核只会将 127.0.0.0/8 路由到 loopback 接口;如果带有该目标地址的数据包从实际网卡到达,内核会将其丢弃为异常数据包。因此,进程正在运行,ss 显示它正在监听,ufw allow 8080 报告成功,但从笔记本电脑发起的连接仍然失败。连接会立即返回 Connection refused,因为数据包到达公网地址后,找不到绑定到该地址的套接字,内核于是返回 TCP reset。

许多程序会有意绑定到 loopback。对于数据库或管理接口,这是正确的默认设置。你有两种明确的选择。修改程序自身配置中的绑定地址(listen_addresses 位于 postgresql.confbind 位于 redis.conf,或者使用应用程序接受的 host 参数),然后开放防火墙端口。或者继续让它绑定到 loopback,通过其他方式访问,例如使用 nginx 反向代理,或从笔记本电脑建立 SSH 隧道:

ssh -L 8080:127.0.0.1:8080 user@203.0.113.10

Docker 的 publish 标志也有相同区别。-p 8080:8080 会绑定 0.0.0.0,并将容器暴露到互联网。-p 127.0.0.1:8080:8080 会绑定 loopback,使其保持本地可访问。

如何从另一台机器检查 Linux 上的端口是否开放

请从不同的网络运行此测试。从服务器本机测试,只能证明环回路径正常。即使从服务器连接自己的公网 IP,也会绕过服务商的网络防火墙,因为该过滤器运行在 VPS 外部。

nc -zv -w 3 203.0.113.10 443

-z 会建立连接,然后在不发送数据的情况下关闭连接。-w 3 会在三秒后放弃连接;这个参数很重要:如果不设置超时时间,丢失的数据包会使客户端持续重试 SYN,超过两分钟后内核才会停止重试。成功时的输出如下:

Connection to 203.0.113.10 443 port [tcp/https] succeeded!

如果缺少该工具(nc: command not found),请在 Debian 或 Ubuntu 上安装 netcat-openbsd,或者使用 bash 内置的网络重定向功能,完全不需要安装软件包:

timeout 3 bash -c '</dev/tcp/203.0.113.10/443' && echo open || echo "no answer"

这种语法是 bash 的功能,因此请使用 bash 运行。Debian 和 Ubuntu 上的 /bin/sh 是 dash,它不支持 /dev/tcp,并会报告路径不存在。要扫描一段端口范围,或需要显示明确的端口状态,请对由您负责的主机使用 nmap:

sudo nmap -Pn -p 22,80,443 203.0.113.10
sudo nmap -Pn -p 1-1024 203.0.113.10

-Pn 会跳过主机发现。大多数 VPS 主机会丢弃 ICMP echo,因此如果不使用 -Pn,nmap 会判断主机已关闭,并且不会进行扫描。当有服务响应并接受连接时,nmap 会显示 open;当有服务响应但返回 reset 时,会显示 closed;完全没有响应时,会显示 filtered。对于 Web 服务,curl -sS -o /dev/null -w '%{http_code}\n' https://example.com 可以区分网络故障和应用故障,因为状态码证明整条路径都正常。

为什么被阻止的端口会一直等待,而关闭的端口会立即拒绝

立即拒绝。数据包已到达计算机,并且有程序或规则对其作出了响应。

nc: connect to 203.0.113.10 port 443 (tcp) failed: Connection refused

两种不同原因都会产生这一结果。可能是没有进程绑定到该地址和端口,因此内核返回 TCP reset;也可能是防火墙规则拒绝了数据包,并返回 reset 或 ICMP port unreachable 消息。拒绝表示收到了明确响应,并会在一次往返通信内返回。

先暂停,然后超时。某个组件丢弃了数据包,没有返回任何信息。

nc: connect to 203.0.113.10 port 443 (tcp) timed out: Operation now in progress

这正是 DROP 规则的行为,云服务商防火墙或云安全组也可能如此处理。无响应是丢弃数据包的特征,因为发送方无法区分数据包被丢弃和主机已失效。

这个现象可以告诉您下一步应检查的位置。出现拒绝表示数据包已正常通过网络,因此应返回 ss -ltnp,检查绑定地址和端口号。出现超时表示数据包正在被丢弃,因此应从外部向内检查各层防火墙。SSH 中的拒绝与超时针对端口 22 分析了同一组区别;大多数人都会在这里遇到这个问题。

ufw 特意提供了这两种行为:ufw deny 8080 会丢弃数据包,ufw reject 8080 会发送拒绝响应。在 nftables 中,这两个目标分别是 dropreject;在 iptables 中则分别是 -j DROP-j REJECT。默认策略几乎总是丢弃数据包,因此缺少规则时会一直等待,而不是显示错误消息。

谁在阻止端口?从外向内排查

sudo ufw status verbose
sudo iptables -L INPUT -n -v --line-numbers
sudo nft list ruleset

-v 计数器才是有用的信息。在外部运行 nc 测试,然后再次运行 iptables 命令,查看哪个计数器发生变化:数据包计数增加的规则就是处理该流量的规则。这样可以用证据代替猜测。

决定性测试在服务器上运行。连接服务器时,同时监控网络接口:

sudo tcpdump -ni any tcp port 8080

如果能看到到达的 SYN,但没有返回 SYN-ACK,说明数据包已到达 VPS,并被主机丢弃。因此,服务商防火墙工作正常,本地规则存在问题。如果完全没有输出,说明数据包从未到达服务器,原因可能是服务商防火墙、安全组或 IP 地址错误。区分这两种情况后,大部分排查工作都可以省去。

有两层配置会产生看似不可能的结果。第一层是 IPv6:如果主机名有 AAAA 记录,客户端可能通过 IPv6 连接,而你的规则只覆盖 IPv4。因此,在确认任一结果前,先使用 nc -4nc -6 分别测试两个地址族。VPS 上的 ufw 规则和 IPv6 端口介绍了这种不匹配问题。第二层是 Docker:即使 ufw status 将该端口列为 denied,已发布的容器端口仍可能可以从互联网访问,因为这些数据包在 ufw 链处理之前就已被处理。Docker 为什么会绕过 ufw 直接发布端口介绍了其工作机制和修复方法;新 VPS 上应设置的 ufw 规则则提供了首先应配置的基础规则集。

UDP 响应为何从设计上就存在歧义

UDP 没有握手,因此探测没有可判定成功的过程。nc -zu 203.0.113.10 53 在数据包离开本机后立即返回 0;这只能证明本机已发送数据包,不能证明远端发生了任何事情。UDP 端口关闭时,主机通常会回复 ICMP 端口不可达消息。内核只会在下一次写入时,向已连接的套接字报告该错误,因此单次数据包探测会漏掉这个错误。防火墙通常会丢弃 ICMP,因此连这一线索也会消失。这就是 nmap 对大多数 UDP 端口打印 open|filtered 的原因:开放但不响应的服务和被过滤的端口都会产生完全相同的无响应结果。

应通过实际使用的协议测试 UDP。DNS 服务器会对 dig +short @203.0.113.10 example.com 作出响应,返回地址或不返回任何内容。WireGuard 对端会在 sudo wg show 中显示最近的 latest handshake 行。然后在服务器端确认数据包确实到达:

sudo tcpdump -ni any udp port 51820

客户端发送数据包时,如果能看到数据包出现,说明数据包已经到达,问题就在服务或输入链中。如果完全看不到数据包,说明数据包根本没有到达。

按最快定位故障的顺序检查

  1. 在服务器上运行 sudo ss -ltnp 'sport = :8080'。没有输出表示没有进程监听,因此先修复服务。
  2. 如果有输出,请查看 Local Address 列。127.0.0.1 表示外部无法访问,除非重新绑定地址或在前面配置代理。
  3. 从其他网络运行 nc -zv -w 3 <public ip> 8080
  4. 如果连接被拒绝,请回到第 1 步。地址、端口或服务器并不是您以为的那个。
  5. 如果请求超时,表示数据包被丢弃。在服务器上启动 sudo tcpdump -ni any tcp port 8080,然后重复测试。
  6. 收到 SYN,但没有任何响应:问题出在主机防火墙。查找在 sudo iptables -L INPUT -n -v 中计数器发生变化的规则。
  7. 没有收到 SYN:问题出在服务商防火墙、安全组或错误的 IP 地址。

FAQ

如何检查自己的 Linux 服务器开放了哪些端口?

运行 sudo ss -ltnp 检查 TCP,运行 sudo ss -lunp 检查 UDP。每一行代表一个监听套接字,Local Address 列表示哪些主机可以访问它:0.0.0.0[::] 会接受防火墙允许的任意来源连接,而 127.0.0.1 只接受本机连接。Process 列需要 root 权限,因此请使用 sudo 运行,否则该列会为空。ss 属于 iproute2,始终会安装;netstat 属于 net-tools,通常不会安装。

为什么 ss 显示服务正在监听,但我仍然无法连接?

通常有两个原因,使用一个命令即可区分。如果 Local Address 是 127.0.0.1,说明服务绑定到了 loopback,其他主机无法访问,因为内核只会将该地址范围路由到 loopback 接口。如果是 0.0.0.0,但连接仍然失败,请在服务器上运行 sudo tcpdump -ni any tcp port <port>,然后从外部发起连接。SYN 到达但没有回复,表示本地防火墙规则丢弃了该数据包。完全没有数据包到达,表示数据包在到达 VPS 之前就被拦截了,通常是提供商防火墙或安全组导致的。

被拒绝的连接和超时的连接有什么区别?

拒绝是一种响应。数据包已到达主机,并收到 TCP reset 或 ICMP port unreachable 响应。这表示该地址和端口没有服务监听,或者某条规则拒绝了连接。超时表示没有响应:某条规则丢弃了数据包且未发送任何响应,因此客户端会不断重试,直到放弃。连接被拒绝时,应检查服务及其绑定地址。连接超时时,应检查防火墙,并首先检查最接近公网入口的防火墙。

如何检查 UDP 端口是否开放?

无法通过通用探测可靠地确认,因为 UDP 没有握手过程,静默服务和被丢弃的数据包表现相同。nc -zu 只要发送数据包就会返回成功,nmap 出于相同原因会报告 open|filtered。应通过实际使用协议进行测试:DNS 使用 dig +short @<host> example.com,WireGuard 对等端则使用 sudo wg show 检查最近一次握手。要确认数据包确实到达服务器,请在客户端发送数据时于服务器上运行 sudo tcpdump -ni any udp port <port>

仍然可以使用 telnet host port 测试端口吗?

TCP 端口可以使用该方法测试,Escape character is '^]' 表示连接已被接受。使用 Ctrl+] 退出,然后运行 quit。有两个原因使 nc -z 成为更好的工具:telnet 在当前大多数服务器镜像中都未安装,而 nc 可通过 -w 设置超时时间,并设置可在脚本中检查的退出状态。两者都不可用时,timeout 3 bash -c '</dev/tcp/<host>/<port>' 完全不需要安装软件包。