Skip to content
You are reading Hyperledger Besu development version documentation and some displayed features may not be available in the stable release. You can switch to stable version using the version box at screen bottom.

Updated on August 13, 2020

Private network example tutorial

The private network example uses the Hyperledger Besu Docker image to run a private network of Besu nodes managed by Docker Compose.


This tutorial runs a private network suitable for education or demonstration purposes and is not intended for running production networks.


To run this tutorial, you must have the following installed:

Clone Besu sample networks source code

Clone the repository from the besu-sample-networks repository:

git clone


To use a specific version of Hyperledger Besu, set the BESU_VERSION environment variable.

Start the network


If running in Windows, run commands from the GitBash shell.

This tutorial uses Docker Compose to assemble the images and run the private network. To build the docker images and run the containers, go to the besu-sample-networks directory and run:


The script builds the images, and runs the containers. It also scales the regular node container to four containers to simulate a network with enough peers to synchronize.

When the process ends, it lists the running services:

Docker-compose services list example

Sample Network for Besu at latest
List endpoints and services
             Name                            Command               State                                        Ports
besu-sample-network_bootnode_1        /opt/besu/bootnode_start.s ...   Up>30303/tcp,>30303/udp, 8545/tcp, 8546/tcp, 8547/tcp
besu-sample-network_elasticsearch_1   /usr/local/bin/docker-entr ...   Up      9200/tcp, 9300/tcp
besu-sample-network_explorer_1        nginx -g daemon off;             Up>80/tcp
besu-sample-network_filebeat_1        /usr/local/bin/docker-entr ...   Up
besu-sample-network_grafana_1         /                          Up>3000/tcp
besu-sample-network_kibana_1          /usr/local/bin/dumb-init - ...   Up>5601/tcp
besu-sample-network_logstash_1        /usr/local/bin/docker-entr ...   Up      5044/tcp, 9600/tcp
besu-sample-network_minernode_1       /opt/besu/ -- ...   Up      30303/tcp, 8545/tcp, 8546/tcp, 8547/tcp
besu-sample-network_node_1            /opt/besu/ -- ...   Up      30303/tcp, 8545/tcp, 8546/tcp, 8547/tcp
besu-sample-network_prometheus_1      /bin/prometheus --config.f ...   Up>9090/tcp
besu-sample-network_redis_1  redis ...   Up      6379/tcp
besu-sample-network_rpcnode_1         /opt/besu/ -- ...   Up      30303/tcp,>8545/tcp, 8546/tcp, 8547/tcp
Setting up the besu index pattern in kibana
Orion not running, skipping the orion index pattern in kibana.

Followed by a list of the endpoints:

Endpoint list example

JSON-RPC HTTP service endpoint      : http://localhost:8545
JSON-RPC WebSocket service endpoint : ws://localhost:8546
GraphQL HTTP service endpoint       : http://localhost:8547
Web block explorer address          : http://localhost:25000/
Prometheus address                  : http://localhost:9090/graph
Grafana address                     : http://localhost:3000/d/XE4V0WGZz/besu-overview?orgId=1&refresh=10s&from=now-30m&to=now&var-system=All
Kibana logs address                 : http://localhost:5601/app/kibana#/discover
  • Use the JSON-RPC HTTP service endpoint to access the RPC node service from your Dapp or from cryptocurrency wallets such as Metamask.
  • Use the JSON-RPC WebSocket service endpoint to access the web socket node service from your Dapp.
  • Use the GraphQL HTTP service endpoint to access the HTTP GraphQL node service from your Dapp.
  • Use the Web block explorer address to display the block explorer web application. View the block explorer by entering the URL in your web browser.
  • Use the Prometheus address to access the Prometheus dashboard.
  • Use the Grafana address to access the Grafana dashboard.
  • Use the Kibana logs address to access the logs in Kibana.

To display the list of endpoints again, run:


Block explorer

This tutorial uses the Alethio Ethereum Lite Explorer.

Run the block explorer

Access the explorer by copying and pasting the Web block explorer address displayed when starting the private network to your browser.

The block explorer displays a summary of the private network:

Block Explorer

See that the explorer indicates six peers: the four regular nodes, the mining node, and the bootnode.

Click the block number to the right of Best Block to display the block details:

Block Details

You can explore blocks by clicking on the blocks under Bk on the left-hand side.

You can search for a specific block, transaction hash, or address by clicking the magnifying glass in the top left-hand corner.

Explorer Search

Monitor nodes with Prometheus and Grafana

The sample network also includes Prometheus and Grafana monitoring tools to let you visualise node health and usage. You can directly access these tools from your browser at the addresses displayed in the endpoint list.

For more details on how to configure and use these tools for your own nodes, see our performances monitoring documentation, as well as Prometheus documentation and Grafana documentation.


Run JSON-RPC requests

You can run RPC requests on rpcnode, the node exposed to the host to listen for requests. This tutorial uses cURL to make JSON-RPC requests.

For the RPC URL, this tutorial uses the placeholder <http-rpc-endpoint>. When you run the tutorial, replace this placeholder with the JSON-RPC HTTP service endpoint provided when you list the endpoints. (For example, http://localhost:8545.) The dynamic docker port mapping changes each time you run the network.

Click the button to import our collection of API examples to Postman.

Run in Postman

or download the raw JSON collection file.

Request the node version

Run the following command from the host shell:

curl -X POST --data '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":1}' <http-rpc-endpoint>

The result specifies the client version:

   "jsonrpc" : "2.0",
   "id" : 1,
   "result" : "besu/<version number>"

Here we query the version of the Besu node, which confirms the node is running.

Successfully calling this method shows that you can connect to the nodes using RPC. From here, you can walk through more interesting requests demonstrated in the rest of this section, or skip ahead to Create a transaction using MetaMask.

Count the peers

Peers are the number of other nodes connected to the RPC node.

Poll the peer count using net_peerCount:

curl -X POST --data '{"jsonrpc":"2.0","method":"net_peerCount","params":[],"id":1}' <http-rpc-endpoint>

The result indicates that there are six peers:

  "jsonrpc" : "2.0",
  "id" : 1,
  "result" : "0x6"

Request the most recently mined block number

Call eth_blockNumber to retrieve the number of the most recent block:

curl -X POST --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' <http-rpc-endpoint>

The result provides the most recently mined block:

  "jsonrpc" : "2.0",
  "id" : 1,
  "result" : "0x8b8"

The hexadecimal value 0x8b8 translates to 2232 in decimal, the number of mined blocks so far.

Check the miner account balance

Call eth_getBalance to retrieve the balance of the mining address (coinbase) defined in the miner node:

curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0xfe3b557e8fb62b89f4916b721be55ceb828dbd73","latest"],"id":1}' <http-rpc-endpoint>

The result specifies the miner account balance:

  "jsonrpc" : "2.0",
  "id" : 1,
  "result" : "0x79f905c6fd34e80000"


0x79f905c6fd34e80000 = 2250000000000000000000 Wei (2250 Ether).


Use a unit converter to translate values from Wei to Ether.

Wait a few seconds until there are new mined blocks then call eth_getBalance again. The balance increases, meaning the miner address successfully received the mining reward.

You can also view this information in the block explorer. It does exactly the same thing as this call, connecting to the RPC node using HTTP JSON-RPC, and displaying information on a web page.

Create a transaction using MetaMask

Now let’s use MetaMask to send transactions.

Before sending transactions, you need to create an account or use one of the accounts below created during the genesis of this private test network.


Do not use the following accounts on mainnet or any public network except for testing.

The private keys are displayed here which means the accounts are not secure.

Account 1 (Miner Coinbase Account)

  • Address: 0xfe3b557e8fb62b89f4916b721be55ceb828dbd73
  • Private key : 0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63
  • Initial balance : 0xad78ebc5ac6200000 (200000000000000000000 in decimal)

Account 2

  • Address: 0x627306090abaB3A6e1400e9345bC60c78a8BEf57
  • Private key : 0xc87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3
  • Initial balance : 0x90000000000000000000000 (2785365088392105618523029504 in decimal)

Account 3

  • Address: 0xf17f52151EbEF6C7334FAD080c5704D77216b732
  • Private key : 0xae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f
  • Initial balance : 0x90000000000000000000000 (2785365088392105618523029504 in decimal)


Besu doesn’t incorporate account management. To create your own account, you have to use a third-party tool, such as MetaMask.

After you sign in to MetaMask, connect to the private network RPC endpoint:

  1. In the MetaMask network list, select Custom RPC.
  2. In the New RPC URL field, enter the JSON-RPC HTTP service endpoint displayed when you started the private network.

Save the configuration and return to the MetaMask main screen. Your current network is now set to the private network RPC node.

Import one of the existing accounts above into MetaMask using the corresponding private key.


In this tutorial, we don’t need to secure the keys, because we’re using a private test network to send valueless Ether. In a production environment, be sure to secure your accounts on the main Ethereum network (MainNet).

When you’re finished importing an existing account, create another account from scratch to send Ether to.

In MetaMask, select the new account and copy the account address by clicking the gadget and selecting Copy Address to clipboard.

In the block explorer, search for the new account by clicking on the magnifying glass and pasting the account address into the search box. The account displays with a zero balance.

Send Ether from the first account (containing ether) to the new account (which has a zero balance).

Refresh the browser page displaying the new account. The updated balance displays and reflects the transaction completed using MetaMask.

Smart contract and DApp usage with the blockchain network

We are going to use the PetShop tutorial on Truffle website with a few modifications, so we use the private network in this tutorial as the blockchain network.


  • Node.js v6+ LTS and npm (comes with Node)
  • Import an account into Metamask using the private key 0xc87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3. The following steps use this account.

Install Truffle

Install Truffle:

npm install -g truffle


npm requires sudo on Linux.

The source code for the smart contract and DApp are in the pet-shop folder. With the blockchain running and Metamask connected to it via the browser, run the command below to start the DApp.

The script first compiles the contract, then performs a migration to the blockchain network and then runs some tests. You can then search for the deployed contracts and transactions in the Web Block Explorer using the addresses displayed in your output earlier http://localhost:32768/ (your port will differ). Similar output to the following displays (your addresses will differ).


Compiling your contracts...
> Compiling ./contracts/Adoption.sol
> Compiling ./contracts/Migrations.sol

Starting migrations...
> Network name:    'quickstartWallet'
> Network id:      2018
> Block gas limit: 0xf7b760


   Replacing 'Migrations'
   > transaction hash:    0x10f5ebaca0e89fa84bcae19d6848dde19817ea3cf270be0fd0ab52f041a02c61
   > Blocks: 0            Seconds: 0
   > contract address:    0x8CdaF0CD259887258Bc13a92C0a6dA92698644C0
   > block number:        64
   > block timestamp:     1579833316
   > account:             0x627306090abaB3A6e1400e9345bC60c78a8BEf57
   > balance:             89999.99472518
   > gas used:            263741
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.00527482 ETH

   > Saving migration to chain.
   > Saving artifacts
   > Total cost:          0.00527482 ETH


   Replacing 'Adoption'
   > transaction hash:    0x56f39e2411f2e95b89832c6ff81b619815ee83db1c54d2b166ecdc3ceda633a8
   > Blocks: 0            Seconds: 0
   > contract address:    0x345cA3e014Aaf5dcA488057592ee47305D9B3e10
   > block number:        66
   > block timestamp:     1579833320
   > account:             0x627306090abaB3A6e1400e9345bC60c78a8BEf57
   > balance:             89999.9890877
   > gas used:            239851
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.00479702 ETH

   > Saving migration to chain.
   > Saving artifacts
   > Total cost:          0.00479702 ETH

> Total deployments:   2
> Final cost:          0.01007184 ETH

Compiling your contracts...
> Compiling ./test/TestAdoption.sol

    ✓ testUserCanAdoptPet (2071ms)
    ✓ testGetAdopterAddressByPetId (6070ms)
    ✓ testGetAdopterAddressByPetIdInArray (6077ms)

  3 passing (37s)

After these tests are successful, it builds a container for the Pet Shop DApp and deployes it, binding it to port 3001 on your system.

In the browser that you have metamask enabled and the account loaded, open a new tab and navigate to http://localhost:3001 which should have the Pet Shop running, and you can adopt pets from the app. When you click on ‘Adopt’, a Metamask window should pop up and ask for permissions to continue with the transaction. After the transaction is complete and successful, the status of the pet you adopted will show ‘Success’.

Dapp UI

You can also search for the transaction and view its details in the Block Explorer UI at http://localhost:25000/.

Dapp UI

The Metmask UI also keeps a record of the transaction.

Dapp UI

Stop and restart the private network without removing containers

To shut down the private network without deleting the containers:


This command stops the containers related to the services specified in the docker-compose.yml file.

To restart the private network:


Stop the private network and remove containers

To shut down the private network and delete all containers and images created from running the sample network:

Questions or feedback? You can discuss issues and obtain free support on Hyperledger Besu chat channel.
For Hyperledger Besu community support, contact the mailing list