入职 Web3 运维日记 · 第 4 日:拒绝“裸奔” —— 接口加固与监控闭环

时间 :入职第 4 天 天气 :多云转晴 状态:如履薄冰,但逐渐掌控局面

前三天,我费了九牛二虎之力才把这个以太坊全节点拉起来,解决了同步死循环和时间漂移的问题。 我本以为今天可以摸个鱼,研究一下公司的代码库。 结果刚上班,安全组(SecOps)的一封邮件就把我炸醒了。

🚨 1. 上午 09:15:一份"刺眼"的漏洞扫描报告

邮件标题是鲜红的:《高危:基础设施组件未授权访问风险通知》。 附件里的 PDF 直接点名了我那台刚上线的节点服务器:

目标 IP :172.31.20.100 (Eth-Mainnet-Node) 漏洞描述 :TCP 8545 端口监听在 0.0.0.0,且未配置鉴权。 风险等级High 整改建议:立即收敛监听地址,或增加访问控制层。

组长路过我工位,敲了敲桌子:"Alen,虽然这是在 VPC 内网,但按照金融合规要求,内网也是'不可信'的。万一内网某台测试机中了毒,黑客扫到你的 8545 端口,发一个恶意的 eth_getLogs 请求,你的节点瞬间就会 CPU 100% 宕机。今天下班前,给它穿上'防弹衣',另外把监控告警配好,我不希望下次是用户告诉我节点挂了。"

我看着那行 0.0.0.0,确实是大意了。在 Web3,JSON-RPC 接口就是金库的大门,我居然让它敞开着。

🛠️ 2. 上午 10:30:第一道防线 ------ 部署 Nginx 反向代理

Scanner 服务确实需要访问我的节点,但我不能让所有内网机器都能访问。 Geth 自带的 HTTP 配置功能太弱,不支持 IP 白名单,也不支持速率限制(Rate Limit)。 解决方案 :在节点前面挡一层 Nginx

步骤一:修改 Geth 启动脚本 首先,我必须把 Geth 那个"危险"的耳朵收起来,只让它听本机的话。

复制代码
# 修改 /usr/local/bin/start_geth.sh
# ... (前略)
  --http \
  # [Day 4 修改] 从 0.0.0.0 改为 127.0.0.1
  # 强制外部流量必须走 Nginx,绕过 Nginx 谁也别想连
  --http.addr 127.0.0.1 \
  --http.port 8545 \
  --http.api "eth,net,web3,txpool" \
  --http.vhosts "*" \
# ... (后略)

步骤二:配置 Nginx 访问控制 安装完 Nginx 后,我写了一个专门的配置文件。这里不仅做了 IP 白名单 ,还加了 Rate Limit(速率限制),防止 Scanner 业务代码死循环把节点打挂。

复制代码
# /etc/nginx/sites-available/ethereum-rpc.conf

# 定义限流区域:每个 IP 每秒最多 1000 个请求,突发不超过 500
limit_req_zone $binary_remote_addr zone=rpc_limit:10m rate=1000r/s;

upstream geth_backend {
    server 127.0.0.1:8545;
}

server {
    listen 8080;  # 换个端口,增加一点隐蔽性

    access_log /var/log/nginx/rpc_access.log; # 开启审计日志

    # --- 核心安全规则 ---
    # 仅允许 Scanner 业务组的 CIDR (网段)
    allow 172.31.50.0/24;
    # 允许监控服务器
    allow 172.31.90.10;
    # 拒绝其他所有内网 IP
    deny all;

    location / {
        proxy_pass http://geth_backend;
        
        # 启用限流
        limit_req zone=rpc_limit burst=500 nodelay;
        
        # 传递真实 IP 给后端 (虽然 Geth 不看,但为了扩展性)
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

重启 Nginx 和 Geth 后,我自己用内网另一台机器测试了一把 curl。 结果:403 Forbidden爽。这就叫安全感。

📊 3. 下午 2:00:让黑盒变透明 ------ Prometheus 监控

加固完接口,接下来是"看见"。 如果不知道当前 Peer 有多少,不知道区块高度差多少,那我就像在开一辆没有仪表盘的赛车。

步骤一:开启 Geth Metrics 我又改了一次启动脚本,加入了 metrics 参数。

复制代码
# 修改 /usr/local/bin/start_geth.sh
# ...
  --metrics \
  --metrics.addr 127.0.0.1 \
  --metrics.port 6060 \
# ...

(注:同样需要在 Nginx 里配置一下 6060 的转发,或者只允许监控机访问)

步骤二:配置 Prometheus 抓取 Job 登录到公司的监控服务器,修改 prometheus.yml

复制代码
scrape_configs:
  - job_name: 'eth_mainnet_node_01'
    scrape_interval: 15s
    metrics_path: /debug/metrics/prometheus
    static_configs:
      - targets: ['172.31.20.100:6060'] # 这里的端口走的是 Nginx 转发或者直连
        labels:
          env: 'prod'
          role: 'full_node'

配置生效后,我在 Grafana 里导入了一个 Dashboard。看着上面跳动的 Block HeightPeer Count (50),我终于觉得自己是在"运维"它,而不是在"供着"它了。

🔔 4. 下午 4:30:告警闭环 ------ 飞书 (Lark) 通知

监控不是给人看的,是给机器看的。我不能 24 小时盯着大屏。 我需要配置一套规则:只要节点有问题,手机必须立刻响。

步骤一:编写告警规则 (Alert Rules) 我定义了三条"生死线":

复制代码
# rules/ethereum_alerts.yml
groups:
- name: EthereumNodeAlerts
  rules:
  # 1. 宕机告警:连不上端口或者进程挂了
  - alert: GethInstanceDown
    expr: up{job="eth_mainnet_node_01"} == 0
    for: 1m
    labels:
      severity: critical
    annotations:
      summary: "🚨 紧急:以太坊节点宕机"

  # 2. 同步落后告警:这是业务最关心的
  # 逻辑:全网最高高度 - 本地高度 > 20 (约 4 分钟)
  - alert: BlockHeightLagging
    expr: (chain_head_block - ethereum_blockchain_height) > 20
    for: 2m
    labels:
      severity: warning
    annotations:
      summary: "⚠️ 警告:节点同步滞后"
      description: "节点落后主网超过 20 个块,Scanner 可能漏单!"

  # 3. 没朋友告警:Peer 数量太少
  - alert: LowPeerCount
    expr: p2p_peer_count < 8
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "⚠️ 警告:P2P 连接数过低"

步骤二:配置 Alertmanager 发送给飞书 修改 alertmanager.yml,把 Webhook 指向公司的飞书机器人:

复制代码
receivers:
- name: 'lark-webhook'
  webhook_configs:
  - url: 'https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxx-xxxx-xxxx'
    send_resolved: true # 恢复正常也发一条通知

测试: 我手动停止了 Geth 进程。 1 分钟后,手机 "叮" 的一声。飞书弹窗:[🚨 紧急:以太坊节点宕机] 。 我又启动进程。 2 分钟后,手机又是 "叮" 的一声:[✅ 恢复:以太坊节点宕机]

✅ 5. 下午 6:00:日结

下班前,我把 Nginx 的访问日志截图和 Grafana 的监控链接发给了安全组和 Scanner 组。 安全组回复:"Pass" 。 组长回复:"干得不错。这才是生产级环境该有的样子。"

今日感悟: 在 AWS 上起个 EC2 很容易,跑个 Geth 也很容易。 但要给它穿上 Nginx 的防弹衣 ,装上 Prometheus 的眼睛 ,配上 Alertmanager 的嘴巴,这才是初级运维和高级运维的区别。

现在,这台节点已经是一座防御森严的堡垒了。 我可以安心下班了......大概吧?


📚 附录:Alen 的 Web3 运维错题本 (Day 4)

📖 第一部分:核心概念解析 (Glossary)

1. JSON-RPC (JSON Remote Procedure Call)
  • 定义:区块链节点与外部世界(如 Scanner、钱包、DApp)交互的标准协议。

  • Alen 的理解:它就像是 Web2 的 REST API,但它是无状态的。

  • 风险点 :REST API 通常有鉴权(Token/Cookie),但以太坊原生的 JSON-RPC 设计之初是完全开放、无鉴权的。谁连上了端口,谁就能发号施令。这就是为什么要挂 Nginx 的根本原因。

2. Lateral Movement (横向移动)
  • 定义:网络安全术语。指黑客攻陷了一台内网低权限服务器(如测试机)后,以此为跳板,扫描并攻击内网其他高价值服务器(如我的节点)。

  • 防御 :VPC 和安全组能防外网,但防不了内网。Nginx 的 IP 白名单就是为了切断这种横向攻击路径。

3. Expensive Query (昂贵查询 / 毒药请求)
  • 定义:消耗极高计算资源的 RPC 请求。

  • 例子eth_getLogs(查询大范围的历史日志)或 debug_traceTransaction(重放交易)。

  • 危害 :一个恶意的 eth_getLogs 请求,可能需要节点扫描几百 GB 的硬盘数据。如果没有 Rate Limit (速率限制),几个并发请求就能让 64核 CPU 瞬间瘫痪。


❓ 第二部分:关键技术问答 (Q&A)

Q1: 为什么 AWS 安全组 (Security Group) 不够用,必须上 Nginx?
  • AWS 安全组 (Layer 4):只管"门禁"。它只能判断来源 IP 是不是允许的,不管你带了什么东西进去。

  • Nginx (Layer 7):它是"安检员"。

    1. 限流:它能限制你每秒只能说 1000 句话(Rate Limit)。

    2. 日志:它能把你说的每句话都录音(Access Log)。

    3. 协议清洗 :未来甚至可以配置只允许 eth_blockNumber,禁止 debug_* 等危险指令。

Q2: 监控里为什么要区分 chain_head_blocklocal_block_height
  • chain_head_block (全网高度):这是 Geth 通过 P2P 网络听到的"别人家的高度"。

  • local_block_height (本地高度):这是我自己硬盘里实际存好的高度。

  • Lag (滞后) = 全网 - 本地。

    • 如果 Lag > 0 但很小(1-2),是正常的网络延迟。

    • 如果 Lag > 10,说明同步出问题了(IO 瓶颈或网络断连)。

    • 告警公式lag > 20 持续 2分钟 -> 报警

Q3: 为什么 0.0.0.0 是万恶之源?
  • 现象--http.addr 0.0.0.0 表示监听服务器上所有的网卡(公网 IP、内网 IP、Loopback)。

  • 后果 :如果你忘了配置 AWS 安全组,或者安全组配置失误开放了 0.0.0.0/0,你的节点瞬间就会暴露在公网,成为全球黑客的肉鸡。

  • 规范 :永远绑定 127.0.0.1,强迫流量走 Nginx 代理,或者只绑定特定的内网 IP。


📊 第三部分:Prometheus 关键监控指标清单

这是 Alen 在 Grafana 看板上配置的核心指标,也是 Geth 暴露出的 Metrics 中最重要的部分:

指标名称 (Metric Name) 含义 正常范围 告警阈值
chain_head_block 本地已同步的最新区块高度 随时间递增 N/A
p2p_peer_count 当前连接的邻居节点数量 30 ~ 50 (主网) < 10 (说明网络可能被隔离)
eth_sync_remaining 剩余未同步的区块/状态数 0 (同步完成) > 0 且长时间不下降
system_cpu_usage CPU 使用率 40% ~ 80% > 90% (可能遭受 DoS 攻击)
disk_usage_percent 磁盘空间使用率 < 70% > 85% (需立即扩容)

🛠️ 第四部分:常用验证命令 (Cheat Sheet)

Alen 留在记事本里的命令,用于以后每次变更配置后自测:

1. 检查端口监听状态 (确保 8545 只有 127.0.0.1)

Bash

复制代码
sudo ss -tulnp | grep 'geth\|nginx'
# 预期输出:
# tcp LISTEN 0 0 127.0.0.1:8545 ... users:(("geth"...))  <-- 只监听本地
# tcp LISTEN 0 0 0.0.0.0:8080 ... users:(("nginx"...))   <-- Nginx 监听所有

2. 模拟内网调用 (测试白名单)

Bash

复制代码
# 在本机测试 (应该成功)
curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' http://127.0.0.1:8080

# 在非白名单机器测试 (应该返回 403 Forbidden)
curl -v http://172.31.20.100:8080

3. 查看实时审计日志 (看谁在查数据)

Bash

复制代码
tail -f /var/log/nginx/rpc_access.log
# 格式:[时间] [来源IP] [请求状态] [响应时间]

(Day 4 附录结束)

相关推荐
Honmaple1 小时前
OpenClaw 远程访问配置指南:SSH 隧道与免密登录
运维·ssh
Jia ming2 小时前
Linux内存管理三层次解密
linux·运维·服务器
新缸中之脑2 小时前
Nanobot:轻量级OpenClaw
java·运维·网络
yqcoder2 小时前
uni-app 之 设置 tabBar
运维·服务器·uni-app
宴之敖者、2 小时前
Linux——git和gdb
linux·运维·git
China_Yanhy2 小时前
入职 Web3 运维日记 · 第 5 日:硬分叉倒计时 —— 给飞行中的飞机换引擎
运维·web3
代码游侠2 小时前
学习笔记——Linux内核与嵌入式开发2
linux·运维·arm开发·嵌入式硬件·学习·架构
Fᴏʀ ʏ꯭ᴏ꯭ᴜ꯭.2 小时前
Nginx性能调优与压测实战指南
运维·nginx
傻小胖3 小时前
18.ETH-GHOST-北大肖臻老师客堂笔记
笔记·区块链