用一份规则文件,管理 Debian/Ubuntu 上的公网入口防火墙
最近把自己 VPS 上分散的公网端口访问控制收了一遍,目标很明确:
- 只接管外部入口
- 不碰 Docker 内部通信
- 不碰容器之间互访
- 不依赖某个特定项目结构
- 能在 Debian / Ubuntu 上重复使用
最后收出来的方案很简单:
仓库页面:
脚本源码页:
模板配置源码页:
适合 wget / curl 的 raw 地址:
- https://raw.githubusercontent.com/jacinli/sky-guardwall/main/scripts/firewall/firewall-apply.sh
- https://raw.githubusercontent.com/jacinli/sky-guardwall/main/scripts/firewall/rules.conf.example
比如别人可以直接这样下:
wget https://raw.githubusercontent.com/jacinli/sky-guardwall/main/scripts/firewall/firewall-apply.sh wget https://raw.githubusercontent.com/jacinli/sky-guardwall/main/scripts/firewall/rules.conf.example
- 一份
rules.conf - 一个执行脚本
firewall-apply.sh - 脚本自己生成并安装 systemd 服务,负责开机自动恢复
这套东西不是去“重写防火墙”,而是把常见 VPS 场景里真正需要的入口控制抽出来,用更容易维护的方式落地。
为什么要做这件事#
很多机器一开始只是跑几个服务,后面慢慢会变成这样:
nginx暴露80/443- 某些后台服务直接映射到公网
- Docker 容器通过
ports:把端口开出来 - 数据库、面板、调试端口偶尔也直接挂在宿主机上
时间一长,很容易出现两个问题:
- 端口到底谁对外开放,自己也记不清
- 改规则时容易误伤内部链路
尤其是 Docker 环境里,很多人第一反应是直接在 INPUT 链上做限制,但 Docker 暴露端口并不总是走 INPUT。如果不理解流量路径,很容易出现“规则写了,但没拦住”或者“把容器互访也一起拦了”的情况。
所以这套方案的核心原则是:
- 宿主机入口管宿主机入口
- Docker 暴露端口管 Docker 暴露端口
- 内部通信默认不碰
设计目标#
我想要的不是一套巨大的安全平台,而是一套足够稳定、足够清楚、足够好迁移的规则模型。
最终保留了 3 个配置区块:
[global]
[public]
[inbound]
分别表示:
global- 全局白名单来源
- 命中后所有端口都允许
public- 对所有来源公开的端口
inbound- 特定端口白名单
- 比如某个后台端口只允许固定 IP 访问
这种模型有几个好处:
- 维护时不用每次都去想链顺序
- 看配置就知道现在的开放面
- 迁移到别的机器时,只需要换一份规则文件
最重要的一点:只管外部入口,不碰内网通信#
这个方案里最关键的约束,不是“怎么写规则”,而是“哪些流量不应该被这套规则接管”。
我最后明确保留了这条边界:
- 只接管外部进来的访问
- 不主动拦截 Docker bridge 内部流量
- 不把容器之间的调用当成公网访问处理
这是为了避免这类问题:
web -> apiapi -> postgresapi -> redis
这些本来都属于内部依赖,如果和公网入口规则混在一起,系统一复杂就很容易把正常业务链路打断。
所以脚本在处理 Docker 暴露端口时,会优先放过常见 Docker bridge 入口,再对外部访问做限制。这样既能管公网入口,又不会把内部服务调用一起误杀。
为什么脚本里还要带 systemd 安装逻辑#
很多人第一次写 iptables 时,规则加上之后觉得已经结束了。其实还差一步:
- 规则通常只是在当前运行时内核里生效
- 机器重启后,不一定会自动回来
所以这套方案会在执行脚本时,顺手把一个非常轻量的 systemd 服务安装到系统里:
- 开机后自动执行一次
firewall-apply.sh
这样做的意义很直接:
- 规则文件是唯一真实来源
- 脚本负责把规则下发到系统
- 脚本自己把 systemd 服务写到系统里
- systemd 负责在重启后恢复状态
这样你就不用再单独维护一个 service 文件,还是只需要关心:
rules.conffirewall-apply.sh
正常使用时,你不需要专门记住:
bash /root/firewall/firewall-apply.sh --install-service
因为你每次执行:
bash /root/firewall/firewall-apply.sh
脚本都会顺手确保 systemd 服务存在并已启用。
现在这套方案适合什么场景#
它适合这样的机器:
- Debian / Ubuntu VPS
- 有 Docker,也可能没有 Docker
- 有 IPv4,也可能有 IPv6
- 想把公网入口规则统一起来
- 不想把系统搞成一个很重的安全平台
它不试图解决所有问题,比如:
- 出站流量控制
- K8s 深层网络策略
- 流量审计平台
- 行为分析和风控
但如果目标只是:
- 哪些端口公开
- 哪些端口只给指定来源访问
- 哪些来源全通
- 重启后还能恢复
那这套东西已经够用了。
我对这类脚本的判断#
很多时候,不需要一上来做一个复杂面板。
先把规则模型收干净,先把边界想清楚,先保证:
- 可读
- 可重复应用
- 不误伤内部通信
- 能跨机器迁移
这比“功能很多”重要得多。
真正稳定的方案,往往不是最复杂的那个,而是你过两个月回来还能一眼看懂、还能放心继续改的那个。
评论
还没有评论,来发第一个吧