时间 :入职第 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 Height 和 Peer 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):它是"安检员"。
-
限流:它能限制你每秒只能说 1000 句话(Rate Limit)。
-
日志:它能把你说的每句话都录音(Access Log)。
-
协议清洗 :未来甚至可以配置只允许
eth_blockNumber,禁止debug_*等危险指令。
-
Q2: 监控里为什么要区分 chain_head_block 和 local_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 附录结束)