Using Truffle with Geth Instead of Ganache
So, as a real blockchain developer, you will sooner or later want to test your smart contract in an environment that closely resembles a real blockchain. Ganache, an in-memory blockchain emulator, only takes you so far. In this case, you're going to use Go Ethereum (Geth) and most likely Truffle for writing, testing, and deploying your contracts.
Using Ganache + Truffle is easy. They feel like they were made for each other. But pairing Truffle + Geth often brings issues. In this post, I'll walk you through solving the problems I encountered.
Environment Setup
| Item | Value |
|---|---|
| Go Ethereum (geth) | 1.10.19-stable (ARM64 build) |
| Truffle | 5.5.18 |
| Goal | Deploy smart contracts through Truffle to Geth and be able to interact with them. |
Geth Command
geth --networkid 4224 --mine --miner.threads 1 --datadir "./private" --nodiscover -port "30303" --nat "any" \
--http --http.api personal,eth,net,web3 \
--ws --ws.api personal,eth,net,web3 \
--password ./private/password.sec --ipcpath "~/Library/Ethereum/geth.ipc"
Notice the --password flag. It points to a password file for unlocking the account securely.
Truffle Configuration (truffle-config.js)
geth: {
host: "127.0.0.1",
port: 8545,
network_id: 4224,
from: '0x6db7f74b66403832fc2cfa40d6ee79f1b6915e37',
}
Create this account using:
geth --datadir . account new
You can skip the password prompt or use a file.
The Problem
Running:
truffle migrate --network geth

Results in an authentication error.
Solution: unlock the account
Add --allow-insecure-unlock to your Geth command:
geth ... --allow-insecure-unlock
Modify the Truffle migration script
Update migrations/1_initial_migration.js:
const Migrations = artifacts.require('Migrations');
const TruffleConfig = require('../truffle-config');
const Web3 = require('web3');
module.exports = function (deployer, network, accounts) {
const config = TruffleConfig.networks[network];
if (process.env.ACCOUNT_PASSWORD) {
const web3 = new Web3(new Web3.providers.HttpProvider(`http://\${config.host}:\${config.port}`));
web3.eth.personal.getAccounts().then((accounts) => {
const defaultAccount = accounts[0];
console.log(`[x] Unlocking account \${defaultAccount}`);
web3.eth.personal.unlockAccount(defaultAccount, process.env.ACCOUNT_PASSWORD);
});
}
console.log('[x] Making migrations');
deployer.deploy(Migrations);
};
Option 2: unlock in Geth console
- Start Geth
- In another terminal:
geth attach

- Then:
personal.unlockAccount('0x6db7f74b66403832fc2cfa40d6ee79f1b6915e37', 'your_password');
- Re-run the migration:
truffle migrate --network geth

You're good to go!
Related
Posts
OpenZeppelin Pausable: The Kill Switch for Your Smart Contract
When the mechanisms you designed into a contract fail, one is left: the switch. OpenZeppelin gives you Pausable for that, and you should never skip it.

AllYouNeedIsNFT: Image Uniqueness Checks and a Generative NFT Editor
Two tools from the AllYouNeedIsNFT marketplace: a service that scores a new NFT image against indexed collections, and an editor that assembles collages from one artist's assets.
Devconnect Argentina 2025 in Buenos Aires: Vitalik, the Ethereum World’s Fair and Key Announcements
My week at Devconnect Argentina 2025, the first Ethereum World’s Fair: Vitalik Buterin, Kohaku, 1inch Aqua, Nym, Flashbots, Geth and the main announcements.
Open for contract collaboration
I am available for contract-based collaboration. If you have an interesting project idea, schedule a call via Calendly.
Schedule a 30-min call