搬瓦工 VPS 遭遇 DDoS 攻击深度排障与自救手册完整版

搬瓦工VPS遭遇DDoS攻击时会触发空路由机制,系统自动屏蔽IP达1800秒(30分钟),表现为全网失联且流量图表出现尖峰后断崖式归零。自救核心方案包括:立即接入Cloudflare代理模式隐藏真实IP,启用攻击模式及WAF规则过滤恶意流量;部署自动脚本(Bash或Go版)监测流量,当入站超50MB/s且出站低于入站40%时,连续确认3次后自动断网300秒实施黑洞防御;长期应通过快照功能迁移至新IP并建立双机备份体系,结合香港CN2 GIA等高防线路降低停机风险。
Ping通的情况,需要结合实际运维经验,深入剖析 DDoS 攻击下的空路由(Nullrouted)触发机制,并建立一套从精准判定到彻底自救的实战方案。

一、 为什么我的搬瓦工服务器会突然“消失”?

搬瓦工绝大多数套餐方案在设计上更偏向于提供高性能的底层架构,而非自带硬件级 DDoS 防御。这意味着当特定 IP 遭遇大规模恶意请求时,机房会采取自动化保护措施以确保整体链路的稳定。

  • 空路由(Nullrouted)机制:当流量超过阈值,系统会将指向该 IP 的所有数据包丢弃,形成所谓的“黑洞”。此时网站无法打开、SSH无法登陆、Ping测试也会完全失效。
  • 1800 秒封禁周期:触发空路由后,默认的屏蔽时长通常为1800 秒(30 分钟)。如果封禁解除后攻击仍在继续,屏蔽时间会循环延长,导致服务器反复失联。

二、 如何确认自己的服务器正处于 DDoS 攻击中?

在排查网络故障时,首先需要区分是软件配置错误还是受到了流量攻击。通过以下数据特征可以快速锁定故障性质。

1. 查看系统邮件通知当 IP 触发空路由时,系统会自动向注册邮箱发送一封包含is currently under a (D)DoS attack的邮件,明确告知 IP 已被暂时屏蔽。

2. 分析流量特征曲线

在排查过程中,通过图形化的数据回馈能最直观地捕捉攻击痕迹。相比于命令行,KiwiVM 后台的统计图表能更清晰地展现出入站流量的异常脉络。

  • 进入路径:登录KiwiVM管理后台,在左侧Security & Records栏目下点击Detailed statistics页面。
  • 观察指标:在右侧详情页中,重点观察Network I/O (Bits per second)图表。
  • 黑洞特征判定:
  • 流量尖峰:如果图表中出现如绿色阴影所示的垂直状极高尖峰,说明该时段遭受了大规模入站流量冲击。
  • 断崖式归零:在尖峰之后,如果流量瞬间掉落并呈水平直线(接近0 bps)持续延伸,说明IP已被系统自动放入黑洞(空路由)进行清洗。
    通过Detailed statistics中的流量断层判定IP是否被封禁3. 状态矛盾核对如果控制面板显示主机状态为 Running 且未执行 重装系统 或主动关闭服务,但外部一切连接手段均失效,基本可以判定为遭受了 DDoS 攻击。

三、 应急方案:利用 Cloudflare 建立前端防线

由于搬瓦工普通套餐无法提供高防线路,利用Cloudflare的全球节点接住流量是目前成本最低且效果最好的自救方式。

1. 接入与隐藏逻辑

通过将域名DNS托管至Cloudflare并点亮橙色云朵图标(代理模式),访客的请求会先打到防护节点而非搬瓦工源站。这种方式能有效隐藏真实 IP,屏蔽掉大量的扫描与流量攻击。

2. 防护策略加固

  • 开启攻击模式:在攻击期间开启Under Attack Mode,强制访客进行 5 秒安全验证。
  • 防火墙规则 (WAF):在后台针对异常频率的请求或特定国家/地区设置拦截规则。
  • 优化缓存设置:适当提高静态资源的缓存比例,减少回源请求,减轻服务器的CPU与网络压力。

四、 利用快照功能实现数据迁移与 IP 更换

如果攻击方持续对特定 IP 进行攻击,即使部署了Cloudflare,旧 IP 一旦解封仍可能被再次打进黑洞。此时,利用快照功能进行业务迁移是更为彻底的办法。

数据迁移与环境恢复流程:

  • 制作快照:在 KiwiVM 界面进入Snapshots页面,为当前受攻击的云服务器做一个全量 备份。
  • 快照还原与迁移:利用搬瓦工的快照功能,可以新建一台同设置的 VPS 并还原该镜像。或者通过面板功能进行更换机房来获取全新的 IP 地址。
  • 解析同步更新:在获取新 IP 后,只需在Cloudflare后台修改A 记录,新 IP 会在几秒钟内生效,从而切断旧 IP 的受攻击链路。

五、遇DDoS自动断开网卡5分钟

检测DDoS就自动断网5分钟

如果你的VPS只入 不出的话..那么这个脚本就不适合你了

可修改的参数

1.触发检查的起步阈值 (MB/s) 这个可以填写你的最大带宽 注意单位是MB

TRIGGER_LIMIT_MB=50

2.出站流量比例因子 (0.0 – 1.0)

如果流出的流量比进入的流量*设置的值(默认是0.4)就认为发生了ddos

如果你的服务器只入 不出的话..那么这个脚本就不适合你了

如果 (出站 TX) < (入站 RX * 因子),则判定为攻击。

SAFE_RATIO=0.4

3. 连续确认次数 防止误报

MAX_RETRIES=3

4. 检查间隔 (秒)

CHECK_INTERVAL=2

5. 黑洞时长 (秒) – 300秒 = 5分钟 断网时长..

BLACKHOLE_TIME=300

6. 安全模式 (true=只报警不操作, false=执行断网)

SAFE_MODE=false

7. 日志显示阈值 (MB/s) 只有高过这个阈值才有显示出来的文本 就是 一些流入和 流出 数据计算的值

LOG_LIMIT_MB=5

Bash脚本版本
搬瓦工的CN2 GIA线路到底有多快?

#!/bin/bash

# ================= 用户配置区域 =================

# 1. 触发检查的起步阈值 (MB/s)
TRIGGER_LIMIT_MB=50

# 2. 出站流量比例因子 (0.0 - 1.0)
# 如果 (出站 TX) < (入站 RX * 因子),则判定为攻击。
SAFE_RATIO=0.4

# 3. 连续确认次数
MAX_RETRIES=3

# 4. 检查间隔 (秒)
CHECK_INTERVAL=2

# 5. 黑洞时长 (秒) - 300秒 = 5分钟
BLACKHOLE_TIME=300

# 6. 安全模式 (true=只报警不操作, false=执行断网)
SAFE_MODE=false

# 7. 日志显示阈值 (MB/s)
LOG_LIMIT_MB=5

# ===============================================

# 自动获取默认网卡
IFACE=$(ip route get 8.8.8.8 | awk '{print $5; exit}')
OVERLOAD_COUNT=0

# 颜色定义
RED='33[0;31m'
GREEN='33[0;32m'
YELLOW='33[0;33m'
NC='33[0m'

echo -e "${GREEN}=== 智能流量保镖 v3.0 (黑洞版) 启动 ===${NC}"
echo "监控网卡: $IFACE"
echo "黑洞时长: $BLACKHOLE_TIME 秒"
echo "安全模式: $SAFE_MODE"
echo "========================================"

get_bytes() {
 cat "/sys/class/net/$IFACE/statistics/$1"
}

# 初始化读数
PREV_RX=$(get_bytes "rx_bytes")
PREV_TX=$(get_bytes "tx_bytes")

while true; do
 sleep $CHECK_INTERVAL

 CURR_RX=$(get_bytes "rx_bytes")
 CURR_TX=$(get_bytes "tx_bytes")

 # 使用 awk 计算速度和逻辑
 read RX_MB TX_MB IS_HIGH IS_ATTACK <<< $(awk -v r1=$PREV_RX -v r2=$CURR_RX 
 -v t1=$PREV_TX -v t2=$CURR_TX 
 -v time=$CHECK_INTERVAL 
 -v limit=$TRIGGER_LIMIT_MB 
 -v ratio=$SAFE_RATIO '
 BEGIN {
 delta_rx = r2 - r1
 delta_tx = t2 - t1
 # 防止负数 (重启网卡后可能发生)
 if (delta_rx < 0) delta_rx = 0
 if (delta_tx < 0) delta_tx = 0

 rx_speed = delta_rx / 1024 / 1024 / time
 tx_speed = delta_tx / 1024 / 1024 / time

 is_high = (rx_speed > limit) ? 1 : 0
 limit_tx = rx_speed * ratio
 is_attack = (tx_speed < limit_tx) ? 1 : 0

 printf "%.2f %.2f %d %d", rx_speed, tx_speed, is_high, is_attack
 }')

 # 更新上一轮数据
 PREV_RX=$CURR_RX
 PREV_TX=$CURR_TX

 # 打印日志
 RX_INT=${RX_MB%.*}
 RX_INT=${RX_INT:-0}
 if [ "$RX_INT" -ge "$LOG_LIMIT_MB" ]; then
 echo "[$(date +%T)] RX: $RX_MB MB/s | TX: $TX_MB MB/s"
 fi

 # 核心判断逻辑
 if [ "$IS_HIGH" -eq 1 ] && [ "$IS_ATTACK" -eq 1 ]; then
 ((OVERLOAD_COUNT++))
 echo -e "${RED}[警报 $OVERLOAD_COUNT/$MAX_RETRIES] 流量异常 (RX高 TX低) 疑似攻击!${NC}"

 if [ "$OVERLOAD_COUNT" -ge "$MAX_RETRIES" ]; then
 echo -e "${RED}!!! 确认攻击,触发黑洞防御 !!!${NC}"

 if [ "$SAFE_MODE" = true ]; then
 echo -e "${YELLOW}[测试] 安全模式开启,不执行断网。${NC}"
 OVERLOAD_COUNT=0
 else
 # === 执行黑洞 ===
 echo -e "${RED}正在关闭网卡 [$IFACE]...${NC}"
 ip link set dev "$IFACE" down

 echo -e "${YELLOW}网卡已关闭,进入 $BLACKHOLE_TIME 秒静默期...${NC}"
 sleep "$BLACKHOLE_TIME"

 echo -e "${GREEN}黑洞结束,正在恢复网卡...${NC}"
 ip link set dev "$IFACE" up

 # 等待网络恢复
 sleep 5

 # === 关键:重置状态 ===
 # 网卡重启后计数器会清零,必须重新获取基准值,否则下次计算会出错
 PREV_RX=$(get_bytes "rx_bytes")
 PREV_TX=$(get_bytes "tx_bytes")
 OVERLOAD_COUNT=0
 echo -e "${GREEN}监控已恢复。${NC}"
 fi
 fi
 else
 # 流量正常或恢复
 if [ "$OVERLOAD_COUNT" -gt 0 ]; then
 echo -e "${GREEN}流量特征恢复正常,警报解除。${NC}"
 fi
 OVERLOAD_COUNT=0
 fi
done

bash版本使用

一、 前置要求

  • 权限:必须以Root用户身份运行(脚本需要控制网卡开关)。
  • 依赖:脚本依赖ipawk命令(BandwagonHost 的绝大多数系统已内置,无需额外安装)。
    二、 安装脚本
  • 创建存放目录(推荐)
    mkdir -p /root/scripts

nano /root/scripts/traffic_guard.sh

  • 粘贴代码将上方的脚本完整复制并粘贴进去,按Ctrl+O保存,Ctrl+X退出。
  • 赋予执行权限chmod +x /root/scripts/traffic_guard.sh
    三、 运行方式

方式 A:Systemd 托管运行(推荐,生产环境标准)

这种方式可以实现开机自启,后台静默运行,且脚本意外退出会自动重启。

  • 创建服务文件nano /etc/systemd/system/traffic_guard.service
  • 填入以下内容
[Unit]
Description=BandwagonHost Traffic Guard Service
After=network.target
[Service]
Type=simple
# 确保此处的路径与你实际保存的路径一致
ExecStart=/root/scripts/traffic_guard.sh
Restart=always
User=root

[Install]
WantedBy=multi-user.target

  • 启动并设置开机自启
    #重载配置文件

systemctl daemon-reload

#设置开机自动启动

systemctl enable traffic_guard

#运行此服务

systemctl start traffic_guard

4.查看运行日志

#查看实时日志

journalctl -u traffic_guard -f

方式 B: 临时运行(测试用)

如果你不想配置 Systemd,或者想在 SSH 窗口看着它/root/scripts/traffic_guard.sh

go版本

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os/exec"
	"strconv"
	"strings"
	"time"
)

// ================= 配置区域 =================
const (
	TriggerLimitMB = 50.0 // 入站流量触发阈值 (MB/s)
	SafeRatio = 0.4 // 出站/入站 最小安全比例
	MaxRetries = 3 // 连续确认次数
	CheckInterval = 2 // 检查间隔 (秒)
	BlackholeTime = 300 // 黑洞时长 (秒)
	LogLimitMB = 5.0 // 日志打印阈值
	SafeMode = false // true=仅打印, false=执行操作
)

// ===========================================

var overloadCount = 0

func main() {
	// 自动获取默认网卡
	iface, err := getDefaultInterface()
	if err != nil {
		log.Fatalf("无法获取网卡: %v", err)
	}

	fmt.Printf("=== Go流量保镖启动 | 网卡: %s | 阈值: %.0fMB/s ===n", iface, TriggerLimitMB)

	// 初始化读取
	prevRx, prevTx := getBytes(iface)

	for {
		time.Sleep(time.Duration(CheckInterval) * time.Second)

		currRx, currTx := getBytes(iface)

		// 计算速度 (MB/s)
		rxSpeed := float64(currRx-prevRx) / 1024 / 1024 / float64(CheckInterval)
		txSpeed := float64(currTx-prevTx) / 1024 / 1024 / float64(CheckInterval)

		// 防止负数(网卡重置后可能出现)
		if rxSpeed < 0 { rxSpeed = 0 }
		if txSpeed < 0 { txSpeed = 0 }

		// 更新基准
		prevRx = currRx
		prevTx = currTx

		// 日志输出
		if rxSpeed > LogLimitMB {
			log.Printf("[流量] RX: %.2f MB/s | TX: %.2f MB/sn", rxSpeed, txSpeed)
		}

		// 判断逻辑
		isHighTraffic := rxSpeed > TriggerLimitMB
		isAttackPattern := txSpeed < (rxSpeed * SafeRatio)

		if isHighTraffic && isAttackPattern {
			overloadCount++
			fmt.Printf("33[31m[警报 %d/%d] 异常流量检测! RX: %.2f, TX: %.2f33[0mn", overloadCount, MaxRetries, rxSpeed, txSpeed)

			if overloadCount >= MaxRetries {
				triggerBlackhole(iface)
				// 黑洞结束后,重置计数器和基准值
				overloadCount = 0
				prevRx, prevTx = getBytes(iface)
			}
		} else {
			if overloadCount > 0 {
				fmt.Println("33[32m流量恢复正常,警报解除。33[0m")
			}
			overloadCount = 0
		}
	}
}

// 执行黑洞逻辑
func triggerBlackhole(iface string) {
	fmt.Println("33[31m!!! 确认攻击,正在执行黑洞防御 !!!33[0m")

	if SafeMode {
		fmt.Println("[安全模式] 模拟执行:关闭网卡...")
		time.Sleep(2 * time.Second)
		fmt.Println("[安全模式] 模拟执行:开启网卡...")
		return
	}

	// 关闭网卡
	log.Printf("正在关闭网卡 %s ...", iface)
	if err := exec.Command("ip", "link", "set", "dev", iface, "down").Run(); err != nil {
		log.Printf("关闭网卡失败: %v", err)
		return
	}

	log.Printf("网卡已关闭,等待 %d 秒...", BlackholeTime)
	time.Sleep(time.Duration(BlackholeTime) * time.Second)

	// 开启网卡
	log.Printf("正在恢复网卡 %s ...", iface)
	if err := exec.Command("ip", "link", "set", "dev", iface, "up").Run(); err != nil {
		log.Printf("CRITICAL: 恢复网卡失败,请手动处理! Error: %v", err)
		return
	}

	// 给一点时间让网络重新协商
	time.Sleep(5 * time.Second)
	log.Println("网络已恢复,重新开始监控。")
}

// 读取系统文件获取流量字节
func getBytes(iface string) (uint64, uint64) {
	rxPath := fmt.Sprintf("/sys/class/net/%s/statistics/rx_bytes", iface)
	txPath := fmt.Sprintf("/sys/class/net/%s/statistics/tx_bytes", iface)

	rx, _ := readUint64(rxPath)
	tx, _ := readUint64(txPath)
	return rx, tx
}

func readUint64(path string) (uint64, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return 0, err
	}
	return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64)
}

// 简单的获取默认网卡方法
func getDefaultInterface() (string, error) {
	out, err := exec.Command("sh", "-c", "ip route get 8.8.8.8 | awk '{print $5; exit}'").Output()
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(string(out)), nil
}

一、环境准备

在编译运行之前,你需要先在 VPS 上安装 Go 语言环境。Debian / Ubuntu:

apt update && apt install golang -y

CentOS / AlmaLinux:

yum install golang -y

验证安装是否成功:

go version

输出类似 go version go1.x.x linux/amd64 即为成功

二、 编译与安装

  • 创建文件创建一个名为traffic_guard.go的文件,并将上方的代码完整粘贴进去。Bashnano traffic_guard.go(粘贴代码后,按Ctrl+O保存,Ctrl+X退出)
  • **修改配置(可选)**代码顶部的const区域是配置项。- TriggerLimitMB: 触发阈值(默认 50MB/s)。
  • SafeMode: 如果设为true,只会报警不会真断网(适合测试)。
  • 编译生成可执行文件go build -o traffic_guard traffic_guard.go此时你会发现当前目录下多了一个名为traffic_guard的可执行文件。
  • 赋予权限并移动chmod +x traffic_guard mv traffic_guard /root/traffic_guard
    三、运行方式

方式 A:Systemd 托管运行(强烈推荐)

这是最稳健的方式,支持开机自启和进程守护。

  • 创建服务文件nano /etc/systemd/system/traffic_guard.service
  • 填入以下内容
[Unit]
Description=BandwagonHost Traffic Guard (Go Version)
After=network.target

[Service]
Type=simple
# 确保这里的路径是你实际存放二进制文件的路径
ExecStart=/root/traffic_guard
Restart=always
User=root

[Install]
WantedBy=multi-user.target

3.启动并配置开机自启

#重载配置文件

systemctl daemon-reload

#设置开机自动启动

systemctl enable traffic_guard

#运行此服务

systemctl start traffic_guard

4.查看状态与日志

#查看运行状态

systemctl status traffic_guard

#查看实时日志

journalctl -u traffic_guard -f

方式 B:临时测试运行

如果你只是想看看它能不能正常工作:

./traffic_guard

(注意:必须以 Root 身份运行,否则无法控制网卡)

💡常见问题 (FAQ)

  • Q: 编译时报错command not found怎么办?– **A:**说明 Go 环境没装好,请重新执行apt install golang。如果 VPS 系统太老源里没有 Go,建议使用 Bash 版本脚本。
  • Q: 程序报错panic: 无法获取网卡– **A:**程序会自动尝试检测默认网卡。如果检测失败,请检查你的 VPS 是否有特殊的网络配置,或者尝试手动修改代码中的getDefaultInterface函数,直接返回字符串"eth0"
    关键配置说明
  • **怎么测试脚本是否有效?**建议将脚本中的SAFE_MODE=false改为SAFE_MODE=true。 这样当流量超标时,脚本只会输出红色警报文字,而不会真的断网。确认触发逻辑正常后,再改回false
  • **触发黑洞断网后,我会彻底失联吗?**不会。黑洞防御只是暂时关闭网卡,您可以通过以下三种方式恢复:- 途径 1:等待自动恢复耐心等待BLACKHOLE_TIME(默认 300秒/5分钟)结束,脚本会自动重新开启网卡,无需任何操作。
  • 途径 2:通过 KiwiVM VNC 恢复登录 KiwiVM 面板,打开VNC Console(类似于物理显示器,不受网卡关闭影响)。在 VNC 窗口中按Ctrl+C终止脚本,然后输入ip link set dev eth0 up手动恢复网络。
  • 方法 3:重启服务器如果以上方法您都不会步骤,可以直接在 KiwiVM 面板点击ResetForce Stop后再Start重启服务器。重启后网卡会默认恢复连通状态。(注意:这会导致您未保存的数据丢失或服务短暂中断)。

六、 长期预案:建立高可用的 VPS 使用环境

防御 DDoS 攻击是一项长期工作。通过完善的预案体系和日常的加固措施,可以将潜在的停机风险降到最低。

安全预防建议:

  • 双机备份方案:建议准备一台速度快的线路(如 香港CN2 GIA 或 日本东京CN2 GIA)作为直连主力机,同时准备一台便宜的KVM常规套餐作为备份服务器。一旦主力机被黑洞,立即切换解析到备份机并开启Cloudflare防御。
  • 系统加固与监控:日常运维中应当修改SSH端口,定期通过Audit Log观察异常操作,并确保开启了搬瓦工自动备份功能以应对极端情况。
  • 资源合理分配:若业务量增长明显,建议及时升级套餐。如果 IP 已被打残无法解封,可咨询搬瓦工客服关于购买IP的具体事宜或申请 退款。
    注意事项
  • 当 IP 处于空路由状态时,所有的SSH工具(如XshellXftp)均无法连接,请耐心等待 1800 秒解封。
  • 若VPS因 CPU 占用过高被暂停(Suspended),处理流程会有所不同。请务必确认失联原因属于流量攻击而非资源超载。

原创文章,作者:banwagong,如若转载,请注明出处:https://bwgcn2gia.com/archives/283.html

(0)
上一篇 2天前
下一篇 21小时前

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注