Deploy Hyperledger Besu on AWS

Victor Yeo
5 min readApr 6, 2022

This article describes my experience of deploying a minimum private permissioned Ethereum compatible blockchain with 2 nodes, running on Proof of Authority (POA) consensus using Hyperledger Besu. The deployment is carried out on AWS cloud.

For this deployment, i create two EC2 instance with 1GB RAM and 16GB type gp2 Elastic Block Store (EBS).

Step 1: Create folder structure

The folder structure for the blockchain deployment is shown as below. Feel free to set Node-1 for one EC2 instance, and Node-2 for another EC2 instance.

Permissioned-Network/
├── Node-1
│ ├── data
└── Node-2
├── data

Step 2: Get the address of Node-1

To use Node-1 as the initial signer, we need the address of Node-1. To get the address of Node-1, we call the besu command:

besu --data-path=data public-key export-address --to=data/nodeAddress1

Step 3: Create the genesis file

With the Node-1 address generated, we proceed to create the genesis file in Node-1 and Node-2 Permissioned-Network folder and name it cliqueGenesis.json.

{ 
“config”:{
“chainId”:1981,
“constantinoplefixblock”: 0,
“clique”:{
“blockperiodseconds”:15,
“epochlength”:30000
}
},
“coinbase”:”0x0000000000000000000000000000000000000000",
“difficulty”:”0x1", “extraData”:”0x0000000000000000000000000000000000000000000000000000000000000000<Node 1 Address>0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
“gasLimit”:”0xa00000",
“mixHash”:”0x0000000000000000000000000000000000000000000000000000000000000000",
“nonce”:”0x0",
“timestamp”:”0x5c51a607",
“alloc”: {
“fe3b557e8fb62b89f4916b721be55ceb828dbd73”: {
“balance”: “0xad78ebc5ac6200000”
},
“627306090abaB3A6e1400e9345bC60c78a8BEf57”: {
“balance”: “90000000000000000000000”
},
“f17f52151EbEF6C7334FAD080c5704D77216b732”: {
“balance”: “90000000000000000000000”
}
},
“number”:”0x0",
“gasUsed”:”0x0", “parentHash”:”0x0000000000000000000000000000000000000000000000000000000000000000"
}

In extraData, replace <Node 1 Address> with the address for Node-1 that was generated earlier, excluding the 0x prefix.

Step 4: Create permission config file

Then, we copy the following permissions configuration to a file called permissions_config.toml and save a copy in the Node-1/data, Node-2/data directories:

accounts-allowlist=["0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", "0x627306090abaB3A6e1400e9345bC60c78a8BEf57"]nodes-allowlist=[]

The permissions configuration file includes the first two accounts from the genesis file (accounts-allowlist).

Step 5: Start node-1 and node-2

In Node-1 folder, we start the Node-1 besu node.

besu --data-path=data --genesis-file=../cliqueGenesis.json  --permissions-nodes-config-file-enabled --permissions-accounts-config-file-enabled --rpc-http-enabled --rpc-http-api=ADMIN,ETH,NET,PERM,CLIQUE --host-allowlist=”*” --rpc-http-cors-origins=”*” --p2p-port=30303 --rpc-http-port=8545

And, in Node-2 folder, we start the Node-2 besu node.

besu --data-path=data --genesis-file=../cliqueGenesis.json  --permissions-nodes-config-file-enabled --permissions-accounts-config-file-enabled --rpc-http-enabled --rpc-http-api=ADMIN,ETH,NET,PERM,CLIQUE --host-allowlist=”*” --rpc-http-cors-origins=”*” --p2p-port=30304 --rpc-http-port=8546

When starting the nodes, we have to observe the enode of Node-1 and Node-2. We copy down the enode. The enode URL format is as below.

enode://<id>@<host:port>[?discport=<port>]

Step 6: Add enode to permission config file

We call JSON RPC API to add permissions to the file called permissions_config.toml that we created earlier.

curl -X POST --data '{"jsonrpc":"2.0","method":"perm_addNodesToAllowlist","params":[["<EnodeNode1>","<EnodeNode2>","<EnodeNode3>"]], "id":1}' http://127.0.0.1:8545

and:

curl -X POST — data ‘{“jsonrpc”:”2.0",”method”:”perm_addNodesToAllowlist”,”params”:[[“<EnodeNode1>”,”<EnodeNode2>”,”<EnodeNode3>”]], “id”:1}’ http://127.0.0.1:8546

Step 7: Add peer node

In Node-2 , we have to add the Node-1 enode to Node-2 so that they can see each other.

curl -X POST --data '{"jsonrpc":"2.0","method":"admin_addPeer","params":["<EnodeNode1>"],"id":1}' http://127.0.0.1:8546

Meanwhile, make sure the relevant inbound ports have all been enabled in AWS security group.

AWS security group screenshot

However, i found out that Node-1 and Node-2 cannot see each other, even after i have performed all the steps above.

After much troubleshooting, it is found out that we need to run bootnode in the private blockchain. Bootnode is used for initial peer node discovery.

Step 8: Start bootnode

To start a bootnode, firstly, we export bootnode public key. We run the command below in Permissioned-Network folder.

besu --genesis-file=cliqueGenesis.json --data-path=nodeDataPath public-key export --to=bootnode

Secondly, we start the bootnode with besu command, specifying bootnodes argument.

besu --genesis-file=cliqueGenesis.json --data-path=nodeDataPath --bootnodes

Step 9: Restart Node-1 and Node-2

After bootnode is started, we need to add the following argument to besu command used Step 5 above.

--bootnodes=<"bootnode enode">

Then, we restart Node-1 and Node-2, and they can see each other !!

The besu output log from Node-2:

2022–04–06 08:51:36.005+00:00 | EthScheduler-Workers-3 | INFO | PersistBlockTask | Imported #2,211 / 0 tx / 0 om / 0 (0.0%) gas / (0x35fc3b6de3255ef7c595a93a3c79c0b46c9be5d211f706923
42afa0c2c08873b) in 0.000s. Peers: 1
Screenshot on Node-2
Screenshot on Node-1

After that, i add AWS elastic IP to Node-1 EC2 instance. So that Node-1 EC2 can be accessed using a public ip address. But when i want to add the private network to metamask, such as :

http://<public_ip>:8545

Metamask is not recognizing the url.

In debugging, i want to check if port 8545 is open or not. I execute the command below in Node-2 command prompt (Node-2 is able to ping Node-1):

$ echo > /dev/tcp/<node-1_private_ip>/8545 && echo “port is open” 
-bash: connect: Connection refused
-bash: /dev/tcp/<node-1_private_ip>/8545: Connection refused

Yes, port 8545 is not open. However, when using local host address, port 8545 is open. Weird.

$ echo > /dev/tcp/127.0.0.01/8545 && echo “port is open” 
port is open

So eventually, i found out that port 8545 is not open to external world, because Besu node is listening on local host only!

This output below is observed when Node-1 is starting. This confirms that port 8545 is not open to external world.

Listening on 127.0.0.1:8545

Step 10: Make Node-1 listen to external connections
To allow remote connections, specify rpc http host to 0.0.0.0 in Node-1 besu command:

--rpc-http-host=0.0.0.0

Now, try adding private network to Metamask. It works finally !!

References:

https://besu.hyperledger.org/en/stable/Tutorials/Permissioning/Create-Permissioned-Network/

--

--