博主头像
Kurfuerst

ワクワク

使用 Cloudflare 橙云 与 Fail2Ban 加固服务器防护

背景

前阵子与同学拼了20x codex,通过一台公网服务器的cpa进行共享。今天早上发现token用量异常,一晚上用了50%的weekly quota,显然是受到了攻击。于是紧急使用Cloudflare进行防护。

本文记录一种常见的服务器访问控制方案:部分端口直接公网开放,部分端口必须通过 Cloudflare 橙云代理访问,其余端口全部默认拒绝。同时,使用 Fail2Ban 对 SSH 暴力破解进行动态封禁。

目标

假设域名为:

example.com

服务器需要开放的端口分为三类。

第一类是直接公网开放的端口:

<SSH_PORT>/tcp        SSH 登录端口
<PUBLIC_PORT_A>/tcp   公网业务端口 A
<PUBLIC_PORT_B>/tcp   公网业务端口 B

第二类是只能通过 Cloudflare 访问的端口:

<CF_ONLY_PORT_A>/tcp
<CF_ONLY_PORT_B>/tcp

第三类是所有其他端口:

默认拒绝入站访问

由于Cloudflare默认只能代理常用端口,cpa使用的两个端口不在此列,所以要么使用Cloudflare Tunnel,要么通过Origin Rules进行回源。我选择了后者。

整体原理

整体链路如下:

用户浏览器
→ Cloudflare 橙云代理
→ Cloudflare Origin Rule 改写回源端口
→ 源站服务器指定端口

源站服务器上的防火墙只允许 Cloudflare 的回源 IP 访问 <CF_ONLY_PORT_A><CF_ONLY_PORT_B>。这样即使攻击者知道服务器真实 IP,也无法直接访问这两个端口。

整体防护分层如下:

Cloudflare:
处理公网 Web 入口、代理转发、WAF、速率限制等边缘防护。

UFW:
处理服务器本机端口访问控制。

Fail2Ban:
分析 SSH 登录失败日志,并动态封禁暴力破解来源 IP。

需要注意,Fail2Ban 不是防火墙的替代品。UFW 决定连接能否进入服务器,Fail2Ban 则基于服务日志进行动态封禁。已经被 UFW 默认拒绝的端口,不需要再额外用 Fail2Ban 防护。

Cloudflare DNS 配置

我自己的域名是腾讯云的,所以需要先将这个域名连接到 Cloudflare。

然后在 Cloudflare 中为域名 example.com 添加两条 DNS 记录:

Type: A
Name: service-a
Content: 服务器公网 IP
Proxy status: Proxied / 橙云
TTL: Auto
Type: A
Name: service-b
Content: 服务器公网 IP
Proxy status: Proxied / 橙云
TTL: Auto

最终得到:

service-a.example.com
service-b.example.com

这两条记录必须开启橙云代理。如果使用灰云,DNS 会直接解析到源站 IP,用户会绕过 Cloudflare 直接访问服务器。

Cloudflare Origin Rules 配置

进入 Cloudflare 控制台:

Websites
→ example.com
→ Rules
→ Origin Rules
→ Create rule

创建第一条 Origin Rule。

规则名称:

service-a to origin port A

匹配条件:

http.host eq "service-a.example.com"

Origin 设置:

Destination port: Rewrite to <CF_ONLY_PORT_A>

创建第二条 Origin Rule。

规则名称:

service-b to origin port B

匹配条件:

http.host eq "service-b.example.com"

Origin 设置:

Destination port: Rewrite to <CF_ONLY_PORT_B>

配置完成后,访问链路变为:

用户访问 https://service-a.example.com
→ Cloudflare
→ 回源到 服务器公网IP:<CF_ONLY_PORT_A>

以及:

用户访问 https://service-b.example.com
→ Cloudflare
→ 回源到 服务器公网IP:<CF_ONLY_PORT_B>

UFW 防火墙配置

服务器侧使用 UFW 做端口访问控制。目标是:

允许 <SSH_PORT>/tcp from Anywhere
允许 <PUBLIC_PORT_A>/tcp from Anywhere
允许 <PUBLIC_PORT_B>/tcp from Anywhere
允许 <CF_ONLY_PORT_A>/tcp from Cloudflare IP ranges only
允许 <CF_ONLY_PORT_B>/tcp from Cloudflare IP ranges only
默认拒绝其他所有入站连接

安装 UFW 和 curl:

sudo apt update
sudo apt install -y ufw curl

设置默认策略:

sudo ufw default deny incoming
sudo ufw default allow outgoing

先开放 SSH 端口,避免启用 UFW 后把自己锁在外面:

sudo ufw allow <SSH_PORT>/tcp comment 'SSH'

开放两个公网业务端口:

sudo ufw allow <PUBLIC_PORT_A>/tcp comment 'Public service A'
sudo ufw allow <PUBLIC_PORT_B>/tcp comment 'Public service B'

如果这两个业务端口需要 UDP,再额外添加:

sudo ufw allow <PUBLIC_PORT_A>/udp comment 'Public service A UDP'
sudo ufw allow <PUBLIC_PORT_B>/udp comment 'Public service B UDP'

然后只允许 Cloudflare IP 段访问两个受保护端口:

for port in <CF_ONLY_PORT_A> <CF_ONLY_PORT_B>; do
  curl -fsS https://www.cloudflare.com/ips-v4 | while read ip; do
    sudo ufw allow from "$ip" to any port "$port" proto tcp comment "Cloudflare to $port"
  done

  curl -fsS https://www.cloudflare.com/ips-v6 | while read ip; do
    sudo ufw allow from "$ip" to any port "$port" proto tcp comment "Cloudflare to $port"
  done
done

启用并查看 UFW 状态:

sudo ufw enable
sudo ufw reload
sudo ufw status verbose

如果之前错误地将受保护端口开放给所有来源,需要删除对应规则:

sudo ufw status numbered

如果看到类似:

<CF_ONLY_PORT_A>/tcp ALLOW Anywhere
<CF_ONLY_PORT_B>/tcp ALLOW Anywhere

按编号删除:

sudo ufw delete <规则编号>

Fail2Ban 配置

Fail2Ban 用于动态封禁异常来源 IP。本场景中,使用 Fail2Ban 保护 SSH 端口。

安装 Fail2Ban:

sudo apt update
sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban

创建 SSH jail 配置:

sudo nano /etc/fail2ban/jail.d/sshd.local

写入:

[sshd]
enabled = true
port = <SSH_PORT>
filter = sshd
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1h
banaction = ufw

重启 Fail2Ban:

sudo systemctl restart fail2ban

查看状态:

sudo fail2ban-client status
sudo fail2ban-client status sshd

配置含义如下:

maxretry = 5     允许失败 5 次
findtime = 10m   统计窗口为 10 分钟
bantime = 1h     封禁 1 小时
banaction = ufw  使用 UFW 执行封禁

如果有固定公网 IP,可以加白自己的 IP,减少误封风险:

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 <YOUR_FIXED_IP>
bantime = 1h
findtime = 10m
maxretry = 5

[sshd]
enabled = true
port = <SSH_PORT>
filter = sshd
backend = systemd
banaction = ufw

保存后重启:

sudo systemctl restart fail2ban

验证方法

测试公网开放端口:

nc -vz 服务器公网IP <SSH_PORT>
nc -vz 服务器公网IP <PUBLIC_PORT_A>
nc -vz 服务器公网IP <PUBLIC_PORT_B>

这些端口应该可以连接。

测试受保护端口:

nc -vz 服务器公网IP <CF_ONLY_PORT_A>
nc -vz 服务器公网IP <CF_ONLY_PORT_B>

从普通公网机器直接访问应失败。

测试 Cloudflare 域名访问:

curl -I https://service-a.example.com
curl -I https://service-b.example.com

正常情况下,请求应经过 Cloudflare,并成功回源到对应端口。

查看 Fail2Ban 状态:

sudo fail2ban-client status sshd

查看 UFW 状态:

sudo ufw status verbose
使用 Cloudflare 橙云 与 Fail2Ban 加固服务器防护
http://blog.kurfuerst.online/index.php/archives/49/
本文作者 Großer Kurfürst
发布时间 2026-07-06
许可协议 CC BY-NC-SA 4.0
发表新评论