上一篇 下一篇 分享链接 返回 返回顶部

香港服务器上如何利用 Ubuntu 18.04 的 firewalld 优化自定义网络策略,提高跨境访问速度并增强安全性?

发布人:Minchunlin 发布时间:2025-08-24 09:56 阅读量:598


凌晨 1:40,我站在机房 19U 的机柜前,手心还残着酒精湿巾的凉。白天华南业务部刚把“跨境访问慢”的锅甩了过来:广州与深圳用户打开我们在香港的 API 时延波动大、偶发 504,运维台上 SYN -> SYN/ACK 的握手就像堵在一条看不见的隧道里。
我做过太多“加带宽”“上 CDN”的直觉尝试,效果都一般。那晚我决定换个思路:用 firewalld 做一层“会思考的边界”,把无效流量挡在外面,把有效流量引到正确的链路上;再配合内核与路由调优,既要稳也要快。

下面是我那一夜到第二天清晨的完整实操与复盘。过程不神秘,但每一步都踩在真实场景的坑沿上。

1. 现场环境与目标

1.1 硬件与网络拓扑

项目 规格
机型 Dell R740(示例)
CPU Intel Xeon Silver 4210 × 2
内存 128 GB
系统盘 2 × 960 GB SSD(RAID1)
数据盘 2 × 1.92 TB NVMe(RAID1)
网卡 2 × 10GbE(eno1:国际 BGP/CMI,eno2:优化回国/CN2)
操作系统 Ubuntu 18.04.5 LTS(内核 4.15.0-*)
核心组件 firewalld 0.5.x、conntrack、iproute2、Docker(部分节点)

说明:Ubuntu 18.04 的默认 iptables 为 legacy 后端,firewalld 在这个版本工作稳定。BBR 从 4.9 起支持,4.15 可直接启用。

1.2 业务与端口

模块 协议/端口 说明
Web/API 80/tcp, 443/tcp Nginx 反代、多域名
管理 22/tcp 仅办公出口与堡垒机可访问
业务 TCP 7000-7020/tcp 内部 RPC(跨可用区)
健康检查 9100/tcp, 9090/tcp Exporter/Prometheus

1.3 基线数据(调优前)

数据为当天 3 组可复现实验的中位数,仅供方法论参考。

指标 广州移动 → HK(CMI) 深圳电信 → HK(CN2)
ICMP RTT(ms) 39~45 33~38
TLS 建连 P95(ms) 420 280
1 并发下载(MiB/s) 2.1 4.3
20 并发下载(MiB/s) 6.8 12.5
504/502 比例 0.7% 0.2%

目标:在不改业务架构的前提下,通过 firewalld + 内核/路由策略把稳定性先拉满(降错误率、控突发),再把有效吞吐拉起来(降低握手重试与 PMTU 相关的损耗),最终让华南用户的 P95 建连与下载速度肉眼可见地提升。

2. 方案设计:把“边界”做聪明

Zone 分层:

  • external:面对公网(eno1/eno2),默认拒绝,仅放行业务端口。
  • trusted:容器网桥/内部回环(docker0、lo、内网 VLAN)。
  • management(自建 zone):只给堡垒机与办公网开放 SSH、Prometheus。

ipset + rich rules:

  • 将允许运维访问与高风险段分别放入 ipset,规则一键引用、易维护。

MSS/PMTU 与 TCP:

  • mangle 链 MSS Clamping,减少跨境链路上 MTU 不一致造成的分片与重传。
  • 启用 BBR、适度 TFO/keepalive、调 somaxconn 与 conntrack。

双上联的策略路由(可选):

  • 按目的网段或SNI/端口特征做 MARK,通过 ip rule 走对应上联(CMI/CN2)。

速率与连接保护:

  • hashlimit/connlimit 阻断异常并发,SYN flood 的速率阈值控制。

Docker 共存:

  • docker0 入 trusted,公网 zone 做 --add-masquerade,避免链冲突。

3. 实操步骤

3.1 准备系统

# 禁用并移除 UFW,避免和 firewalld 抢规则
sudo systemctl stop ufw && sudo systemctl disable ufw
sudo apt purge -y ufw

# 安装 firewalld 与常用工具
sudo apt update
sudo apt install -y firewalld ipset conntrack iproute2

# 启动并开机自启
sudo systemctl enable --now firewalld
sudo firewall-cmd --state   # 预期输出:running

坑 1:如果之前装过 iptables-persistent,它的还原脚本可能在重启时覆盖 firewalld 设定。建议卸载或清空其规则文件。

3.2 Zone 规划与接口绑定

# 新建 management zone
sudo firewall-cmd --permanent --new-zone=management
sudo firewall-cmd --permanent --zone=management --set-target=DROP

# 绑定接口到 zone(根据实际网卡名)
sudo firewall-cmd --permanent --zone=external --add-interface=eno1
sudo firewall-cmd --permanent --zone=external --add-interface=eno2
sudo firewall-cmd --permanent --zone=trusted  --add-interface=docker0

# 设置默认 zone 为 external(更安全的默认拒绝)
sudo firewall-cmd --set-default-zone=external

# 放行业务端口(external)
sudo firewall-cmd --permanent --zone=external --add-service=http
sudo firewall-cmd --permanent --zone=external --add-service=https
sudo firewall-cmd --permanent --zone=external --add-port=7000-7020/tcp

# 管理面(management)仅允 SSH 与监控
sudo firewall-cmd --permanent --zone=management --add-service=ssh
sudo firewall-cmd --permanent --zone=management --add-port=9090/tcp
sudo firewall-cmd --permanent --zone=management --add-port=9100/tcp

# 允许来自办公出口与堡垒机的管理访问(示例网段)
sudo firewall-cmd --permanent --zone=management \
  --add-source=203.0.113.0/24
sudo firewall-cmd --permanent --zone=management \
  --add-source=198.51.100.10/32

# 公网 SNAT/容器出口
sudo firewall-cmd --permanent --zone=external --add-masquerade

sudo firewall-cmd --reload
sudo firewall-cmd --get-active-zones

小技巧:用 --add-source 把可信来源“拉进”到更高权限的 zone,比在 external 中逐项放行更直观。

3.3 ipset 与 rich rules(白/黑名单)

# 允许的管理来源(白名单)
sudo firewall-cmd --permanent --new-ipset mgmt_allow --type=hash:ip
sudo firewall-cmd --permanent --ipset=mgmt_allow --add-entry=203.0.113.0/24
sudo firewall-cmd --permanent --ipset=mgmt_allow --add-entry=198.51.100.10

# 高风险段(示例)
sudo firewall-cmd --permanent --new-ipset risk_drop --type=hash:net
sudo firewall-cmd --permanent --ipset=risk_drop --add-entry=45.155.0.0/16

# 使用 rich rules 引用 ipset
sudo firewall-cmd --permanent --add-rich-rule='rule source ipset=risk_drop drop'
sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source ipset=mgmt_allow service name=ssh accept'

sudo firewall-cmd --reload

批量导入国家网段:

  • 可从 IP 区段公开源下载(如 *.zone),批量写入 ipset 后用 rich-rule 引用;注意 每日差异更新,避免规则膨胀。示例导入(思路):
while read ip; do
  sudo firewall-cmd --permanent --ipset=risk_drop --add-entry=$ip
done < cn.zone
sudo firewall-cmd --reload

3.4 传输层优化(BBR、TFO、连接跟踪等)

# 启用 BBR、TCP Fast Open(Server),优化 listen/backlog
cat <<'EOF' | sudo tee /etc/sysctl.d/99-crossborder.conf
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
net.ipv4.tcp_fastopen=3
net.core.somaxconn=4096
net.ipv4.tcp_max_syn_backlog=4096
net.ipv4.ip_local_port_range=10240 60999
net.netfilter.nf_conntrack_max=1048576
net.netfilter.nf_conntrack_tcp_timeout_established=1200
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_fin_timeout=15
EOF
sudo sysctl --system

坑 2:tcp_fastopen 需要应用层(如 Nginx)也开启 fastopen 才能显效;此外个别中间设备会对 TFO 不友好,如异常可先关掉验证。

3.5 MSS Clamping(修复跨境 PMTU 问题)

跨境链路经常存在 MTU 低于 1500 的段(如 1460/1492),容易触发分片与重传。我们通过 direct 规则 在 mangle 表对 SYN 做 MSS 自动钳制:

# 对本机对外连接
sudo firewall-cmd --permanent --direct --add-rule ipv4 mangle OUTPUT 0 \
  -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

# 对转发流量(如作为网关时)
sudo firewall-cmd --permanent --direct --add-rule ipv4 mangle FORWARD 0 \
  -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

sudo firewall-cmd --reload

坑 3:有的教程把规则加在 POSTROUTING,但对入站连接不生效;放在 FORWARD/OUTPUT 更稳。使用 0 优先级确保位于链首。

3.6 SYN flood/异常并发保护(hashlimit/connlimit)

# SSH 并发上限(超过直接复位)
sudo firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 \
  -p tcp --dport 22 -m connlimit --connlimit-above 5 -j REJECT --reject-with tcp-reset

# 针对 443 的 SYN 速率限制(每源 50/s,突发 200)
sudo firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 1 \
  -p tcp --dport 443 -m state --state NEW -m hashlimit \
  --hashlimit-name https_syn --hashlimit-mode srcip --hashlimit-upto 50/second \
  --hashlimit-burst 200 -j ACCEPT
# 超出直接丢弃
sudo firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 2 \
  -p tcp --dport 443 -m state --state NEW -j DROP

sudo firewall-cmd --reload

说明:firewalld 的 rich 语言对“速率限制”主要用于日志;精细限速建议走 direct 规则,调用 iptables 匹配扩展更可靠。

3.7(可选)双上联策略路由:按目的地走“对的线”

场景:eno1 走 CMI(对移动友好),eno2 走 CN2(对电信友好)。按目的网段给报文打标记,走不同路由表:

# 1) 为不同上联建独立路由表(/etc/iproute2/rt_tables)
echo "100 cmi" | sudo tee -a /etc/iproute2/rt_tables
echo "200 cn2" | sudo tee -a /etc/iproute2/rt_tables

# 2) 各自默认路由(按实际网关)
sudo ip route add default via 10.0.0.1 dev eno1 table cmi
sudo ip route add default via 10.0.1.1 dev eno2 table cn2

# 3) 打标 + 策略规则
#   - 目的为 223.120.0.0/14(示例,移动常见归属)走 CMI
#   - 目的为 101.0.0.0/8(示例,电信常见段)走 CN2

# mangle OUTPUT 标记(本机发起)
sudo firewall-cmd --permanent --direct --add-rule ipv4 mangle OUTPUT 0 \
  -d 223.120.0.0/14 -j MARK --set-mark 0x64
sudo firewall-cmd --permanent --direct --add-rule ipv4 mangle OUTPUT 1 \
  -d 101.0.0.0/8 -j MARK --set-mark 0xc8

# 应用策略路由
sudo ip rule add fwmark 0x64 table cmi
sudo ip rule add fwmark 0xc8 table cn2

sudo firewall-cmd --reload

坑 4:策略路由容易产生出入向不对称。务必在对应 egress zone 开启 MASQUERADE 或在边界路由器上处理 SNAT,保持回程可达。

3.8 端口转发与健康检查

# 将外部 443 转发到内网 10.0.10.10:443(四层直转)
sudo firewall-cmd --permanent --zone=external \
  --add-forward-port=port=443:proto=tcp:toaddr=10.0.10.10:toport=443

# 放行健康检查到 exporter
sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 \
  source address=198.51.100.200/32 port port=9100 protocol=tcp accept'

sudo firewall-cmd --reload

4. 验证与观测

4.1 快速体检命令

firewall-cmd --list-all --zone=external
firewall-cmd --list-rich-rules
sudo conntrack -S
ss -s
ip rule show; ip route show table cmi; ip route show table cn2
sudo tcpdump -ni eno1 tcp[tcpflags] & 0x02 != 0 -c 50  # 观察 SYN

4.2 优化后数据(同样 3 组中位数)

指标 广州移动 → HK(CMI) 深圳电信 → HK(CN2)
ICMP RTT(ms) 39~45(无变化) 33~38(无变化)
TLS 建连 P95(ms) 310(-110) 220(-60)
1 并发下载(MiB/s) 3.3(+57%) 5.6(+30%)
20 并发下载(MiB/s) 10.2(+50%) 15.8(+26%)
504/502 比例 0.18% 0.08%

这些提升来自 无效重试与重传的减少(MSS/BBR/conntrack),以及把有效流量送上更匹配的回国线(策略路由)。

5. 与 Docker 的和平相处

Docker 会改 iptables,常见的两个点:

把 docker0 加入 trusted 并允许 SNAT(前文已做)。

在 external zone 打开 相关/已建立连接即可;若有复杂转发,优先用 firewalld 的 forward-port,避免和 Docker 自建 NAT 乱序。

# 允许既有连接与 ICMP(默认有,确认)
sudo firewall-cmd --permanent --zone=external --add-service=ssh
sudo firewall-cmd --permanent --zone=external --add-icmp-block-inversion=no
sudo firewall-cmd --reload

坑 5:firewalld --reload 不会丢失 --permanent 的 direct 规则,但只写了运行态的 direct 规则会丢;务必加 --permanent 再 reload。

6. 运维常用“回滚按钮”

出问题时先保命:

# 暂时放宽(时间窗内操作完再收紧)
sudo firewall-cmd --zone=external --add-service=ssh
sudo firewall-cmd --zone=external --add-port=443/tcp

# 完整重载(同步磁盘配置)
sudo firewall-cmd --complete-reload

# 彻底停用 firewalld(慎用,建议有带外/KVM)
sudo systemctl stop firewalld

我会在 /root/ 留一份最小可用的 iptables-restore 文本,紧急时一键恢复最小白名单与 443 放行,避免把自己锁在门外。

7. FAQ 与排障手记

握手还是慢?

看 tcpdump 是否有 Frag needed but DF set(PMTU 黑洞),若有,确认 MSS Clamping 是否生效、优先级是否在链首。

BBR 不生效?

sysctl net.ipv4.tcp_congestion_control 应为 bbr;若是容器内监听,宿主侧 BBR 仍生效,但应用层限速/反向代理配置也会影响。

策略路由无效?

检查 MARK 是否命中(iptables -t mangle -S | grep MARK),以及 ip rule 顺序(策略规则按序匹配)。

连接耗尽?

查看 conntrack -S,适度提升 nf_conntrack_max,并用 hashlimit/connlimit 削峰。

DSCP 标记有用吗?

跨境多数运营商会清零 DSCP,不保证生效,生产中不以此为核心手段。

8. 一次性部署脚本(节选)

供参考,建议按需拆分成 Ansible 角色或 cloud-init。

#!/usr/bin/env bash
set -euo pipefail

apt update && apt install -y firewalld ipset conntrack iproute2

systemctl enable --now firewalld

firewall-cmd --permanent --new-zone=management
firewall-cmd --permanent --zone=management --set-target=DROP

firewall-cmd --permanent --zone=external --add-interface=eno1
firewall-cmd --permanent --zone=external --add-interface=eno2
firewall-cmd --permanent --zone=trusted  --add-interface=docker0
firewall-cmd --set-default-zone=external

for svc in http https; do
  firewall-cmd --permanent --zone=external --add-service=$svc
done
firewall-cmd --permanent --zone=external --add-port=7000-7020/tcp
firewall-cmd --permanent --zone=external --add-masquerade

firewall-cmd --permanent --zone=management --add-service=ssh
firewall-cmd --permanent --zone=management --add-port=9090/tcp
firewall-cmd --permanent --zone=management --add-port=9100/tcp
firewall-cmd --permanent --zone=management --add-source=203.0.113.0/24
firewall-cmd --permanent --zone=management --add-source=198.51.100.10/32

firewall-cmd --permanent --new-ipset mgmt_allow --type=hash:ip
firewall-cmd --permanent --ipset=mgmt_allow --add-entry=203.0.113.0/24
firewall-cmd --permanent --ipset=mgmt_allow --add-entry=198.51.100.10
firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source ipset=mgmt_allow service name=ssh accept'

firewall-cmd --permanent --direct --add-rule ipv4 mangle OUTPUT 0 \
  -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
firewall-cmd --permanent --direct --add-rule ipv4 mangle FORWARD 0 \
  -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 \
  -p tcp --dport 22 -m connlimit --connlimit-above 5 -j REJECT --reject-with tcp-reset

sysctl -w net.core.default_qdisc=fq
sysctl -w net.ipv4.tcp_congestion_control=bbr
sysctl -w net.ipv4.tcp_fastopen=3
sysctl -w net.core.somaxconn=4096
sysctl -w net.ipv4.tcp_max_syn_backlog=4096
sysctl -w net.netfilter.nf_conntrack_max=1048576
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=1200

firewall-cmd --reload

9. 清晨 6:20 的那条消息

天色发白时,Prometheus 的告警板从橙色褪成了绿色。广州移动侧的 P95 TLS 建连压到了 300ms 出头,API 错误率掉到千分之二以下。业务负责人在群里丢来一句:“这次真稳住了。”

我把那晚做的每一步都记在变更单里:不是为了证明“firewalld 能让网络变快”,而是要证明把边界做聪明,有效流量自然就快了——这在跨境场景尤其成立。

10. 清单复核(给未来的我/你)

  •  UFW 已禁用,firewalld 运行且为唯一规则管理者
  •  Zone/接口/源地址划分清晰,默认拒绝,显式放行
  •  ipset 管理白/黑名单,差异更新可自动化
  •  BBR/TFO/conntrack/sysctl 生效且观测指标正常
  •  MSS Clamping 在 OUTPUT/FORWARD 生效,确认优先级
  •  (可选)策略路由出入向对称,回程可达
  •  Docker 与 firewalld 规则边界明确,避免链冲突
  •  预案:最小可用规则与紧急回滚脚本随时可用

如果你也在香港机房扛着“跨境访问慢”的锅,以上流程基本可以复用。先让边界会思考,再让链路去奔跑——这是那夜留给我的最朴素的经验。

目录结构
全文