description: Setting up private Ethereum networks, the easy way
---
This guide explains how to set up a private network of multiple Geth nodes along with their corresponding [consensus clients](/docs/getting-started/consensus-clients) using [Kurtosis](https://docs.kurtosis.com/basic-concepts), a tool that facilitates running containerized packages. An Ethereum network is private if the nodes are not connected to mainnet or any of the testnets. In this context private only means reserved or isolated, rather than protected or secure. A fully controlled, private Ethereum network is useful as a backend for core developers working on issues relating to networking/blockchain syncing etc. Private networks are also useful for Dapp developers testing multi-block and multi-user scenarios.
<Note>Geth only supports the Ethereum PoS consensus mechanism. This is a permissionless algorithm, meaning anyone who can access the private network and has enough ether (local to that network) can become a validator and propose blocks.</Note>
## Prerequisites {#prerequisites}
To follow the tutorial on this page it is necessary to have a working Kurtosis installation (instructions [here](https://docs.kurtosis.com/install)), as well as [Docker](https://docs.docker.com/get-docker/). It is also helpful to understand Geth fundamentals (see [Getting Started](/docs/getting-started)).
## Private Networks {#private-networks}
A private network is composed of multiple Ethereum nodes that can only connect to each other. There are many details to setting up a fresh PoS network. To name a few: a genesis block must be generated for the execution as well as consensus client. The genesis will also contain the deposit contract which validators will use to stake on the network. Then ELs and CLs must be set-up in a concert off of the genesis files. The Kurtosis [ethereum-package](https://github.com/ethpandaops/ethereum-package) will handle all of that behind the scenes with the ability to costumize where needed.
### Choosing A Network ID {#choosing-network-id}
Ethereum Mainnet has Network ID = 1. There are also many other networks that Geth can connect to by providing alternative Chain IDs, some are testnets and others are alternative networks built from forks of the Geth source code. Providing a network ID that is not already being used by an existing network or testnet means the nodes using that network ID can only connect to each other, creating a private network. A list of current network IDs is available at [Chainlist.org](https://chainlist.org/).
### Basic configuration
Kurtosis runs based off Starlark configurations. Write the following content in a file named `network_params.yaml`:
```yaml
participants:
- el_type: geth
cl_type: lighthouse
count: 2
- el_type: geth
cl_type: teku
network_params:
network_id: "585858"
additional_services:
- dora
```
This describes the structure of the network desired. The network will consist of 3 client pairs (execution and consensus). 2 of them running geth/lighthouse and 1 running geth/teku. Each pair would have an equal number of validators. They all will share a genesis block and will be peered together. It's best to specify a non-conflicting network ID for a private network. If no ID is indicated kurtosis will choose a default one (at the time of writing the default is 3151908).
### Spinning up the network
Once the config is written, it is straightforward to spin up the network. Run the following command:
This indicates ethereum-package as a dependency which defines what the fields above mean. `--image-download always` makes sure the latest images are used always. Running it will produce an output such as the one below on a successful run:
That's it. Kurtosis has started all of the network components that was specified in the config in an enclave. The name of the enclave (i.e. `dusty-soil` for the run above) will be required to interact with the services. By now, the network should have started producing and validating new blocks. To get some insight into each of the clients it's possible to check the logs.
```
> kurtosis service logs dusty-soil el-1-geth-lighthouse
[el-1-geth-lighthouse] INFO [06-04|07:59:05.048] Chain head was updated number=495 hash=2f3200..673eee root=d3d92f..d3bd27 elapsed=3.429333ms
[el-1-geth-lighthouse] INFO [06-04|07:59:13.008] Starting work on payload id=0x03c53477e90934c9
[el-1-geth-lighthouse] INFO [06-04|07:59:17.007] Stopping work on payload id=0x03c53477e90934c9 reason=delivery
[el-1-geth-lighthouse] INFO [06-04|07:59:17.041] Imported new potential chain segment number=496 hash=e995db..f5310d blocks=1 txs=0 mgas=0.000 elapsed=20.254ms mgasps=0.000 snapdiffs=98.81KiB triediffs=454.03KiB triedirty=79.69KiB
[el-1-geth-lighthouse] INFO [06-04|07:59:17.047] Chain head was updated number=496 hash=e995db..f5310d root=36638a..e3c9a9 elapsed=2.198709ms
```
### Block explorer
You might have noticed in the configuration above an additional service called `dora` was requested. [Dora](https://github.com/ethpandaops/dora) is a lightweight block explorer. The kurtosis logs above indicate that dora was successfuly launched as a service and is available at `http://127.0.0.1:54628` to inspect the chain.
### Interacting with geth
The most straightforward to interact with any of the geth nodes is through JSON-RPC. They are started already with the RPC server running and kurtosis has exposed those ports to the host as indicated in the logs. E.g. First geth node can be accessed via `http://127.0.0.1:54589`. Therefor the current block number can be retrieved via:
```
> curl -X POST -H "Content-Type: application/json" --data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}' http://127.0.0.1:54589
{"jsonrpc":"2.0","id":1,"result":"0x332"}
```
In the end the kurtosis services are docker images. It is also possible to get shell access to them and poke around, e.g. load up the console. Kurtosis facilitates the shell access through a command:
This tutorial covered the basics of spinning up a network via Kurtosis. The [ethereum-package](https://github.com/ethpandaops/ethereum-package) has far more features and options than the scope of this tutorial. The [guide](https://ethpandaops.io/posts/kurtosis-deep-dive/) by ethPandaOps also goes over more advanced functionality such as deploying a MEV stack, shadowforking etc.