搬瓦工 VPS 遭遇 DDoS 攻擊深度排障與自救手冊
更多語言
更多操作
面對搬瓦工 VPS 突然全網失聯且無法 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分鐘
如果你的伺服器只入 不出的話..那麼這個腳本就不適合你了
可修改的參數
# 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腳本版本
#!/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='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[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 用戶身份運行(腳本需要控制網卡開關)。
- 依賴:腳本依賴
ip和awk命令(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/s\n", rxSpeed, txSpeed)
}
// 判断逻辑
isHighTraffic := rxSpeed > TriggerLimitMB
isAttackPattern := txSpeed < (rxSpeed * SafeRatio)
if isHighTraffic && isAttackPattern {
overloadCount++
fmt.Printf("\033[31m[警报 %d/%d] 异常流量检测! RX: %.2f, TX: %.2f\033[0m\n", overloadCount, MaxRetries, rxSpeed, txSpeed)
if overloadCount >= MaxRetries {
triggerBlackhole(iface)
// 黑洞结束后,重置计数器和基准值
overloadCount = 0
prevRx, prevTx = getBytes(iface)
}
} else {
if overloadCount > 0 {
fmt.Println("\033[32m流量恢复正常,警报解除。\033[0m")
}
overloadCount = 0
}
}
}
// 执行黑洞逻辑
func triggerBlackhole(iface string) {
fmt.Println("\033[31m!!! 确认攻击,正在执行黑洞防御 !!!\033[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 版本腳本。
- A: 說明 Go 環境沒裝好,請重新執行
- Q: 程序報錯
panic: 无法获取网卡?- A: 程序會自動嘗試檢測默認網卡。如果檢測失敗,請檢查你的 VPS 是否有特殊的網絡配置,或者嘗試手動修改代碼中的
getDefaultInterface函數,直接返回字符串"eth0"。
- A: 程序會自動嘗試檢測默認網卡。如果檢測失敗,請檢查你的 VPS 是否有特殊的網絡配置,或者嘗試手動修改代碼中的
關鍵配置說明
- 如何測試腳本是否有效? 建議將腳本中的
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 面板點擊 Reset 或 Force Stop 後再 Start 重啟伺服器。重啟後網卡會默認恢復連通狀態。(注意:這會導致您未保存的數據丟失或服務短暫中斷)。
- 方法 1:等待自動恢復 耐心等待
六、 長期預案:建立高可用的 VPS 使用環境
防禦 DDoS 攻擊是一項長期工作。通過完善的預案體系和日常的加固措施,可以將潛在的停機風險降到最低。
安全預防建議:
- 雙機備份方案:建議準備一台速度快的線路(如 香港CN2 GIA 或 日本東京CN2 GIA)作為直連主力機,同時準備一台便宜的KVM常規套餐作為備份伺服器。一旦主力機被黑洞,立即切換解析到備份機並開啟
Cloudflare防禦。 - 系統加固與監控:日常運維中應當修改SSH埠,定期通過
Audit Log觀察異常操作,並確保開啟了搬瓦工自動備份功能以應對極端情況。 - 資源合理分配:若業務量增長明顯,建議及時升級套餐。如果 IP 已被打殘無法解封,可諮詢搬瓦工客服關於購買IP的具體事宜或申請 退款。
注意事項
- 當 IP 處於空路由狀態時,所有的
SSH工具(如Xshell、Xftp)均無法連接,請耐心等待 1800 秒解封。 - 若伺服器因 CPU 占用過高被暫停(Suspended),處理流程會有所不同。請務必確認失聯原因屬於流量攻擊而非資源超載。