公众号旧文
如何在 Linux 服务器上按端口统计流量?
服务器商家后台显示机器用了很多流量,
但不知道这些流量是哪个服务、哪个端口产生的。
一台服务器上可能同时跑着:
- SSH:22 端口
- Nginx:80 / 443 端口
- DNS:53 端口
- Tailscale:UDP 随机端口
- 其他自定义服务端口
如果只看总流量,很难判断到底是谁消耗了流量。
这个时候就可以用 iptables / ip6tables 做按端口流量统计。
一、基本思路
Linux 的 iptables 规则本身就带有计数器。
每一条规则都会记录:
pkts packets 数量
bytes 字节数
所以我们可以创建一组专门用于统计的规则。
让流量经过这些规则,但不拦截、不放行、不改变原有防火墙逻辑。
只用它们的计数器来统计流量。
核心思路是:
指定端口流量 -> 单独统计
未知端口流量 -> 归到 OTHER
只统计外网网卡 -> 排除 127.0.0.1 本地回环流量
IPv4 用 iptables
IPv6 用 ip6tables
二、先确认外网网卡
先查看服务器默认出口网卡:
ip route show default
示例输出:
default via 10.57.68.1 dev eth0 proto dhcp src 10.57.68.55
其中:
dev eth0
说明外网网卡是 eth0。
后面的规则都只统计 eth0,这样可以避免把 127.0.0.1、本机端口转发、本地 DNS 等回环流量误算进去。
三、查看当前机器有哪些端口在监听
在配置统计前,建议先查看当前服务器有哪些服务正在监听端口:
ss -tulnp
这个命令可以看到:
TCP / UDP
监听地址
监听端口
对应进程
比如:
tcp LISTEN 0 128 0.0.0.0:22 users:(("sshd",pid=150,fd=3))
tcp LISTEN 0 128 127.0.0.1:8080 users:(("ssh",pid=1918,fd=5))
udp UNCONN 0 0 0.0.0.0:41641 users:(("tailscaled",pid=1166,fd=19))
这里要区分两类端口:
1. 公网监听端口
例如:
0.0.0.0:22
[::]
:22
0.0.0.0:41641
这些端口可能产生公网流量,值得统计。
2. 本机回环端口
例如:
127.0.0.1:8080
127.0.0.53:53
[::1]
:8080
这些只在本机内部使用,不应该算作公网月流量。
所以按端口统计流量时,最好配合网卡参数:
-i eth0
-o eth0
只统计外网网卡流量。
四、创建按端口统计规则
下面是一份完整示例。
假设外网网卡是 eth0。
统计的已知端口包括:
TCP:
22, 53, 80, 443, 2053, 2083, 2087, 2096, 8080, 8443, 5355
UDP:
53, 443, 8443, 36409, 41641, 5355
其中:
22 SSH
53 DNS
80/443 Web
41641 Tailscale
5355 systemd-resolve / LLMNR
36409 自定义 UDP 服务示例
可以根据自己的机器情况修改端口列表。
执行:
IFACE=eth0
TCP_PORTS="22 53 80 443 2053 2083 2087 2096 8080 8443 5355"
UDP_PORTS="53 443 8443 36409 41641 5355"
echo "当前统计网卡: $IFACE"
echo "TCP端口: $TCP_PORTS"
echo "UDP端口: $UDP_PORTS"
# 创建 IPv4 统计链
iptables -N PORT_TRAFFIC_IN 2>/dev/null
iptables -N PORT_TRAFFIC_OUT 2>/dev/null
# 创建 IPv6 统计链
ip6tables -N PORT_TRAFFIC_IN 2>/dev/null
ip6tables -N PORT_TRAFFIC_OUT 2>/dev/null
# 把统计链挂到 INPUT / OUTPUT
iptables -C INPUT -j PORT_TRAFFIC_IN 2>/dev/null || iptables -I INPUT -j PORT_TRAFFIC_IN
iptables -C OUTPUT -j PORT_TRAFFIC_OUT 2>/dev/null || iptables -I OUTPUT -j PORT_TRAFFIC_OUT
ip6tables -C INPUT -j PORT_TRAFFIC_IN 2>/dev/null || ip6tables -I INPUT -j PORT_TRAFFIC_IN
ip6tables -C OUTPUT -j PORT_TRAFFIC_OUT 2>/dev/null || ip6tables -I OUTPUT -j PORT_TRAFFIC_OUT
# 清空旧统计规则
iptables -F PORT_TRAFFIC_IN
iptables -F PORT_TRAFFIC_OUT
ip6tables -F PORT_TRAFFIC_IN
ip6tables -F PORT_TRAFFIC_OUT
# IPv4 TCP 端口统计
for port in $TCP_PORTS; do
iptables -A PORT_TRAFFIC_IN -i "$IFACE" -p tcp --dport "$port" -j RETURN
iptables -A PORT_TRAFFIC_OUT -o "$IFACE" -p tcp --sport "$port" -j RETURN
done
# IPv4 UDP 端口统计
for port in $UDP_PORTS; do
iptables -A PORT_TRAFFIC_IN -i "$IFACE" -p udp --dport "$port" -j RETURN
iptables -A PORT_TRAFFIC_OUT -o "$IFACE" -p udp --sport "$port" -j RETURN
done
# IPv4 OTHER:其他端口总流量
iptables -A PORT_TRAFFIC_IN -i "$IFACE" -m comment --comment "OTHER" -j RETURN
iptables -A PORT_TRAFFIC_OUT -o "$IFACE" -m comment --comment "OTHER" -j RETURN
# IPv6 TCP 端口统计
for port in $TCP_PORTS; do
ip6tables -A PORT_TRAFFIC_IN -i "$IFACE" -p tcp --dport "$port" -j RETURN
ip6tables -A PORT_TRAFFIC_OUT -o "$IFACE" -p tcp --sport "$port" -j RETURN
done
# IPv6 UDP 端口统计
for port in $UDP_PORTS; do
ip6tables -A PORT_TRAFFIC_IN -i "$IFACE" -p udp --dport "$port" -j RETURN
ip6tables -A PORT_TRAFFIC_OUT -o "$IFACE" -p udp --sport "$port" -j RETURN
done
# IPv6 OTHER:其他端口总流量
ip6tables -A PORT_TRAFFIC_IN -i "$IFACE" -m comment --comment "OTHER" -j RETURN
ip6tables -A PORT_TRAFFIC_OUT -o "$IFACE" -m comment --comment "OTHER" -j RETURN
# 清零,从当前时刻重新开始统计
iptables -Z PORT_TRAFFIC_IN
iptables -Z PORT_TRAFFIC_OUT
ip6tables -Z PORT_TRAFFIC_IN
ip6tables -Z PORT_TRAFFIC_OUT
五、为什么要加 OTHER?
如果只统计指定端口,比如只统计:
22
80
443
8443
那么如果有其他端口突然产生大量流量,比如:
3000
5000
51820
随机 UDP 端口
你是看不到的。
所以建议在最后加一条 OTHER 统计规则。
这样结果会分成两类:
已知端口:单独显示
未知端口:统一归到 OTHER
如果后面发现:
OTHER 出站 20GB
就说明有未列入统计的端口在跑流量,需要继续排查。
六、创建查看脚本
直接查看 iptables -L 输出比较难读,可以创建一个脚本,把 bytes 自动换算成 MB 和 GB。
创建脚本:
cat > /usr/local/bin/port-traffic <<'EOF'
#!/bin/bash
show_chain() {
local CMD="$1"
local IPVER="$2"
local DIR="$3"
local CHAIN="$4"
$CMD -L "$CHAIN" -v -n -x 2>/dev/null | awk -v ipver="$IPVER" -v dir="$DIR" '
/dpt:|spt:|OTHER/ {
bytes=$2
if ($0 ~ /tcp/) proto="tcp"
else if ($0 ~ /udp/) proto="udp"
else proto="all"
if ($0 ~ /OTHER/) {
port="OTHER"
} else {
port=$NF
sub("dpt:","",port)
sub("spt:","",port)
}
printf "%-5s %-6s %-4s %-8s %15d bytes %10.2f MB %10.4f GB\n", ipver, dir, proto, port, bytes, bytes/1024/1024, bytes/1024/1024/1024
}'
}
echo "IP版本 方向 协议 端口 bytes MB GB"
echo "--------------------------------------------------------------------------"
show_chain iptables IPv4 入站 PORT_TRAFFIC_IN
show_chain iptables IPv4 出站 PORT_TRAFFIC_OUT
show_chain ip6tables IPv6 入站 PORT_TRAFFIC_IN
show_chain ip6tables IPv6 出站 PORT_TRAFFIC_OUT
EOF
赋权:
chmod +x /usr/local/bin/port-traffic
以后直接执行:
port-traffic
示例输出:
IP版本 方向 协议 端口 bytes MB GB
--------------------------------------------------------------------------
IPv4 入站 tcp 22 7440 bytes 0.01 MB 0.0000 GB
IPv4 出站 tcp 22 13100 bytes 0.01 MB 0.0000 GB
IPv4 入站 all OTHER 6870 bytes 0.01 MB 0.0000 GB
IPv4 出站 all OTHER 5256 bytes 0.01 MB 0.0000 GB
IPv6 入站 all OTHER 1328 bytes 0.00 MB 0.0000 GB
IPv6 出站 all OTHER 1216 bytes 0.00 MB 0.0000 GB
七、如何理解统计结果?
1. 入站和出站都要看
服务商一般统计的是总流量,通常要看:
入站 + 出站
比如:
IPv4 入站 tcp 443:10GB
IPv4 出站 tcp 443:90GB
那么 443 端口大概用了:
100GB
2. SSH 有少量流量是正常的
只要你正在登录服务器,22/tcp 就会一直有少量流量:
IPv4 入站 tcp 22
IPv4 出站 tcp 22
这属于正常情况。
3. OTHER 很小不用管
如果 OTHER 只有几 KB、几 MB,一般是系统正常通信或零散流量。
如果 OTHER 很大,比如几百 MB、几 GB、几十 GB,就要排查未知端口。
八、排查 OTHER 流量
如果发现 OTHER 很大,可以先看当前监听端口:
ss -tulnp
也可以实时查看端口连接流量:
apt install -y iftop
iftop -i eth0 -P
其中:
-i eth0
表示指定外网网卡。
-P
表示显示端口。
这样可以看到当前哪些连接、哪些端口正在跑流量。
九、清零重新开始统计
如果想从当前时间重新开始统计,可以执行:
iptables -Z PORT_TRAFFIC_IN
iptables -Z PORT_TRAFFIC_OUT
ip6tables -Z PORT_TRAFFIC_IN
ip6tables -Z PORT_TRAFFIC_OUT
然后再查看:
port-traffic
十、持久化保存规则
默认情况下,iptables 规则重启后可能丢失。
Debian / Ubuntu 可以安装:
apt update
apt install -y iptables-persistent
安装过程中如果询问:
Save current IPv4 rules?
Save current IPv6 rules?
都选择:
Yes
之后手动保存:
netfilter-persistent save
看到类似输出:
run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables save
run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables save
说明 IPv4 和 IPv6 规则都保存成功了。
十一、这种方式的优缺点
优点
不需要额外安装复杂监控系统
直接利用 iptables 自带计数器
可以同时统计 IPv4 和 IPv6
可以按端口区分流量
可以排除本机回环流量
可以增加 OTHER 发现未知端口流量
缺点
每台机器都要单独配置
只能统计本机流量
端口列表需要根据服务情况维护
不能直接显示历史曲线
规则重启后需要持久化保存
总结
按端口统计 VPS 流量的一种实用方案:
iptables / ip6tables 统计链
指定外网网卡
常用端口单独统计
未知端口归到 OTHER
port-traffic 脚本格式化输出
netfilter-persistent 持久化保存
这样既能知道 22、443、8443、41641 等端口分别用了多少流量,
也能通过 OTHER 发现未知端口是否在偷偷跑流量。
对于日常排查 VPS 月流量、Tailscale 流量、Web 服务流量,这种方式已经足够实用。