A simple, reliable Ethereum testnet deployment using Geth in dev mode for development and testing purposes.
- Docker installed on your system
- Node.js (for running deployment scripts)
- Git (for version control)
Start the Ethereum testnet node with a single command:
docker run -d \
--name eth-node \
-p 8545:8545 \
-p 8546:8546 \
ethereum/client-go:latest \
--dev \
--dev.period 1 \
--http \
--http.addr "0.0.0.0" \
--http.port 8545 \
--http.api "eth,net,web3,personal,admin,miner,debug,txpool" \
--http.corsdomain "*" \
--http.vhosts "*" \
--ws \
--ws.addr "0.0.0.0" \
--ws.port 8546 \
--ws.api "eth,net,web3,personal,admin,miner,debug,txpool" \
--ws.origins "*" \
--verbosity 3Wait 10-15 seconds for the node to start, then verify:
curl -X POST http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'The repository includes a GitHub Actions workflow that automatically deploys the testnet on push or manual trigger.
Workflow file: .github/workflows/deploy-eth-node.yml
To trigger manually or simply push from CLI:
- Go to your repository on GitHub
- Click "Actions" tab
- Select "Deploy Ethereum Testnet"
- Click "Run workflow"
- RPC Endpoint:
http://localhost:8545 - WebSocket Endpoint:
ws://localhost:8546 - Chain ID:
1337(dev mode default) - Block Time: 1 second
- Pre-funded Account:
0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
The node exposes the following JSON-RPC APIs:
eth- Ethereum-related methodsnet- Network informationweb3- Web3 utilitiespersonal- Account managementadmin- Node administrationminer- Mining controldebug- Debugging toolstxpool- Transaction pool inspection
Start the node:
docker run -d --name eth-node -p 8545:8545 -p 8546:8546 ethereum/client-go:latest --dev --dev.period 1 --http --http.addr "0.0.0.0" --http.port 8545 --http.api "eth,net,web3,personal,admin,miner,debug,txpool" --http.corsdomain "*" --http.vhosts "*" --ws --ws.addr "0.0.0.0" --ws.port 8546 --ws.api "eth,net,web3,personal,admin,miner,debug,txpool" --ws.origins "*"Stop the node:
docker stop eth-nodeRemove the node:
docker rm eth-nodeView logs:
docker logs -f eth-nodeCheck node status:
docker ps | grep eth-nodeGet current block number:
curl -X POST http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'Get account balance:
curl -X POST http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266","latest"],"id":1}'Get network ID:
curl -X POST http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"net_version","params":[],"id":1}'Symptoms:
Fatal: Failed to write genesis block: invalid chain configuration in blobSchedule for fork "cancun": update fraction must be defined and non-zero
Cause: Using custom genesis.json with newer Geth versions that require complete blob schedule configuration.
Solution:
- Remove any custom genesis.json files
- Remove docker-compose.yml if it contains genesis initialization
- Use pure
--devmode (no custom genesis needed) - Clean up old data:
docker stop eth-node docker rm eth-node docker volume prune -f
Symptoms:
FetchError: request to http://localhost:8545/ failed, reason: connect ECONNREFUSED 127.0.0.1:8545
Cause: Ethereum node is not running or not ready yet.
Solution:
- Check if container is running:
docker ps | grep eth-node - If not running, start it with the docker run command above
- Wait 10-15 seconds for the node to fully initialize
- Check logs for errors:
docker logs eth-node
Symptoms:
invalid command: "sh"
invalid command: "geth"
Cause: Using shell wrapper commands (sh -c) with the geth Docker image.
Solution: Pass geth flags directly without shell wrappers. Use the command format shown in Quick Start.
Symptoms:
ERROR: Geth only supports PoS networks. Please transition legacy networks using Geth v1.13.x.
Fatal: Failed to register the Ethereum service: 'terminalTotalDifficulty' is not set in genesis block
Cause: Using old PoW (Proof of Work) genesis configuration with newer Geth that only supports PoS (Proof of Stake).
Solution:
Use --dev mode which automatically configures everything correctly. Avoid custom genesis files.
Symptoms:
flag provided but not defined: -miner.threads
Cause: The --miner.threads flag was removed in newer Geth versions.
Solution:
Remove the --miner.threads flag from your command. Dev mode handles mining automatically.
Symptoms: Container starts but exits with code 1 immediately.
Cause: Usually due to configuration errors or conflicting flags.
Solution:
- Check logs:
docker logs eth-node
- Ensure you're not mixing
--devwith custom genesis - Remove any old volumes:
docker volume rm $(docker volume ls -q | grep eth)
Symptoms: Workflow shows genesis-related errors even though local deployment works.
Cause: Old workflow file with embedded genesis configuration.
Solution:
Update .github/workflows/deploy-eth-node.yml to use the simplified dev mode approach (see Quick Start section).
If you're experiencing persistent issues, do a complete cleanup:
# Stop all containers
docker stop $(docker ps -aq)
# Remove all containers
docker rm $(docker ps -aq)
# Remove all volumes
docker volume prune -f
# Remove all unused images
docker system prune -a --volumes -f
# Start fresh
docker run -d --name eth-node -p 8545:8545 -p 8546:8546 ethereum/client-go:latest --dev --dev.period 1 --http --http.addr "0.0.0.0" --http.port 8545 --http.api "eth,net,web3,personal,admin,miner,debug,txpool" --http.corsdomain "*" --http.vhosts "*" --ws --ws.addr "0.0.0.0" --ws.port 8546 --ws.api "eth,net,web3,personal,admin,miner,debug,txpool" --ws.origins "*"If you need data to persist across restarts:
mkdir -p ./eth-data
docker run -d \
--name eth-node \
-p 8545:8545 \
-p 8546:8546 \
-v $(pwd)/eth-data:/data \
ethereum/client-go:latest \
--dev \
--dev.period 1 \
--datadir /data \
--http \
--http.addr "0.0.0.0" \
--http.port 8545 \
--http.api "eth,net,web3,personal,admin,miner,debug,txpool" \
--http.corsdomain "*" \
--http.vhosts "*" \
--ws \
--ws.addr "0.0.0.0" \
--ws.port 8546 \
--ws.api "eth,net,web3,personal,admin,miner,debug,txpool" \
--ws.origins "*"Modify --dev.period value (in seconds):
--dev.period 5 # 5 second blocks
--dev.period 0 # Instant blocks (mines only when transactions are pending)--allow-insecure-unlockis enabled- No authentication on RPC endpoints
- CORS is wide open (
*) - No network security
- Private keys are not secured
This project is open source and available under the MIT License.
Contributions, issues, and feature requests are welcome!
If you encounter issues not covered in this README:
- Check the Troubleshooting section
- Review container logs:
docker logs eth-node - Open an issue with detailed error messages and steps to reproduce