线上配置防火墙辅助脚本
前段时间整了个灵车 - 网站后台没有 VNC,甚至连简单的开关机都没有。
即便如此,防火墙还是要配置的,用来限制端口访问等。
用途
因为服务器很灵车,如果防火墙配置有问题造成了不可逆转的错误,则需要一个能自动恢复的机制。
因此,你需要另一台可控的服务器(或类似 pastebin 的服务),通过定期查询最新的指令执行操作。
最简单的方案则是利用 Python 开一个临时服务器:
mkdir -p /tmp/firewall_helper
echo 'clock' > /tmp/firewall_helper/cmd.txt
# 在 ip:8080 提供访问
python3 -m http.server --directory /tmp/firewall_helper 8080
需求:
- 网络无法联通时自动重启当前服务器;
- 若出口正常但是入口被阻挡,可以通过读取服务器指令进行自动重启或其它自定义操作;
脚本本体
#!/bin/bash
# 如果需要调试就取消注释
# set -x
work() {
local ERROR_COUNT=0
local CURL_EXIT=0
local RESP=""
local CMD=""
local PARAM=""
local CMD_URL="${1:-http://example.com/cmd.txt}"
echo "Current user: $(whoami)"
while true; do
RESP="$(curl -sfL "$CMD_URL")"
CURL_EXIT="$?"
printf "resp = %s\n" "$RESP"
if [[ "$CURL_EXIT" -ne 0 ]]; then
echo "ERROR: curl error = ${CURL_EXIT}"
ERROR_COUNT="$((ERROR_COUNT + 1))"
else
# 简易命令解析器。
# 格式为 "指令 参数",参数/指令不能包含空格。
CMD="$(echo -n "$RESP" | cut -d' ' -f1)"
PARAM="$(echo -n "$RESP" | cut -d' ' -f2)"
case "$CMD" in
reboot) reboot || sudo reboot ;;
ping) echo pong ;;
clock) date ;;
hello) printf "hello: %s\n" "$PARAM" ;;
*)
echo "ERROR: unknown command = ${CMD}"
ERROR_COUNT="$((ERROR_COUNT + 1))"
;;
esac
fi
# 连续错误 3 次,可能网络出问题了。
if [[ "$ERROR_COUNT" -ge 3 ]]; then
echo 'network error: reboot'
reboot || sudo reboot
return
fi
echo "Waiting... ERROR_COUNT = ${ERROR_COUNT}"
sleep 5
done
}
work "$@" 2>&1 | tee ./network.log
使用方法
储存上述的脚本本体代码至 firewall_helper.sh
。
将其标记为可执行:
chmod a+x ./firewall_helper.sh
然后执行。注意将参数替换为你自己可控的地址:
./firewall_helper.sh "http://example.com:8080/cmd.txt"
另外开启一个 SSH 连接并连接到服务器,确保:
- 服务器在重启后的状态,能通过 SSH 远程连接。
※ 如果你熟悉 screen
或 tmux
,也可以在服务器使用他们代替使用多个 SSH 连接。
此时可以在新的 SSH 会话进行线上防火墙规则的调整。
使用 nftables 防火墙规则
我使用的是 Debian 服务器上的 nftables
来进行管理。
配置文件是纯文本格式,且可以加入简单的变量来编写一次应用规则,然后在不同的机器上微调变量。
首先随便找个地方定义规则文件,并设置为可执行(chmod a+x rules.nft
):
#!/usr/sbin/nft -f
# 确保该文件不会被系统启动时自动加载。
# 测试成功后手动拷贝到能被系统读取的配置处。
# reset
flush ruleset
# ... rules ...
然后就是重复上述的步骤,直到规则配置满意为止。
后记
因为灵车程度过高,这个脚本反而占据了我大部分的时间… 防火墙规则编写倒是安安稳稳的,在没有把网络搞炸的情况下调试完成了。