如何使用Nginx和SSL在AWS EC2上运行完整的Ethereum Geth节点

1,068 阅读12分钟

一个完整的以太坊节点对于开发来说往往是必要的,或者如果你不想依靠第三方如Infura来访问区块链。与*"以太坊杀手 "相比,*运行一个完整的ETH节点是相对实惠的,只需要基本的开发操作技能。在这篇博文中,我将描述在AWS EC2上设置一个完整的Geth节点的逐步过程。我们将讨论的主题包括硬件成本和要求,同步光节点,以及使用安全的HTTPS连接将Metamask钱包连接到节点的NGNIX代理。

本教程涵盖Ubuntu20.04上的Geth1.10.16版本。只有第一部分是针对AWS的。其余的步骤在任何其他云VPS供应商或运行Ubuntu的专有服务器上都是相同的。

我们有很多内容要讲,所以让我们开始吧!

启动一个EC2实例

首先是配置一个新的EC2实例。转到EC2 > 实例 > 启动实例。选择Ubuntu Server 20.04 LTS (HVM), SSD Volume TypeAMI。在下一步,选择m5.large(8 GiB RAM, 2 vCPUs) 实例类型(费用∼75美元/月)。

在 "步骤3:配置实例细节"屏幕上,你可以把一切都保持在默认值,然后点击下一步。添加存储

在撰写本文时,以太坊全节点需要600GB的磁盘空间。在选择磁盘大小之前,请检查当前的空间需求。根据你想保持节点运行多长时间,你必须为新区块留出一些阈值。目前,完整节点的增长率似乎是在50GB/月。

对于卷的类型,选择通用固态硬盘(gp3),默认的IOPS和吞吐量设置。它比老一代的gp2磁盘要便宜20%。在本教程中,我添加了750GB的磁盘,所以每月的存储空间费用将是~60美元。另外,确保选择**(默认)aws/ebs**加密。

现在点击下一步。添加标签下一步。配置安全组。在这个屏幕上,选择创建一个新的安全组。修改入站流量规则,将所有IP的TCP端口22 列为白名单,即:0.0.0.0/0

image.png

你还必须允许TCPUDP 端口30303 的入站流量,因为它是P2P发现和同步所需要的。30303 端口也应该为0.0.0.0/0 通配符地址暴露。此外,如果你想配置对节点JSON-RPC API的外部访问,你必须开放TCP 端口80443

接下来,点击审查和启动启动。当提示有关密钥对时,选择,创建一个新的密钥对,并给它任何有意义的名字。按 "下载密钥对"将其保存在你的本地磁盘上,随后启动实例

现在回到你的终端,通过运行改变你的密钥对的权限。

chmod 400 keypair-ec2.pem

接下来,进入EC2 > 实例,并进入你的新服务器细节页面。复制它的公共 IPv4 地址。 回到你的终端,你现在可以 SSH 进入你的 EC2。

ssh ubuntu@123.123.123.123 -i keypair-ec2.pem

在Ubuntu上配置Geth

我们将把 Geth 进程作为一个 systemd 服务来启动,使其在后台运行并启用自动重启。首先运行这些命令,从官方仓库安装 Geth。

sudo add-apt-repository ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install ethereum

现在创建/lib/systemd/system/geth.service 文件,内容如下。

[Unit]

Description=Geth Full Node
After=network-online.target
Wants=network-online.target

[Service]

WorkingDirectory=/home/ubuntu
User=ubuntu
ExecStart=/usr/bin/geth --syncmode snap --http --http.api personal,eth,net,web3,txpool
Restart=always
RestartSec=5s

[Install]
WantedBy=multi-user.target

ExecStart 命令 决定了我们将启动一个完整的节点。从 Geth--syncmode snap 1.10.16 开始, 同步模式已经取代了 模式。如果你试图使用传统的 模式,你会看到以下错误。snap fast fast

invalid value "fast" for flag -syncmode: unknown sync mode "fast", want "full", "snap" or "light"

--http flag(替换了传统的 )启用了 HTTP API,我们将用它来连接我们的 Metamask 客户端。--rpc

现在你可以通过运行Geth服务来启用和启动它。

sudo systemctl enable geth
sudo systemctl start geth

并看到使用的日志输出。

sudo journalctl -f -u geth

现在你可以通过启动 Geth 控制台来验证该节点是否已经启动并运行。

geth attach

在控制台中,现在运行。

eth.syncing

你应该得到一个类似的输出,表明节点已经开始同步了。

{
  currentBlock: 2254868,
  healedBytecodeBytes: 0,
  healedBytecodes: 0,
  healedTrienodeBytes: 0,
  healedTrienodes: 0,
  healingBytecode: 0,
  healingTrienodes: 0,
  highestBlock: 14426316,
  startingBlock: 2250487,
  syncedAccountBytes: 2670602107,
  syncedAccounts: 11057974,
  syncedBytecodeBytes: 257393098,
  syncedBytecodes: 50954,
  syncedStorage: 42499504,
  syncedStorageBytes: 9161595917
}

如果你得到的是false ,你应该等待一两分钟来启动同步。如果你在完成同步过程中遇到任何问题,你可以运行。

sudo journalctl -f -u geth

来跟踪日志输出。另外,你可以用--verbosity 5 标志来运行geth进程,以增加日志的颗粒度。

在节点完成同步的几个小时后,它应该可以在ethernodes.org上被发现。你可以通过进入geth attach 控制台并运行来仔细检查你是否正确地打开了所有必要的端口。

admin.peers.map((el) => el.network.inbound)

你应该看到truefalse 两个值,意味着你的节点在P2P网络中是可以被发现的。如果你只看到假的,你可能没有公开暴露TCPUDP 端口30303

初始同步时间取决于硬件配置(后面有更多细节)。你可以通过进入geth控制台并运行来检查我们的节点是否已经完全同步了。

eth.blockNumber

并将该值与外部数据源进行比较,例如Etherscan。你可以查看Geth的官方文档,了解更多关于可用的API方法的信息。

如果你得到0 ,那么检查你的日志是否有类似的条目。

State heal in progress

它们的出现意味着你的节点失去了同步,可能需要几个小时才能赶上。如果这个问题在10多个小时后没有自行解决,你的服务器可能缺乏CPU、内存或磁盘吞吐量。

用NGINX对完整的Geth节点进行密码保护的HTTPS访问

每个控制台方法都有它的JSON-RPC等价物。你可以通过运行以下cURL命令,用HTTP API检查当前的块数。

curl -X POST http://127.0.0.1:8545 
-H "Content-Type: application/json" 
--data '{"jsonrpc":"2.0", "method":"eth_blockNumber", "id":1}'

但是现在,你只能从EC2实例内部与节点对话。让我们看看我们如何通过添加NGINX的JSON-RPC流量来安全地将API暴露给公众。

你需要一个域来实现这个解决方案。它可以是一个根域或一个子域。你必须添加一个A DNS记录,指向你的EC2实例的IP。建议使用一个弹性IP地址,这样,如果你必须改变实例配置,地址就不会改变。

接下来,在实例内,你必须安装必要的软件包。

sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install nginx apache2-utils
sudo apt-get install python3-certbot-nginx

现在你可以通过运行生成一个SSL证书和初始NGINX配置。

sudo certbot --nginx -d example.com

为了自动更新你的证书,在/etc/crontab文件中添加这一行。

@monthly root certbot -q renew

一旦你完成这些步骤,你应该在你的域名上看到一个NGINX欢迎页面。

image.png

NGINX欢迎页面

接下来生成一个HTTP基本认证用户和密码。

sudo htpasswd -c /etc/nginx/htpasswd.users your_user

现在你需要编辑NGINX的配置文件/etc/nginx/sites-enabled/default

server {
    server_name example.com;

    auth_basic "Restricted Access";
    auth_basic_user_file /etc/nginx/htpasswd.users;

    location / {
        proxy_pass http://localhost:8545;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_cache_bypass $http_upgrade;
    }

    listen [::]:443 ssl ipv6only=on;
    listen 443 ssl;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}

server {
  if ($host = example.com) {
      return 301 https://$host$request_uri;
  }

  listen 80 ;
  listen [::]:80 ;
  server_name example.com;
  return 404;
}

SSL证书文件是由certbot 指令自动生成的

我们使用proxy_pass 指令将流量从加密的443 HTTPS端口代理到我们EC2实例上的Geth节点端口8545 ,而不公开暴露。此外,每个请求都需要HTTP基本认证头。

现在验证一下配置是否正确。

sudo nginx -t

并重新启动NGINX进程以应用变化。

sudo service nginx restart

默认的欢迎页面应该不再能被访问。你可以使用从你的EC2外部执行的这个命令,检查你的全节点是否可以通过安全的HTTPS连接。

curl -X POST https://example.com 
  -H "Content-Type: application/json" 
  -u your_user:your_password 
  --data '{"jsonrpc":"2.0", "method":"eth_blockNumber", "id": 1}'

一旦你有了它的工作,你现在可以连接你的浏览器Metamask扩展,使用你的个人全节点来访问区块链。要做到这一点,请进入Metamask设置>网络>添加一个网络。给你的网络起个名字,并在新的RPC URL中,以下列格式输入你的全节点连接URL。

https://user:password@example.com

image.png

Metamask自定义网络配置

输入ETH货币符号链ID应该自动填充为1 ,代表Ethereum主网。你现在可以点击保存,像平时一样使用你的Metamask钱包。你现在直接与以太坊区块链对话,而不需要像Infura或Alchemy这样受信任的第三方。如果AWS对于你的区块链需求来说还是太集中了,请记住,你可以在你的专有硬件上使用类似的设置。

不幸的是,我只能让自定义网络配置在Brave/Chrome版本的Metamask上工作。在Firefox上,从10.11.3开始,似乎有一个错误。我已经在GH上提交了一个问题,所以希望这个问题能得到解决。

全节点和轻节点的硬件要求

下面你可以看到显示m5.large (8 GiB RAM,2 vCPU)EC2实例在完全同步过程中的CPU、内存和磁盘利用率的图表。

image.png

你可以看到,整个过程花了大约20个小时。显然,CPU已经达到了最大值,但内存使用率一直低于80%。同步完成后,CPU和内存的使用率都明显下降。

我还在m5.xlarge (16GiB内存,4个vCPU)实例上测试了完全同步,花了12小时而不是20小时。但是,CPU和RAM的指标几乎是相同的。

这意味着,硬件的选择取决于你对全节点启动和运行的迫切程度。但是,一定要避免使用t2/t3 实例。它们的特点是所谓的*"可突发 "CPU,这意味着持续的处理器使用量超过基线*(根据实例大小在5%到40%之间)将被节制或产生额外费用。

同步完成后,节点的硬件要求将根据你的使用情况而有所不同。如果你正在运行一个扫描mempool的套利机器人或每个区块上的数千个AMM合约,你将需要一个更强大的服务器,而不是你偶尔提交几个交易。可以选择使用--light.serve 标志,你可以将你的节点的一部分处理能力用于服务P2P轻型节点。

image.png

上图显示了两个完整节点的磁盘读取操作量。你可以看到,为轻型客户提供服务的节点,其密集程度是其他节点的10倍。两个节点上的CPU和内存使用量是相当的。运行一个公开接受轻客户端连接的完整节点是提高以太坊网络的去中心化和安全性的一种方式。但是,请记住,AWS会对流出的数据产生额外费用。如果你想支持轻型节点,强烈建议添加预算警报。

确定最具成本效益的实例类型的最好方法是持续观察指标,看看你是否没有耗尽CPU、内存或磁盘IOPS。AWS Cloudwatch可以在指标超过预定义阈值时轻松配置电子邮件警报。查看这些文档,了解如何收集磁盘和内存使用数据的信息,因为它们在默认情况下没有启用。

轻量级节点同步

如果你曾经试图启动一个轻型Geth节点,你可能对下面的日志输出感到熟悉。

Looking for peers peercount=0 tried=16 static=0
Looking for peers peercount=0 tried=16 static=0
Looking for peers peercount=0 tried=16 static=0
Looking for peers peercount=0 tried=16 static=0

image.png

轻节点对硬件和磁盘空间的要求明显低于全节点。我已经成功地在AWS免费层t2.micro 实例上运行了一个轻型Geth节点,它有一个8GB的磁盘。同步完成后,实际存储的区块链大小为~350MB,而全节点则超过500GB。轻型节点不保留和验证整个区块链,而只保留最后几十个区块。但是,他们依靠全节点与他们分享区块链的当前状态。正如我们所讨论的,支持轻量级节点是默认禁用的,并且会产生额外的费用。根据以太坊网络的拥堵情况,你的轻节点可能无法对等足够的全节点来赶上当前的区块链状态。因此,可怕的Looking for peers 消息。

我无法找到一个一致的模式,即什么因素决定了轻节点是否会开始同步。我猜这一切都归结于当前的网络拥堵情况。因此,如果你在一个AWS地区没有运气,一个解决方案可能是在全球范围内启动一个EC2实例。通常情况下,光节点至少需要10分钟才能开始同步。而且你可以随时尝试把它关闭和重新打开。有时在卡住一个多小时后,重新启动后同步就会马上启动。

你可以通过运行来调查你已经成功连接到了哪些节点。

admin.peers

但是,与完整的节点相比,对等节点的network.inbound 属性将总是false ,因为轻型节点不接受传入的连接。

总结

Infura和Alchemy目前是日常区块链互动的行业标准。但是,知道即使中心化的看门人不营业,我也总是能够访问我的资金,这大大增加了我对以太坊网络的信任。此外,即使在即将到来的合并之后,你仍然能够在类似的硬件上托管完整的节点。存储空间只是要变得更便宜。因此,不断增长的区块链规模绝不应该成为普通用户托管完整节点和支持网络的障碍。