如何在Linux VPS上使用UFW和nftables配置防火墙

3 分钟阅读·Matthieu·vpssecuritylinuxfirewallnftablesufw|

在你的Linux VPS上使用UFW或nftables配置默认拒绝防火墙。两种工具,一个目标:只有你明确允许的端口保持开放。

新开通的VPS没有任何防火墙规则。所有端口都是开放的。自动化扫描器会在你的服务器上线几分钟内发现它,然后开始探测SSH、测试默认凭据、寻找暴露的服务。默认拒绝防火墙是第一道防线。

本教程涵盖两个工具:

  • UFW——一个简化的前端,通过简短的命令生成防火墙规则。适合快速建立安全基线。
  • nftables——Linux原生防火墙框架,替代iptables。适合需要精细控制、Docker兼容性或按IP速率限制的运维人员。

选择适合你需求的路径。两者最终结果相同:一个经过验证的默认拒绝防火墙,只有你明确允许的端口可以访问。

应该在VPS上使用UFW还是nftables?

UFW是一个简化的前端,通过ufw allow 22等简短命令生成iptables/nftables规则。nftables是Linux原生防火墙框架,替代iptables,使用表、链和规则,语法更清晰。UFW适合想要快速默认配置的初学者。nftables适合需要使用meter进行速率限制、命名集合或Docker兼容规则的运维人员。

特性 UFW nftables
学习曲线 低。单行命令。 中等。表/链/规则结构。
默认安装于 Ubuntu(已安装,未激活) Debian 12(已安装,最小配置)
IPv6支持 自动(双栈) 需要手动规则(inet族)
速率限制 ufw limit(按规则) Meter,按IP跟踪
Docker兼容 否。Docker绕过UFW规则。 是。nftables与Docker的DOCKER-USER链配合工作。
配置持久化 ufw enable时自动 /etc/nftables.conf + systemd
推荐场景 单应用VPS、第一台服务器 多服务、Docker主机、生产环境

如果你运行Docker,跳过UFW或阅读修复Docker绕过UFW防火墙:4种经过测试的VPS解决方案了解解决方法。Docker直接操作iptables,完全绕过UFW,即使UFW显示端口被阻止,容器端口仍然暴露在互联网上。

前提条件

在修改防火墙规则之前,确认两件事:

  1. **你有SSH访问权限并且可以正常使用。**你现在正通过SSH连接到你的VPS。
  2. **你有控制台访问作为备用方案。**你的托管商控制面板提供VNC或串行控制台。如果SSH被锁定,你仍然可以通过控制台访问服务器。

本教程针对Ubuntu 24.04Debian 12。除非另有说明,命令在两者上都适用。

检查你的操作系统版本:

cat /etc/os-release | grep PRETTY_NAME

预期输出:

PRETTY_NAME="Ubuntu 24.04.4 LTS"

PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"

如何在Ubuntu 24.04上配置UFW?

UFW在Ubuntu 24.04上默认安装但未激活。在Debian 12上,先安装它:

apt update && apt install -y ufw

检查当前状态:

ufw status

预期输出:

Status: inactive

如何使用UFW启用默认拒绝?

将默认策略设置为丢弃所有入站流量,然后只明确允许你的服务需要的端口。使用UFW:设置默认值,允许SSH,然后启用。顺序很重要。如果在允许SSH之前启用UFW,你会把自己锁在外面。

设置默认策略:

ufw default deny incoming
ufw default allow outgoing

这告诉UFW默认丢弃所有入站连接,允许所有出站连接。你的服务器仍然可以访问互联网(用于更新、DNS等),但外部的任何流量如果没有规则就无法进入。

如何在不被锁定的情况下允许SSH?

在启用UFW之前允许SSH。这是最重要的一步:

ufw allow 22/tcp comment 'SSH'

如果你更改了SSH端口(例如改为2222),使用那个端口号。

现在启用UFW:

ufw enable

你会看到:

Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

你当前的SSH会话保持不变。UFW在激活之前添加允许规则,因此现有连接不会断开。

验证规则:

ufw status verbose

预期输出:

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere                   # SSH
22/tcp (v6)                ALLOW IN    Anywhere (v6)              # SSH

注意:IPv4和IPv6规则同时出现。当/etc/default/ufw中设置了IPV6=yes时,UFW会自动创建双栈规则(这是Ubuntu 24.04的默认设置)。

如何使用UFW允许Web流量?

如果你的VPS运行Web服务器,允许HTTP和HTTPS:

ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'

验证:

ufw status numbered
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     ALLOW IN    Anywhere                   # SSH
[ 2] 80/tcp                     ALLOW IN    Anywhere                   # HTTP
[ 3] 443/tcp                    ALLOW IN    Anywhere                   # HTTPS
[ 4] 22/tcp (v6)                ALLOW IN    Anywhere (v6)              # SSH
[ 5] 80/tcp (v6)                ALLOW IN    Anywhere (v6)              # HTTP
[ 6] 443/tcp (v6)               ALLOW IN    Anywhere (v6)              # HTTPS

编号视图在你需要用ufw delete <number>删除特定规则时很有用。

如何使用UFW限制SSH连接速率?

UFW内置了速率限制器。它拒绝在30秒内尝试超过6次连接的IP。用限制规则替换普通允许规则:

ufw delete allow 22/tcp
ufw limit 22/tcp comment 'SSH rate-limited'

验证:

ufw status verbose

SSH规则现在显示LIMIT IN而不是ALLOW IN。这会减缓暴力破解尝试,但不会阻止合法访问。要获得更强的保护,可以与Fail2Ban结合使用在Linux VPS上安装和配置Fail2Ban

如何使用UFW允许特定IP或子网?

按源IP限制服务访问:

ufw allow from 198.51.100.0/24 to any port 22 proto tcp comment 'SSH from office'

允许单个IP访问所有端口:

ufw allow from 198.51.100.42 comment 'Trusted admin'

这对不应该面向公共互联网的管理服务很有用。将受限访问与默认拒绝策略结合使用。

如何删除UFW规则?

通过指定确切的规则来删除。这是最安全的方法,因为它不受规则顺序影响:

ufw delete allow 80/tcp

你也可以按编号删除。先列出带编号的规则:

ufw status numbered

然后按编号删除:

ufw delete 2

按编号删除时要小心。每次添加或删除规则时编号都会改变。删除前务必先执行ufw status numbered确认每个编号对应的规则。删错编号可能导致SSH被锁定。

如何配置UFW日志?

启用日志以查看被阻止的连接:

ufw logging on

UFW支持三个日志级别:lowmediumhigh。默认的low级别记录被阻止的数据包。排查问题时,临时提高级别:

ufw logging medium

查看日志:

journalctl -k -f | grep UFW

或直接检查日志文件:

tail -20 /var/log/ufw.log

调试完成后设回low。较高级别会在繁忙服务器上产生大量磁盘I/O。

UFW支持IPv6吗?

支持。当/etc/default/ufw中设置了IPV6=yes时,UFW同时管理IPv4和IPv6。这在Ubuntu 24.04上默认启用。验证:

grep IPV6 /etc/default/ufw

预期:

IPV6=yes

每条ufw allow规则会自动创建对应的IPv4和IPv6条目。无需额外步骤。

UFW验证清单

运行以下检查确认防火墙正常工作:

  1. 列出所有规则:ufw status verbose
  2. 检查UFW是否开机启动:systemctl is-enabled ufw
  3. 从第二个终端测试SSH(不要关闭当前会话)
  4. 从服务器外部测试——从你的本地机器:
nc -zv YOUR_SERVER_IP 22

预期:Connection to YOUR_SERVER_IP 22 port [tcp/ssh] succeeded!

nc -zv YOUR_SERVER_IP 25

预期:连接被拒绝或超时(端口25未被允许)。

如何在Debian 12上配置nftables?

nftables是Debian 12上的默认防火墙框架。它用更清晰的语法和更好的性能替代iptables。在Ubuntu 24.04上,如果你想用它代替UFW,先安装:

apt update && apt install -y nftables

**如果UFW处于活动状态,先禁用它。**同时运行两者会产生冲突规则:

ufw disable
systemctl disable --now ufw

什么是nftables的表、链和规则?

nftables将防火墙规则组织在层级结构中:

  • (table)——一个包含链的容器。inet族在一个表中同时处理IPv4和IPv6。
  • (chain)——一组规则,挂接到数据包处理的特定点。input链过滤发往服务器的数据包。forward链过滤转发的数据包。
  • 规则(rule)——一个匹配-动作对。"如果数据包匹配TCP端口22,接受。"

核心概念:将链的策略设置为drop,然后添加对特定流量执行accept的规则。未被明确允许的一切都会被静默丢弃。

如何编写默认拒绝的nftables规则集?

将默认策略设置为丢弃所有入站流量,然后添加SSH、HTTP和HTTPS的规则。使用nftables,你将其写成配置文件。

创建配置:

cp /etc/nftables.conf /etc/nftables.conf.bak
cat > /etc/nftables.conf << 'NFTEOF'
#!/usr/sbin/nft -f

flush ruleset

table inet firewall {

    set ssh_ratelimit {
        type ipv4_addr
        flags dynamic
        timeout 60s
    }

    set ssh_ratelimit6 {
        type ipv6_addr
        flags dynamic
        timeout 60s
    }

    chain inbound_ipv4 {
        icmp type echo-request limit rate 5/second accept
    }

    chain inbound_ipv6 {
        icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept
        icmpv6 type echo-request limit rate 5/second accept
    }

    chain inbound {
        type filter hook input priority filter; policy drop;

        ct state established,related accept
        ct state invalid drop

        iifname "lo" accept

        meta protocol vmap { ip : jump inbound_ipv4, ip6 : jump inbound_ipv6 }

        tcp dport 22 ct state new add @ssh_ratelimit { ip saddr limit rate 3/minute burst 5 packets } accept
        tcp dport 22 ct state new add @ssh_ratelimit6 { ip6 saddr limit rate 3/minute burst 5 packets } accept

        tcp dport { 80, 443 } accept

        log prefix "[nftables] Dropped: " counter drop
    }

    chain forward {
        type filter hook forward priority filter; policy drop;
    }

    chain outbound {
        type filter hook output priority filter; policy accept;
    }
}
NFTEOF

每个部分的作用:

  • flush ruleset——清除所有现有规则,从零开始。
  • table inet firewall——在inet族中创建一个表(IPv4+IPv6双栈)。
  • set ssh_ratelimit——一个动态集合,跟踪SSH速率限制的源IP。条目在60秒后过期。
  • chain inbound——主入站链,策略为drop。不匹配任何规则的数据包都会被丢弃。
  • ct state established,related accept——允许服务器发起的连接的返回流量。没有这条规则,出站连接(apt更新、DNS查询)会失败。
  • ct state invalid drop——丢弃不属于任何已知连接的畸形数据包。
  • iifname "lo" accept——允许回环流量。很多服务通过localhost进行内部通信。
  • meta protocol vmap——根据协议跳转到IPv4或IPv6特定的链。分别处理ICMP和ICMPv6。
  • tcp dport 22 ... limit rate 3/minute——允许SSH并按IP进行速率限制。每个源IP每分钟3个新连接,突发5个。
  • tcp dport { 80, 443 } accept——允许HTTP和HTTPS。
  • log prefix "[nftables] Dropped: "——将所有被丢弃的数据包记录到内核日志中,用于排查问题。

如何在nftables中处理IPv6?

表定义中的inet族在一个规则集中同时处理IPv4和IPv6。但IPv6需要特定的ICMPv6类型才能让基本网络正常工作。

inbound_ipv6链接受三种ICMPv6类型:

  • nd-neighbor-solicit——相当于IPv6的ARP。没有它,你的服务器无法发现本地网络上的邻居。
  • nd-router-advert——允许路由器宣告自身。SLAAC(自动IPv6地址配置)所必需。
  • nd-neighbor-advert——邻居请求的响应。IPv6连通性所必需。

阻止其中任何一种都会破坏IPv6网络。上面的规则集正确处理了这一点。如果你只有IPv4,这些规则是无害的——它们根本不会匹配。

如何使用nftables meter限制连接速率?

上面的规则集使用动态集合(以前称为meter)对SSH进行按IP速率限制。当连接到达时,处理流程如下:

  1. 一个新的TCP连接从198.51.100.42到达端口22。
  2. nftables检查@ssh_ratelimit中是否有匹配该IP的条目。
  3. 如果该IP在过去一分钟内的连接少于3个,连接被接受,计数器更新。
  4. 如果该IP超过限制,规则不匹配,数据包落入drop策略。

burst 5 packets参数允许短暂的突发,然后强制执行稳定速率。集合上的timeout 60s意味着条目会自动清理,防止集合无限增长。

检查速率限制器的当前状态:

nft list set inet firewall ssh_ratelimit

这会显示当前正在跟踪的IP及其计数器。

如何为其他服务添加规则?

上面的规则集允许SSH、HTTP和HTTPS。要添加更多服务,在inbound链的最后一行log ... drop之前插入规则。

例如,只允许特定IP访问端口3000上的Node.js应用:

tcp dport 3000 ip saddr 198.51.100.42 accept

允许WireGuard等UDP服务使用端口51820:

udp dport 51820 accept

允许端口范围(例如被动FTP):

tcp dport 40000-50000 accept

编辑/etc/nftables.conf后,验证语法但不应用:

nft -c -f /etc/nftables.conf

-c标志检查错误后退出。没有输出表示语法有效。

如何在运行时管理nftables规则?

你可以在不编辑配置文件的情况下添加和删除规则。这些更改是临时的,重启后丢失,除非你保存它们。

运行时添加规则:

nft add rule inet firewall inbound tcp dport 8080 accept

列出当前规则集:

nft list ruleset

通过handle编号删除规则。先列出带handle的规则:

nft -a list chain inet firewall inbound

每条规则显示一个# handle N后缀。通过handle删除:

nft delete rule inet firewall inbound handle 15

将运行时更改保存到配置文件:

nft list ruleset > /etc/nftables.conf

在文件顶部重新添加shebang行:

sed -i '1i #!/usr/sbin/nft -f' /etc/nftables.conf

如何应用和持久化nftables规则?

应用配置:

nft -f /etc/nftables.conf

验证规则已加载:

nft list ruleset

你应该能看到包含所有链和规则的完整表。如果有语法错误,nft -f会输出行号和错误信息。

设置nftables开机启动:

systemctl enable --now nftables

enable使其在重启后保持。--now立即启动。验证服务正在运行:

systemctl status nftables

预期输出包含Active: active (exited)exited状态是正常的。nftables将规则加载到内核后退出。规则在内核空间中保持活跃。

确认已设置为下次启动时启用:

systemctl is-enabled nftables

预期:enabled

如何查看nftables日志?

规则集在最后的drop之前包含一条log语句。被丢弃的数据包会出现在内核日志中,前缀为[nftables] Dropped:

实时查看被丢弃的数据包:

journalctl -k -f | grep nftables

一条典型的日志条目:

Mar 19 14:23:01 vps kernel: [nftables] Dropped: IN=eth0 OUT= SRC=203.0.113.55 DST=198.51.100.1 PROTO=TCP SPT=44521 DPT=3389

这告诉你:一个外部IP(203.0.113.55)试图访问你服务器上的端口3389(RDP)并被丢弃。这是正常的扫描流量。如果你在SRC字段中看到自己的IP,说明规则有问题。

为避免在频繁被扫描的服务器上产生日志垃圾,下面的故障排除部分说明了如何为日志规则添加速率限制。

nftables验证清单

  1. 列出完整规则集:nft list ruleset
  2. 检查服务:systemctl is-enabled nftables
  3. 从第二个终端测试SSH(保持当前会话打开)
  4. 从本地机器测试:
nc -zv YOUR_SERVER_IP 22

预期:连接成功。

nc -zv YOUR_SERVER_IP 25

预期:连接被拒绝或超时。

  1. 检查日志中的丢弃数据包:
journalctl -k | grep "nftables"

修改防火墙规则时如何防止SSH锁定?

在配置防火墙时,把自己锁在SSH外面是最大的风险。两个保障措施可以防止这种情况。

保障措施1:始终在第二个终端中测试

在修改防火墙规则后关闭SSH会话之前,打开一个新终端通过SSH连接到你的服务器。如果新连接成功,你的规则是正确的。如果失败,回到原来的会话修复规则。

在确认第二个连接可以正常工作之前,永远不要关闭你正在使用的SSH会话。

保障措施2:使用at定时安全恢复

测试nftables更改时,安排一个任务在5分钟后自动清除所有规则。如果新规则把你锁在外面,等5分钟后重试。

at now + 5 minutes <<< 'nft flush ruleset'

如果at未安装:

apt install -y at
systemctl enable --now atd
at now + 5 minutes <<< 'nft flush ruleset'

确认规则正常工作后,取消安全任务:

atrm $(atq | awk '{print $1}')

对于UFW,等效的安全措施:

at now + 5 minutes <<< 'ufw disable'

Docker和防火墙怎么办?

Docker直接操作iptables来设置容器网络。当你用-p 8080:80发布端口时,Docker创建的NAT规则完全绕过UFW。你的ufw deny规则对Docker发布的端口没有任何效果。

这是Linux VPS上最常见的防火墙意外。一个你以为被阻止的端口实际上完全开放,因为Docker将流量绕过了你的防火墙。

两个解决方案:

  1. **使用nftables代替UFW。**nftables不存在同样的绕过问题,因为你控制着完整的规则集。
  2. **应用DOCKER-USER链修复。**参见修复Docker绕过UFW防火墙:4种经过测试的VPS解决方案获取强制Docker流量通过UFW的详细步骤。

如果你在生产环境中运行Docker,nftables是更安全的选择。

常用端口参考

服务 端口 协议 UFW命令 nftables规则
SSH 22 TCP ufw allow 22/tcp tcp dport 22 accept
HTTP 80 TCP ufw allow 80/tcp tcp dport 80 accept
HTTPS 443 TCP ufw allow 443/tcp tcp dport 443 accept
DNS 53 TCP/UDP ufw allow 53 tcp dport 53 accept; udp dport 53 accept
PostgreSQL 5432 TCP ufw allow 5432/tcp tcp dport 5432 accept
MySQL 3306 TCP ufw allow 3306/tcp tcp dport 3306 accept

不要将数据库端口暴露到互联网上。如果需要远程数据库访问,使用SSH隧道或限制为特定IP:

UFW:

ufw allow from 198.51.100.0/24 to any port 5432 proto tcp comment 'PostgreSQL from trusted network'

nftables(在inbound链的最后drop之前添加):

tcp dport 5432 ip saddr 198.51.100.0/24 accept

故障排除

出了什么问题?

**SSH被锁定:**使用你的托管商的VNC/串行控制台连接。然后执行ufw disablenft flush ruleset清除所有规则。在重新启用防火墙之前,先重新添加SSH允许规则。

**规则在重启后不保留(nftables):**检查服务是否已启用:systemctl is-enabled nftables。如果显示disabled,执行systemctl enable nftables。同时验证/etc/nftables.conf语法是否有效:nft -c -f /etc/nftables.conf-c标志检查语法但不应用)。

**UFW显示规则但流量仍被阻止:**检查是否有冲突的nftables或iptables规则:nft list rulesetiptables -L -n。同时运行两个防火墙工具会产生不可预测的结果。

**日志占满磁盘:**如果你启用了日志且服务器接收大量扫描流量,日志会快速增长。降低日志级别(ufw logging low)或为nftables日志规则添加速率限制:

log prefix "[nftables] Dropped: " limit rate 10/minute counter drop

**启用速率限制后无法连接:**速率限制器可能太严格。对于nftables,检查动态集合:nft list set inet firewall ssh_ratelimit。对于UFW,ufw limit使用固定的6连接/30秒阈值,无法配置。如果太严格,使用普通的ufw allow并依赖Fail2Ban在Linux VPS上安装和配置Fail2Ban

下一步

防火墙阻止不需要的端口。它不检测重复的登录失败尝试或应用层攻击。要完成你的VPS安全基线:


版权所有 2026 Virtua.Cloud。保留所有权利。 本内容为 Virtua.Cloud 团队原创作品。 未经书面许可,禁止复制、转载或再分发。

准备好亲自尝试了吗?

几秒内部署您自己的服务器。支持 Linux、Windows 或 FreeBSD。

查看 VPS 方案