从零打造 1G 内存 VPS 上的商业级 WAF:NPM + CrowdSec + Telegram 移动运维中心全栈实战

图片[1]-从零搭建 NPM + CrowdSec 极简 WAF:1G 内存 VPS 上的低功耗商业级防御与 Telegram 随身运维中心

一、 系统架构与性能账本:为什么选择这套组合?

1.1 1GB 内存硬件账本

组件 / 进程物理内存占用作用与定位
Linux 系统内核 + Docker 守护进程约 180MB ~ 250MB操作系统基础底噪
NPM (Nginx + Node.js 核心)约 150MB ~ 220MB图形化反向代理、SSL 证书自动续签
CrowdSec 核心守护进程 (Go 语言)约 50MB ~ 80MB高性能日志入侵检测、决策下发
nftables 防火墙阻断器 (Bouncer)约 15MB ~ 30MB底层内核级丢弃恶意数据包 (DROP)
Telegram Sentinel 机器人 (Python)约 14MB ~ 18MB移动端交互控制台(纯标准库)
系统剩余缓冲内存 (Available RAM)约 400MB ~ 500MB安全冗余,绝不触发 OOM 崩溃

1.2 整体防御架构图

外部流量 (HTTP/HTTPS)
    │
    ▼
┌────────────────────────────────────────────────────────┐
│ Linux 宿主机网络栈 (nftables 防火墙)                     │
│  ├─ [CAPI 云端 2万黑名单 IP] ──► 内核直接 DROP (零开销) │
│  ├─ [本地决策黑名单 IP]    ──► 内核直接 DROP (连接超时)  │
│  └─ [正常访客流量]         ──► 本地端口 (80/443, host)   │
└──────────────────────┬─────────────────────────────────┘
                       │
                       ▼
┌────────────────────────────────────────────────────────┐
│ NPM 容器 (Nginx Proxy Manager)                         │
│  ├─ SSL 证书卸载与业务转发 ──► 后端站点 / 业务容器      │
│  └─ 流式输出访问日志       ──► /home/docker/npm/data/logs/*│
└──────────────────────┬─────────────────────────────────┘
                       │ (毫秒级文件轮询监听)
                       ▼
┌────────────────────────────────────────────────────────┐
│ CrowdSec 守护进程 (检测大脑)                           │
│  ├─ 规则集匹配 (CVE / 嗅探 / 0容忍瞬发触发器)           │
│  ├─ 阻断决策下发 ──► 注入宿主机 nftables 集合           │
│  ├─ 威胁情报上报 ──► CrowdSec 云端大屏 (0MB 本地开销)   │
│  └─ SQLite 数据库 ──► 毫秒级提供本地取证报文             │
└──────────────────────┬─────────────────────────────────┘
                       │
                       ▼
┌────────────────────────────────────────────────────────┐
│ Telegram 威胁情报中心 3.0 (口袋 SOC)                    │
│  ├─ 3×3 九宫格大屏 (系统大屏 / 攻击态势 / 最新拦截)    │
│  ├─ 深度威胁分析 (Top 10 黑客榜单 / Top 10 漏洞靶心)  │
│  ├─ 刑侦级报文穿透 (调阅原始 HTTP 请求、URL 与指纹 UA) │
│  └─ 交互式处置卡片 (手机端 1 键误杀解封 / 1 键永久加白) │
└────────────────────────────────────────────────────────┘

二、 第一阶段:Nginx Proxy Manager 规范化部署

2.1 准备目录结构

登录 VPS(推荐 Ubuntu 22.04/24.04 或 Debian 11/12),创建专属部署目录:

sudo mkdir -p /home/docker/npm/data
sudo mkdir -p /home/docker/npm/letsencrypt
cd /home/docker/npm

2.2 编写 docker-compose.yml(关键避坑:Host 网络模式)

⚠️ 致命避坑点:若使用默认 Bridge 桥接模式映射端口(如 - 80:80),Docker 底层的 docker-proxy 与 DNAT 会在数据包进入宿主机防火墙 INPUT 链之前就强行截胡转发,导致 CrowdSec 注入宿主机的防火墙黑名单被直接绕过!反向代理必须采用 network_mode: host!

创建 docker-compose.yml:

sudo cat << 'EOF' > /home/docker/npm/docker-compose.yml
services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: npm
    restart: unless-stopped
    # 核心:使用 host 网络模式,彻底杜绝防火墙被绕过并保留真实客户端真实 IP
    network_mode: host
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    environment:
      - DISABLE_IPV6=false
EOF

启动 NPM:docker compose up -d

启动完成后,通过浏览器访问 http://<服务器IP>:81 进入后台(默认账号:admin@example.com,密码:changeme),根据引导修改管理员邮箱与强密码,配置好反向代理域名与 SSL 证书。

三、 第二阶段:CrowdSec 引擎与底层防火墙阻断器安装

我们将 CrowdSec 和防火墙阻断器直接原生安装在宿主机上,最直接、最高效地接管 Linux 内核级防火墙。

3.1 安装 CrowdSec 核心引擎

# 导入官方源脚本
curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash

# 安装 crowdsec
sudo apt-get update
sudo apt-get install -y crowdsec

3.2 安装 nftables 防火墙阻断器 (Bouncer)

sudo apt-get install -y crowdsec-firewall-bouncer-nftables

# 检查服务状态
sudo systemctl status crowdsec-firewall-bouncer --no-pager

看到 active (running) 说明防火墙“打手”已经就位!

3.3 对接 NPM 日志采集(通配符与官方 Parser 关键点)

NPM 会为每个 Proxy Host 独立生成日志(例如 proxy-host-7_access.log)。我们需要让 CrowdSec 动态监控整个日志目录。

⚠️ 血泪避坑点:采集标签绝不能随性自定义为 type: npm-custom!
CrowdSec 官方针对 NPM 特殊日志格式(IP 包裹在 [Client x.x.x.x])的解析器严格依据 type: nginx-proxy-manager 进行路由匹配。若写错标签,日志会在解析流水线第 1 步被 100% 静默丢弃,导致后续规则永远无法触发!

编辑日志采集配置:

sudo cat << 'EOF' > /etc/crowdsec/acquis.yaml
filenames:
  - /home/docker/npm/data/logs/*_access.log
  - /home/docker/npm/data/logs/default-host_access.log
  - /home/docker/npm/data/logs/fallback_access.log
labels:
  type: nginx-proxy-manager   # 核心:必须声明为 nginx-proxy-manager
---
filenames:
  - /var/log/auth.log
labels:
  type: syslog
EOF

重启 CrowdSec 载入日志采集:sudo systemctl restart crowdsec

四、 第三阶段:装配黄金 WAF 规则舰队与 0 容忍秒封规则

4.1 一键装配推荐规则集

更新官方 Hub 索引并批量安装最强防御规则包:

# 更新规则索引
sudo cscli hub update

# 1. 核心底座:必须安装 NPM 专属日志解析器(否则无法提取真实 IP)
sudo cscli collections install crowdsecurity/nginx-proxy-manager

# 2. Web 核心与通用 CVE 漏洞防御
sudo cscli collections install crowdsecurity/base-http-scenarios
sudo cscli collections install crowdsecurity/http-cve
sudo cscli collections install crowdsecurity/http-dos

# 3. 合规爬虫与白名单(防止 Google/Bing/Baidu 蜘蛛被误封)
sudo cscli collections install crowdsecurity/whitelist-good-actors

# 4. 主机级防护(SSH 22 端口防撞库与 Linux 提权审计)
sudo cscli collections install crowdsecurity/sshd
sudo cscli collections install crowdsecurity/linux

# 5. 可选:针对 WordPress 的专项防御(若有 WP 站点推荐安装)
sudo cscli collections install crowdsecurity/wordpress

4.2 配置防报错白名单模板

为了避免解析器加载空文件报错,我们先初始化一个标准的 IP 白名单:

sudo cat << 'EOF' > /etc/crowdsec/parsers/s02-enrich/tg-whitelist.yaml
name: custom/tg-whitelist
description: "Whitelist trusted IPs"
whitelist:
  reason: "Admin manual whitelist"
  ip:
    - "127.0.0.1"
    - "::1"
EOF

4.3 打造自研 0 容忍瞬发触发器(秒杀定向扫描器)

💡 核心设计:官方规则为了避免误伤,通常使用“漏桶算法(需要累计命中 5~10 次才封禁)”。但针对如 pearcmd(PHP 包含)、目录穿越、.env 探针、phpmyadmin 等行为,正常人类绝不可能访问。我们配置 type: trigger,实现首发请求当场秒封 4 小时!

创建自定义场景 /etc/crowdsec/scenarios/strict-path-traversal.yaml:

sudo cat << 'EOF' > /etc/crowdsec/scenarios/strict-path-traversal.yaml
type: trigger
name: custom/strict-path-traversal
description: "0-Tolerance Instant Ban for Path Traversal and Sensitive Probing"
filter: "evt.Meta.log_type == 'http_access-log' && evt.Parsed.request != nil && evt.Parsed.request matches '(?i)(/[.]|[.][.]|pearcmd|phpmyadmin|actuator|pma)'"
groupby: "evt.Meta.source_ip"
blackhole: 1m
labels:
  service: http
  type: exploit
  remediation: true
EOF

语法排坑细节:

  1. remediation: true 必须严格缩进在 labels: 内部,写在根节点会引发 Go struct unmarshal 致命崩溃;
  2. 正则使用 /[.] 与 [.][.] 匹配点号,杜绝 YAML 与 Go expr 引擎的双重反斜杠转义冲突(invalid char escape);
  3. 必须包含 groupby: "evt.Meta.source_ip",系统才能准确提取出攻击者 IP 并实施精准拉黑。

执行配置自检并热重载:sudo crowdsec -t && sudo systemctl reload crowdsec

终端显示 configuration is valid 即代表规则 100% 编译成功!

五、 第四阶段:云端大屏与原生告警联动

5.1 接入 CrowdSec 官方云端控制台(0MB 本地内存开销)

  1. 访问并注册 CrowdSec Console (app.crowdsec.net);
  2. 在控制台左侧点击 Security Engines ➡️ Enroll Engine,复制生成的注册密钥;
  3. 在 VPS 终端执行接入命令:sudo cscli console enroll <你的EnrollKey>
  4. 回到网页端点击 Accept 批准。在手机浏览器打开该网址并「添加到主屏幕」,即刻拥有一款精美且零本地开销的全球威胁大屏 PWA。

六、 第五阶段:主机 SSH 哨兵与防刷屏防抖治理

为了防止服务器被未授权登录,我们可以配置 SSH 登录实时推送。

⚠️ 致命刷屏陷阱:使用 FinalShell、VS Code Remote-SSH、Termius 等工具时,其后台每隔 2~5 秒就会偷偷发起一次免密 SSH 连接去采集服务器 CPU/内存状态。如果直接写脚本,Telegram 会被瞬间刷屏千条!必须加入 TTY 终端校验与 10 分钟冷却防抖缓存!

编辑 /etc/ssh/sshrc:

sudo cat << 'EOF' > /etc/ssh/sshrc
#!/bin/sh
# 1. 严格过滤非交互式连接(彻底屏蔽 FinalShell 状态探针与 SFTP 轮询)
[ -z "$SSH_TTY" ] && exit 0

CLIENT_IP=$(echo $SSH_CONNECTION | awk '{print $1}')
LOGIN_USER=$(whoami)
LOGIN_DATE=$(date "+%Y-%m-%d %H:%M:%S")

# 2. 10 分钟 (600秒) 同一 IP 冷却防抖
LOCK_FILE="/tmp/.ssh_alert_${CLIENT_IP}"
NOW=$(date +%s)
COOLDOWN=600

if [ -f "$LOCK_FILE" ]; then
    LAST_TIME=$(cat "$LOCK_FILE" 2>/dev/null || echo 0)
    DIFF=$((NOW - LAST_TIME))
    if [ "$DIFF" -lt "$COOLDOWN" ]; then
        exit 0
    fi
fi
echo "$NOW" > "$LOCK_FILE"

# 3. 发送告警(替换为您的 Token 与 Chat ID)
BOT_TOKEN="你的_BOT_TOKEN"
CHAT_ID="你的_CHAT_ID"

curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
  -H "Content-Type: application/json" \
  -d "{
    \"chat_id\": \"${CHAT_ID}\",
    \"text\": \"🚨 <b>【VPS SSH 登录提醒】</b>\n━━━━━━━━━━━━━━━━━━\n• <b>登录用户:</b> <code>$LOGIN_USER</code>\n• <b>来源 IP:</b> <code>$CLIENT_IP</code>\n• <b>登录时间:</b> <code>$LOGIN_DATE</code>\n━━━━━━━━━━━━━━━━━━\n<i>如果非本人操作,请立刻检查服务器!</i>\",
    \"parse_mode\": \"HTML\"
  }" > /dev/null 2>&1 &
EOF

sudo chmod +x /etc/ssh/sshrc

七、 第六阶段:Telegram 威胁情报中心 3.0(口袋 SOC)

我们全面重构了 Python 机器人,打造 威胁情报中心 3.0:

  • 100% 依赖 Python 3 标准库:无任何 pip 依赖,常驻物理内存仅 15MB 左右;
  • 原生命令菜单联想:自动注入 setMyCommands,在 TG 聊天框输入 / 即可弹出全中文操作提示;
  • 反向游标日志抽样(防 OOM 核心):单站点日志即使膨胀到 28MB+,每次也仅流式读取末尾 512KB 分块做反向聚合,CPU 占用瞬间 < 3%,内存零抖动;
  • 刑侦级报文穿透:直接调阅底层 HTTP 请求路径、User-Agent 客户端指纹与归属地;
  • 卡片内嵌快捷处置:拦截告警直接携带 [🔓 一键解封] 与 [🛡️ 永久加白] Inline 按钮。

7.1 编写守护脚本 /usr/local/bin/crowdsec_bot.py

7.2 配置 Systemd 开机自启服务

sudo chmod +x /usr/local/bin/crowdsec_bot.py

sudo cat << 'EOF' > /etc/systemd/system/crowdsec-tg-bot.service
[Unit]
Description=CrowdSec Telegram Threat Intelligence Bot 3.0
After=network.target crowdsec.service

[Service]
Type=simple
User=root
ExecStart=/usr/bin/python3 /usr/local/bin/crowdsec_bot.py
Restart=always
RestartSec=5s

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now crowdsec-tg-bot.service

八、 第七阶段:全链路攻防实测与三大避坑锦囊

一切就绪后,我们来执行完整的闭环验证。

8.1 零风险“显微镜”冒烟测试(无需碰公网)

CrowdSec 内置了强大的离线流水线回放工具 cscli explain,可以在本地瞬间完成冒烟验证:

echo '[09/Oct/2026:12:00:00 +0000] - 404 404 - GET http test.com "/.env" [Client 198.51.100.99] [Length 162] [Gzip -] "curl/7.68.0" "-"' | sudo cscli explain --type nginx-proxy-manager -f -

全绿验收标准:

  • s01-parse 中 🟢 crowdsecurity/nginx-proxy-manager-logs 显示绿色;
  • 结算显示 ├-------- parser success 🟢;
  • 底部场景显示 🟢 custom/strict-path-traversal 命中!

8.2 实弹射击与「Happy Eyeballs」避坑

⚠️ 高危提醒:千万不要用正在连 SSH 的电脑测试!拿起手机,关闭 Wi-Fi,用 4G/5G 蜂窝数据访问: http://你的域名/.env

验证闭环:

  1. Telegram 手机端:1 秒内弹出【突发威胁阻断】卡片,附带手机运营商 IP、归属地与解封按钮;
  2. 手机端访问:刷新页面立刻无限超时转圈(内核级 DROP 生效);
  3. 一键恢复:在手机 TG 告警卡片上直接点击 [🔓 一键解封此 IP],手机访问瞬间满血复活!

避坑:为什么在电脑上 curl 被封后再次执行还能通?(RFC 8305 双栈回退)

如果你在 Windows 上再次运行 curl -I "https://你的域名/?test=pearcmd",发现居然返回了 200,不要误以为没封住!

  • 底层机制:Windows 启用了 RFC 8305「快乐眼球 (Happy Eyeballs)」算法。电脑默认走 IPv6,当 IPv6 被 nftables 丢弃后,系统仅用 250ms 就自动降级回退到了 IPv4 连接!
  • 铁证检验:强制指定 IPv6 请求:curl -6 -I "https://你的域名/?test=pearcmd",此时连接将彻底卡死超时,证明底层封杀万无一失!

8.3 终极排错锦囊:为什么刚部署完没有攻击记录?

如果系统刚上线时一条告警都没有,请参照以下三点排查:

  1. 查验核心解析率:运行 sudo cscli metrics。
    • 查看 Acquisition Metrics 与 Parser Metrics:若 Lines read == Lines parsed 且 Lines unparsed 为 -(0行),说明解析率 100%。没有告警是因为进入的都是正常用户的 200 请求,零误杀是系统最健康的表现!
  2. CAPI 2万黑名单在内核层无声守护:
    • cscli metrics 中的 CAPI (community blocklist: 19.94k IPs) 已经为你提前拦截了公网上两万个最臭名昭著的扫描器。这些机器人在握手阶段就被内核直接 DROP,根本进不了 NPM,自然不会产生日志。
  3. 时区差陷阱:
    • NPM 容器内部固定使用 UTC 协调世界时(比北京时间慢 8 小时)。北京时间晚上 19:00 的日志,在日志里记录的是 11:00,检索当天日志时请注意换算时区。

九、 第八阶段:全自动无人值守维护与总结

9.1 规则库每日自动更新

通过 Crontab 定时在每天凌晨 04:30 自动拉取最新的社区恶意特征:sudo crontab -e

追加一行:30 4 * * * /usr/bin/cscli hub update && /usr/bin/cscli hub upgrade && /bin/systemctl reload crowdsec > /dev/null 2>&1

总结与工程价值

回顾整套工程实践,我们用极简优雅的架构实现了惊人的低功耗奇迹:

  • 极致轻量:全套组件总物理内存占用牢牢压在 380MB 以内,即使在最廉价的 1GB 内存 VPS 上,仍留有近 500MB 缓冲空间,彻底告别 OOM 宕机恐惧;
  • 铜墙铁壁:通过 network_mode: host 堵死了 Docker 绕过宿主机 INPUT 链的致命漏洞;结合自研 0 容忍触发器与 CAPI 2 万黑名单,黑客的初次扫描即被立地正法;
  • 掌中掌控:宏观上通过 CrowdSec Console 查看全球威胁地图,微观上通过 Telegram 九宫格随时体检、一键释放内存、调阅黑客榜单与原始报文取证,真正实现了“轻量省心、人在外面走、安全掌中控”!
© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容