Setting up an Ethereum private chain is a powerful way to experiment with blockchain technology, test smart contracts, and simulate decentralized applications in a controlled environment. Whether you're a developer exploring Ethereum's core mechanics or building a proof-of-concept dApp, a private network offers full control over consensus rules, gas pricing, and account management — all without the cost or unpredictability of the public mainnet.
This comprehensive guide walks you through every step: from compiling Geth to initializing a genesis block, creating accounts, mining Ether, sending transactions, and deploying and interacting with a smart contract using Solidity.
Step 1: Download the Geth Client
To begin, you’ll need the Go implementation of Ethereum — Geth. It allows you to run a full Ethereum node and interact directly with the blockchain.
Clone the official repository:
git clone https://github.com/ethereum/go-ethereum.gitThis command downloads the latest version of the Ethereum protocol written in Go, giving you access to essential tools like geth, the command-line interface for managing your node.
👉 Learn how blockchain nodes power decentralized networks.
Step 2: Compile Geth
Navigate into the project directory and compile the geth binary:
cd go-ethereum
make gethAfter compilation completes, the executable will be located at ./build/bin/geth. For convenience, add this path to your system’s PATH environment variable so you can run geth from anywhere.
This self-built version ensures you're working with a clean, customizable Ethereum client — ideal for development and testing.
Step 3: Configure the Genesis Block
The genesis block defines the initial state of your private blockchain. All chain parameters — including chain ID, difficulty, gas limit, and pre-funded accounts — are set here.
Create a file named genesis.json with the following configuration:
{
"config": {
"chainId": 7777,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"ethash": {}
},
"difficulty": "1",
"gasLimit": "8000000",
"alloc": {
"7df9a875a174b3bc565e6424a0050ebc1b2d1d82": { "balance": "300000" },
"f41c74c9ae680c1aa78f42e5647a62f353b7bdde": { "balance": "400000" }
}
}Key points:
chainId: Unique identifier for your network (7777 in this case).difficulty: Kept low ("1") to allow fast local mining.gasLimit: High enough to support complex contract deployments.alloc: Pre-funds two addresses with Ether at launch.
Initialize the blockchain with:
geth init --datadir data genesis.jsonThis creates a new blockchain data directory (data) based on your custom genesis file.
Step 4: Launch Your Ethereum Node
Start your private node with mining enabled and peer discovery disabled (to keep it isolated):
geth --datadir data --nodiscover --mine consoleYou’ll enter the interactive JavaScript console where you can execute Ethereum commands. The --mine flag enables built-in mining, while --nodiscover prevents unwanted connections from external nodes.
Your private Ethereum network is now live.
Step 5: Create Accounts
Inside the Geth console, generate a new Ethereum account:
> personal.newAccount()
Passphrase:
Repeat passphrase:
"0x45281eb7bbaa41fef62d40ae881378c14335c1cf"Securely store both the password and keystore file path shown in the warning message. Losing them means losing access to your funds.
List all available accounts:
> personal.listAccounts
["0x45281eb7bbaa41fef62d40ae881378c14335c1cf", "0x96b638097bb4dd40d9bca6f1197b8d24b1705cfa"]These accounts exist only on your private chain but follow standard Ethereum address formats.
Step 6: Start Mining Ether
Begin mining to generate Ether for your accounts:
> miner.start()You’ll see logs indicating new blocks being sealed. To stop mining:
> miner.stop()Check an account’s balance:
> web3.fromWei(eth.getBalance("0x45281eb7bbaa41fef62d40ae881378c14335c1cf"), "ether")
196Mining rewards accumulate in the coinbase (default mining) address — typically your first account.
Step 7: Send Transactions Between Accounts
Before sending Ether, unlock the sender account:
> personal.unlockAccount(eth.accounts[0])
Passphrase:
trueSend 10 Ether to the second account:
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(10, 'ether')})The transaction hash confirms submission. Mine one block to confirm it:
> miner.start(1); admin.sleepBlocks(1); miner.stop();Verify the recipient balance:
> web3.fromWei(eth.getBalance(eth.accounts[1]), 'ether')
10You’ve successfully executed your first cross-account transfer.
Step 8: Write and Compile a Smart Contract
Create a simple Solidity contract (demo.sol) that stores and retrieves a number:
pragma solidity >=0.7.0 <0.9.0;
contract SimpleStorage {
uint storedData;
function set(uint x) public {
storedData = x;
}
function get() public view returns (uint) {
return storedData;
}
}Compile it using Solc:
solc --optimize --combined-json abi,bin demo.solThis outputs ABI (interface) and bytecode (bin), which are required for deployment.
Step 9: Deploy and Interact With the Smart Contract
Unlock the deploying account:
> personal.unlockAccount("0x45281eb7bbaa41fef62d40ae881378c14335c1cf")Parse the compilation output and prepare deployment:
var storageContractJson = /* paste full solc output */
var storageContract = eth.contract(storageContractJson.contracts["demo.sol:SimpleStorage"].abi)
var storageContractObj = {
from: eth.accounts[0],
data: "0x" + storageContractJson.contracts["demo.sol:SimpleStorage"].bin,
gas: 1000000
}Deploy the contract:
var storageContractIns = storageContract.new(storageContractObj)Mine the transaction:
miner.start(1); admin.sleepBlocks(1); miner.stop();Retrieve the deployed contract address:
var storageContractInsAddress = eth.getTransactionReceipt(storageContractIns.transactionHash).contractAddressReconnect to the contract instance:
var storageContractIns = storageContract.at(storageContractInsAddress)Test interaction:
> storageContractIns.set.sendTransaction(77, {from: eth.accounts[0], gas: 1000000})
// Mine again
> storageContractIns.get.call()
77Your smart contract is now live and functional on your private Ethereum chain.
👉 Explore how smart contracts enable trustless automation.
FAQ Section
Q: Why use a private Ethereum chain?
A: A private chain lets developers test dApps, smart contracts, and network configurations safely and cost-effectively without relying on public testnets or spending real Ether.
Q: Can I connect MetaMask to my private chain?
A: Yes. Add a custom RPC network in MetaMask using your node’s URL (e.g., http://localhost:8545) and import accounts via private keys or JSON files.
Q: What is the purpose of the genesis.json file?
A: It defines the starting state of your blockchain — including initial accounts, balances, consensus settings, and protocol versions — ensuring all nodes agree on the chain’s foundation.
Q: How do I stop my Geth node gracefully?
A: Press Ctrl+C in the terminal or run exit in the console. This safely shuts down the node and flushes data to disk.
Q: Is mining necessary on a private chain?
A: Yes, if you’re using Proof-of-Work (Ethash). Mining creates new blocks and rewards. Alternatively, you can switch to Proof-of-Authority (e.g., Clique) for faster block times without heavy computation.
Q: Can I reuse my private chain after restarting Geth?
A: Absolutely. As long as you keep the --datadir folder intact, your accounts, contracts, and blockchain history persist across sessions.
By following these steps, you now have a fully functional Ethereum private network — perfect for learning, development, or enterprise use cases requiring isolated blockchain environments.
Whether you're testing gas optimization strategies or simulating multi-node interactions, mastering private chains is a foundational skill in blockchain engineering.
👉 Discover tools that accelerate blockchain development workflows.