Ethereum: Deploy on a Private Blockchain

truffle, geth, and private blockchains

A brief introduction to deploying smart contracts on a private blockchain with truffle and geth.

Previously we went through setting up an Ethereum development environment with truffle and testrpc, and deploying a simple smart contract written in Solidity. Now we will take it a step further using truffle and geth to deploy a smart contract on a private blockchain. First, we will use geth to start a single node running locally on Ubuntu, then we’ll use truffle to deploy our smart contract.

For these steps I’m running Ubuntu 16 in VirtualBox on Windows 10, as described here.


Check out these previous articles which describe setting up the dev environment and other tools I’ll be using:

If you’re using Atom on Windows 10, the following articles may be useful for editing files on a remote Ubuntu server:

Install geth

First we need to install geth on our Ubuntu machine. These steps are from the documentation:

sudo apt-get install software-properties-common
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install ethereum

That’s the basic geth install done.

Initialise the private blockchain with the genesis block

Next we need to initialise the private blockchain with a genesis block.

The article article at the link below has a good explanation of this process. The geth steps are a bit out of date, but the surrounding explanations are still valuable.

Let’s go through it quickly:

  1. Create a new directory to work from, then create the genesis.json file.

    mkdir geth && cd geth
    mkdir privchain
    touch genesis.json
  2. Edit the genesis.json file and type or paste the following:

        "nonce": "0x0000000000220042",
        "timestamp": "0x0",
        "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
        "extraData": "0x0",
        "gasLimit": "0x8000000",
        "difficulty": "0x400",
        "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
        "coinbase": "0x3333333333333333333333333333333333333333",
        "alloc": {

    Now we’re ready to initialise the blockchain. Note that some of the tools we’re using are bleeding edge, and evolving quickly. As a result, information quickly goes out of date.

  3. To initialise the blockchain. open a new terminal and enter

    geth --datadir privchain init genesis.json


    ...WARNING: No etherbase set and no accounts found as default
    ...Allotted 128MB cache and 1024 file handles to /home/someone/privchain/geth/chaindata
    ...closed db:/home/someone/privchain/geth/chaindata
    ...Allotted 128MB cache and 1024 file handles to /home/someone/privchain/geth/chaindata
    ...successfully wrote genesis block and/or chain rule set: 6650a0ac6c5e805475...

    This should generate a new folder privchain with stuff inside it.

Start a node with geth

Next we use geth to start the first node on our private network. Since this is a private blockchain, it will be the only node for now.

  1. Type the following to start the node using the initialised genesis block:

    geth --port 3000 --networkid 58342 --nodiscover --datadir="privchain" --maxpeers=0 --autodag \
         --rpc --rpcport 8545 --rpcaddr --rpccorsdomain "*" --rpcapi "eth,net,web3" \
         --ipcapi "eth,net,web3"

    --rpcapi "eth,net,web3" is required for geth attach to work (we’ll use this shortly)

    --rpcport 8545 is to be consistent with ethereumjs-testrpc, and make integration with truffle easier

    --rpcapi "eth,net,web3" is required for web3 to work in truffle

    Read more about the geth command line options here:

    After starting the geth node you should see something like IPC endpoint opened: /home/someone/privchain/geth.ipc

  2. Next we attach to the geth console. Open a new terminal window and type:

    geth attach ipc://home/someone/privchain/geth.ipc
  3. Then create an account to use

    > personal.newAccount('password')
  4. Lastly, verify the new account is your default.

    > personal.listAccounts
    > web3.eth.coinbase

    These two commands should both return the same address, which should match the account created in the previous step.

Prepare to deploy a contract using truffle

For this step I’ll assume you already have a truffle project with a contract you’d like to deploy (if not, check out my earlier article). Before we can actually deploy the contract, there are a few things we need to do first (these are the sorts of things testrpc usally takes care of for us).

  1. If we were to open a new terminal, cd to our truffle project, and run truffle migrate, we’d probably get an error:

    Deploying Migrations...
    Error encountered, bailing. Network state unknown. Review successful transactions manually.
    Error: authentication needed: password or unlock

    We need to unlock the account so truffle can deploy the contract. Refer also

  2. In the geth console, enter the following to unlock the default account, ensuring to replace password with the value entered when the account was created previously.

    > personal.unlockAccount(web3.eth.coinbase, "password", 15000)

    But still, if we were to run truffle compile again, we’d probably get another error:

    Deploying Migrations...
    Error encountered, bailing. Network state unknown. Review successful transactions manually.
    Error: Insufficient funds for gas * price + value
  3. We seem to be making progress, and this error indicates we don’t have any ether at our default address. We can start mining briefly on our private network to create some Ether. Type the following into the geth console.

    > miner.start()

    Now back in the first terminal, where we started the geth node, you should start to see output like:

    Generating DAG for epoch 0 (size 1073739904) (000000000000000000000000000000000000000...)
    ...Generating DAG: 0%
    ...Generating DAG: 1%
    ...Generating DAG: 2%

    This could take a while to run, but you can pass the time by reading about the DAG:

    Also note that if you’re running your geth node for extended periods of time, i.e longer than 30000 blocks, using --autodag to enable automatic DAG pregeneration can help speed things up.

  4. Eventually you’ll see the mining start:

    ...Generating DAG: 100%
    ...Done generating DAG for epoch 0, it took 8m16.297777249s
    ... 🔨  mined potential block #1 [ab929aa6…], waiting for 5 blocks to confirm
    ... commit new work on block 2 with 0 txs & 0 uncles. Took 271.899µs
    ... 🔨  mined potential block #2 [04beaa19…], waiting for 5 blocks to confirm
  5. Let it run for a few minutes, then return to the second terminal running geth console and make sure you’ve got some ether.

    > miner.stop()
    > web3.fromWei(eth.getBalance(eth.coinbase), "ether")
  6. Now we’re ready to deploy our contract. Make sure to start mining again, otherwise the transaction with our contract will not be included in a block:

    > miner.start()

    And unlock the account again (this times out)

    > personal.unlockAccount(web3.eth.coinbase, "password", 15000)
  7. In a third terminal window, run truffle migrate from you truffle project directory

    truffle migrate


    Using network 'development'.
    Running migration: 1_initial_migration.js
        Replacing Migrations...
        Migrations: 0x1a8c52f9f20aa0eea656fffe07...
    Saving successful migration to network...
    Saving artifacts...
    Running migration: 2_deploy_contracts.js
        Replacing [[ContractName]]...
        [[ContractName]]: 0x27890f0f20a99dc85742759cdf...
    Saving successful migration to network...
    Saving artifacts...
  8. Now start truffle console

    truffle console
    > web3.eth.accounts
    > ContractName.deployed()

We should be able to interact normally with the contract.

If you are sending a transaction or trying to change the state of the blockchain, make sure at least one miner is running on your private network, otherwise the transaction will not be included in a block. If you need more than one account for testing, you’ll need to make sure they have some ether too, and that it’s unlocked when neccessary. It makes you appreciate testrpc!

In the next article, we will setup a block explorer running against our private network.


This section contains help for some common errors and provides possible resolutions:

Problem: No default account

The error when using truffle migrate:

config.networks[].from = accounts[0];
TypeError: Cannot read property '0' of null

Make sure you have a default account configured. In geth console, enter the following to list your accounts:

> personal.listAccounts()

or, alternatively

> web3.eth.coinbase
> web3.eth.accounts

If these return null, or an error, try setting up a new account:

> personal.newAccount('password')

Then try listing your account again with web3.eth.accounts. You can also view your accounts in the truffle console:

truffle console
> web3.eth.accounts

Which should return the same as the geth console.

Problem: Account is locked

The error when using truffle migrate:

Deploying Migrations...
Error encountered, bailing. Network state unknown. Review successful transactions manually.
Error: authentication needed: password or unlock

Make sure to unlock your account. In the geth console, type:

> personal.unlockAccount(web3.eth.coinbase, "password", 15000)

Also see this page:

Problem: RPC not started on node correctly

The error when using truffle migrate:

Error: The method net_version does not exist/is not available

When starting your geth node, make sure to include net and web3 in the --rpcapi argument, e.g.

  • --rpcapi "eth,net,web3"

Also make sure rpc is enabled when starting the geth node, e.g.

  • --rpc --rpcport 8545 --rpcaddr

Check the settings in truffle.js match up appropriately

Another error you may see is:

Error: The method eth_accounts does not exist/is not available

Similar to previous error, make sure to include eth in the --rpcapi argument.

Problem: truffle migrate seems to hang at “Deploying Migrations…”

Make sure there is at least one miner running on your private network. If not, start one from the geth console:

> miner.start()

and re-run truffle migrate.

You should see your transaction getting mined in the terminal window where geth is running.