How To: Create Your Own Private Ethereum Blockchain

Why we use Private Ethereum Blockchain

Ethereum software enables a user to set up a “private” or “testnet” Ethereum chain that is separate from the main Ethereum chain. This is useful for testing distributed apps built on Ethereum without having to expose your apps or trials to the real Ethereum network using real Ether.



You need to have Geth installed. The easiest way to do this is through homebrew.

  1. Open Terminal and
/usr/bin/ruby -e "$(curl -fsSL"

2. Now

brew tap ethereum/ethereum
brew install ethereum


  1. Download and install

Step :

  1. create a folder
  2. create custom genesis file
  3. create custom data directory
  4. set custom networkID (ChainID)

Create Genesis File

The Genesis block is the start block of the Blockchain — the first block, block 0, and the only block that does not point to a predecessor block. the genesis block is hard coded into clients, but in Ethereum it can be whatever you like.

The Genesis file is a JSON file that defines the characteristics of that initial block and subsequently the rest of the blockchain.

  1. Create a directory to hold your network files
mkdir eth-chain
cd eth-chain

2. Create your genesis file

touch Genesis.json

3. Open your genesis file and paste the following

"nonce": "0x0000000000000042",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x20000",
"alloc": {},
"coinbase": "0x0000000000000000000000000000000000000000",
"timestamp": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0xffffffff",
"config": {
"chainId": 4224,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0


  • chainId — this is your chain’s identifier, and is used in replay protection.
  • homesteadBlock, eip155Block, eip158Block, byzantiumBlock — these relate to chain forking and versioning, so in our case lets leave them 0 since we’re starting a new blockchain.


This dictates how difficult it is to mine a block. Setting this value low (~10–10000) is helpful in a private blockchain as it lets you mine blocks quickly, which equals fast transactions, and plenty of ETH to test with.


This is the the total amount of gas that can be used in each block. With such a low mining difficulty, blocks will be moving pretty quick, but you should still set this value pretty high to avoid hitting the limit and slowing down your network.


Here you can allocate ETH to specific addresses. This won’t create the account for you, so make sure its an account you already have control of. You will need to add the account to your private chain in order to use it, and to do that you need access to the keystore/utc file.


A scalar value equal to the number of transactions sent by the sender.


mixhash is an intermediary calculation to finding the nonce that is not as costly to determine.


The ether rewards gained from “mining” the genesis block go to the 160-bit coinbaseaddress.


The output of the Unix time() function when the block was created


The Keccak 256-bit hash of the previous block’s header. This is meaningless in the genesis block, since block 0 has no parent.


An optional free, but max. 32 byte long space to conserve smart things for ethernity on the Blockchain.

Initial the genesis block

  • Init our blockchain with the settings in the genesis file and define a folder for storing chain data.
>  geth --datadir "./db" init genesis.json
  • datadir : Data directory for the databases and keystore
  • init: initialize a new genesis block

Data Directory

•Everything geth persists gets written inside its data directory (except for the PoW Ethash DAG, see note below). The default data directory locations are platform specific:

  • Mac: ~/Library/Ethereum
  • Linux: ~/.ethereum
  • Windows: %APPDATA%\Ethereum

Output should look like this:

Start your Ethereum peer node.

Networkid helps ensure the privacy of your network. You can use any number here (where we used “ 123456”), but other peers joining your network must use the same one.


geth --datadir "./db" --networkid 123456 --rpc --rpcport "8545" --rpccorsdomain "*" --nodiscover --rpcapi=”admin,db,eth,net,web3,personal”


geth --datadir "./db" --networkid 123456 --rpc --rpcport "8545" --rpccorsdomain "*" --port 30303 --nodiscover --rpcapi="admin,db,eth,debug,miner,net,shh,txpool,personal,web3"

Output should look like this:

Open a new terminal

Command Line Options

Management APIs

Beside the official DApp APIs interface go-ethereum has support for additional management APIs. Similar to the DApp APIs, these are also provided using JSON-RPC and follow exactly the same conventions.


Geth provides the following extra management API namespaces:

  • admin: Geth node management
  • debug: Geth node debugging
  • miner: Miner and management
  • personal: Account management
  • txpool: Transaction pool inspection

For more here

Open a new terminal ,type

geth attach

Output should look like this:

Node Information

The nodeInfo administrative property can be queried for all the information known about the running Geth node at the networking granularity.

> admin.nodeInfo

Creating a new account

Creates a new account and prints the address. On the console, use:

> personal.newAccount()

Enter your password and then it will display account address. In my case, I set password to “123456”

The account is saved in encrypted format. You must remember this passphrase to unlock your account in the future.

Second way to create a new account

> personal.newAccount("123456")

Check account

Check accounts

> eth.accounts

Accounts is an array so you can search account by index.

> eth.accounts[0]


Check balance of account

> eth.getBalance(eth.accounts[0])

Check balance by using web3

> web3.fromWei(eth.getBalance(eth.accounts[0]),"ether")


1. Set Default Account

  • Check your default account, type
    > eth.coinbase
  • If this address is the same as the one from step 4, skip the rest of step 5.
  • To set your default account, type
    > miner.setEtherbase(web3.eth.accounts[0])

2. Start mining

  • Check your balance with
    > eth.getBalance(eth.coinbase)
  • Run
    > miner.start()
  • Look at your other terminal window, you should see some mining action in the logs. Check your balance again and it should be higher.
  • To end mining, type
    > miner.stop()


  1. Check your balance
> eth.getBalance(eth.coinbase)


> web3.fromWei(eth.getBalance(primary), “ether”);

2. Transfer Ether, type:

> eth.sendTransaction({from: '0x036a03fc47084741f83938296a1c8ef67f6e34fa', to: '0xa8ade7feab1ece71446bed25fa0cf6745c19c3d5', value: web3.toWei(1, "ether")})


> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(1, "ether")})

But you should get error like this.

Actually , User have to unlockaccount first before transfer.

3. Unlockaccount

> personal.unlockAccount("eth.accounts[0]")

4. Transfer Ether again, type:

> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(1, "ether")})

Transaction Pool

  1. shows transaction pool
> txpool.status

2. number of pending txs

> eth.getBlockTransactionCount("pending");

3. print all pending txs

> eth.getBlock("pending", true).transactions

You will find that Account[1] did not receive Ether from Account[0]. This is because no miner create a new block and verify your transaction. To process your transaction, you have to execute “miner.start(1)” again.

The whole process is :

> personal.unlockAccount("eth.accounts[0]")
//transfer Ether to Accounts[0]
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(1, "ether")})
//check Transaction
> txpool.status
//start mining
> miner.start(2)
//stop mining
> miner.stop()
// check balance of accounts[1]
> eth.getBalance(eth.accounts[1])

Add Other Peers

Add more nodes to your private Ethereum network.

1. Start another peer

  • On your same machine instantiate a new datadir:
 > geth --datadir ./db2 init ./Genesis.json
  • Launch the 2nd peer on a different port:
geth --datadir "./db2" --networkid 123456 --rpc --rpcport "8546"  --rpccorsdomain "*"  --port 30304 --nodiscover --rpcapi="admin,db,eth,debug,miner,net,shh,txpool,personal,web3" --ipcdisable consoleNote: remember to changer rpcport number and port number

folder structure

2. Join the 2nd peer

  • In the geth JavaScript console of your 2nd peer, type:
> admin.nodeInfo.enode

Output will look like this:

  • In the geth JavaScript console of your new 1st peer, type:
> admin.addPeer("enode://081739378a62d5c47e611a59c0e6dc3b82c8d47b98d7a33a05915c6d04cbaad64feb36cb5cc3682fbf0dc4a3950207a9acbbb671f9838962936df5e2adce7c20@[::]:30303?discport=0")
  • Make sure you replace “enode://…@” above with the output from admin.nodeInfo.enode which is specific to you. As shown above, the “[::]” is replaced with “” which is the IP:Port of the 1st peer.

3. Verify your nodes are now communicating

  • In the geth JavaScript console of your new 2nd peer, type:
> admin.peers
  • Output should show that peer 1 is connected to127.0.0.1:30304

Next chapter :

I do this because I love it, but if you want me to buy me a cup of coffee I won’t say no :O )

donation :


Ether : 0xf2d15dEAf62b8c4AFC0343006579E8E662c120D9

Bitcoin : 332UiyAfSXyvhqCYgDgBkNLFSf25ccNV9i

  • *Do CLAP, COMMENT and SHARE! I also welcome any business opportunities that arises**


撰寫任何事情,O型水瓶混魔羯,咖啡愛好者,Full stack/blockchain developer,Founder of Blockchain&Dapps meetup and DeFi-Decentralized-Finance-SG meetup,Udemy teacher。