---
# System prepended metadata

title: How to Run an Ephemery Public Testnet Node with Besu and Teku
tags: [Besu, Ephemery, Teku]

---


# How to Run an Ephemery Public Testnet Node with Besu and Teku

In this tutorial, I’m going to walk you through how I set up an Ephemery testnet node using Besu for the execution layer and Teku for the consensus layer. If you're curious about running your own Ethereum-like beacon chain locally or just want a clean test environment that resets every four weeks, Ephemery is a great choice. I'll show you exactly what I did to get it up and running. Not to mention that went through the process as a normal user. So there is no need for special skills in DevOps, you can do it! 

>[!Note]
This is a beacon node only (without validator duties)!

- Prerequisites
Docker & Docker-Compose installed


## Step 1: Set Up Your Working Directory

Start by creating a project folder:
```bash
mkdir ephemery-node && cd ephemery-node

 ```
 
## Step 2: Download the Latest Ephemery Files

fetch the file and unpack it inside testnet-all folder
```bash
curl -L -o testnet-all.tar.gz https://github.com/ephemery-testnet/ephemery-genesis/releases/latest/download/testnet-all.tar.gz
mkdir testnet-all && tar -xzf testnet-all.tar.gz -C testnet-all
 ```
 
## Step 3: Load the environment variables

```bash
cd testnet-all
source nodevars_env.txt
cd ..
 ``` 
This will give you access to:

- `$BOOTNODE_ENODE` – for Besu
- `$BOOTNODE_ENR_LIST` – for Teku

You can run echo `$BOOTNODE_ENODE` to check the values if needed.
You should now have:

```bash
echo "$BOOTNODE_ENODE"      # e.g. enode://…@IP:30303
echo "$BOOTNODE_ENR_LIST"   # e.g. enr:-… ,enr:-…
echo "$GENESIS_SSZ_PATH"    # genesis.ssz
echo "$CONFIG_YAML_PATH"    # config.yaml
 ```
Create a .env file in the same directory as your docker-compose.yml and paste in the values from your nodevars_env.txt like this(values are real):

```env
BOOTNODE_ENODE=enode://50a54ecbd2175497640bcf46a25bbe9bb4fae51d7cc2a29ef4947a7ee17496cf39a699b7fe6b703ed0feb9dbaae7e44fc3827fcb7435ca9ac6de4daa4d983b3d@137.74.203.240:30303
BOOTNODE_ENR_LIST=enr:-LK4QM7kEZAgPNZmwuEdfS68qxtvXmdY0Uk4mSrflr3gDTFTNAS09cRc-eLE-Gb-1Mc6FqOJgphhAEFDc52Kil2HWOsEh2F0dG5ldHOIAAAAAMAAAACEZXRoMpDOicPBYAAQG___________gmlkgnY0gmlwhIlKy_CJc2VjcDI1NmsxoQNOcwdwpHPZTopFyzuvy2XT2k4Wy4gMbE7e7a1WHLlZo4N0Y3CCI4yDdWRwgiOM,enr:-Iq4QNMYHuJGbnXyBj6FPS2UkOQ-hnxT-mIdNMMr7evR9UYtLemaluorL6J10RoUG1V4iTPTEbl3huijSNs5_ssBWFiGAYhBNHOzgmlkgnY0gmlwhIlKy_CJc2VjcDI1NmsxoQNULnJBzD8Sakd9EufSXhM4rQTIkhKBBTmWVJUtLCp8KoN1ZHCCIyk,enr:-Jq4QKOark9WXFRsOLx4RGwdYrH_YDiK39KP0niQ6D5gagX4Jo7ZxuzPwRN6YWedFhvlWP305qoDq8X4AmQ2PyyW3ukBhGV0aDKQzonDwWAAEBv__________4JpZIJ2NIJpcIRBbZouiXNlY3AyNTZrMaEDSZOVyosoT9D64UUw4_XiFapjaeCsvT0G5Zsnf81gyymDdWRwgiMp,enr:-Iq4QIc297-de1P6hznMX2cIdVsQkve9BD9NUsJ7vVQa7eh5UpekA9rLid5A-yLiS3gZwOGugYZPi58x76zNs2cEQFCGAYhBJlTYgmlkgnY0gmlwhEFtmi6Jc2VjcDI1NmsxoQJDyix-IHa_mVwLBEN9NeG8I-RUjNQK_MGxk9OqRQUAtIN1ZHCCIyg,enr:-OS4QPmu9RBpnkIciCJQCpTCdkZDUdp1Zl259VcYGGz1KinVa9dAWRxC-dK6X8vlRR1kffpQwkeLMzDE_nDtG05mVVYDh2F0dG5ldHOIAAMAAAAAAACGY2xpZW502IpMaWdodGhvdXNljDcuMC4wLWJldGEuN4RldGgykM6Jw8FgABAb__________-CaWSCdjSCaXCEp-sBuYRxdWljgiNRiXNlY3AyNTZrMaECRFTZ7g8SwCvj7Gwa7OSjBb51_pd0v--6Tbto_k9R6qSIc3luY25ldHMAg3RjcIIjUIN1ZHCCI1A
```
## Step 4: Create a JWT Secret File
This is required for Besu and Teku to talk over the Engine API:
```bash
mkdir shared
openssl rand -hex 32 > shared/token.txt
 ```
 

## Step 5: Create docker-compose.yml
Create a file named docker-compose.yml with this content:

```yaml
---
version: "3.4"
services:
  besu_node:
    image: hyperledger/besu:develop
    command:
      [
        "--network=ephemery",
        "--bootnodes=${BOOTNODE_ENODE}",
        "--rpc-http-enabled=true",
        "--rpc-http-cors-origins=*",
        "--rpc-ws-enabled=true",
        "--host-allowlist=*",
        "--engine-host-allowlist=*",
        "--engine-rpc-enabled",
        "--engine-jwt-secret=/shared/token.txt",
        "--p2p-port=30303",
        "--p2p-host=0.0.0.0",
      ]
    volumes:
      - ./besu:/var/lib/besu/data
      - ./shared:/shared
    ports:
      # Map the p2p port(30303), RPC HTTP port(8545), and engine port (8551)
      - "8545:8545"
      - "8551:8551"
      - "30303:30303/tcp"
      - "30303:30303/udp"

  teku_node:
    environment:
      - "JAVA_OPTS=-Xmx4g"
    image: consensys/teku:develop
    command:
        [
          "--network=https://ephemery.dev/latest/config.yaml",
          "--ee-endpoint=http://besu_node:8551",
          "--ee-jwt-secret-file=/shared/token.txt",
          "--metrics-enabled=true",
          "--rest-api-enabled=true",
          "--ignore-weak-subjectivity-period-enabled=true",
          "--checkpoint-sync-url=https://ephemery.beaconstate.ethstaker.cc/",
          "--p2p-advertised-ip=127.0.0.1",
          "--p2p-port=9000",
       "--p2p-discovery-bootnodes=${BOOTNODE_ENR_LIST}",

       ]
    depends_on:
      - besu_node
    volumes:
      - ./teku:/var/lib/teku/data
      - ./shared:/shared
    ports:
      # Map the p2p port(9000) and REST API port(5051)
      - "9000:9000/tcp"
      - "9000:9000/udp"
      - "5051:5051"
```

## Step 6: Start Your Node
Back in the project root inside `ephemery-node` folder, run:

```bash
docker-compose up 
```
Watch logs, you should see:

```Besu → “Starting synchronizer…”

Teku → “Execution Client is online”

Both → gradually “Connected peers: N > 0”

Teku → “Syncing *** Slot: … Head slot: … Remaining slots: …”
```

Screenshots from logs on my running node:

![image (2)](https://hackmd.io/_uploads/Hkr86Lpvxl.png)

![image (3)](https://hackmd.io/_uploads/SJwJZwpPel.png)

>[!Warning]
>I've got this :point_down:  error in the screenshot below when entered `ephemery` as network for Teku command options. so you better enter the url as the value for network.



![image](https://hackmd.io/_uploads/S1gAfDpvlx.png)

Running Ephemery is a bit tricky here, at least for now. hopefully soon in future I will check into Teku codebase see why this error arises.


>[!Tip]
Some tips if you got problem with running with above inputs: 


- Running this command should show your head state and attestations.

 ```bash
curl -s localhost:5051/eth/v1/beacon/states/head/finality_checkpoints
```

- Check your bootnodes / ENR_LIST are correct.

- Ensure UDP/TCP ports (30303, 9000) are open in Docker and firewall.

- Try explicit host IP instead of 0.0.0.0 or 127.0.0.1  for advertised-ip.

- The valu for `engine-jwt-secret` should point at the same `/shared/token.txt`.

- If no peer, copy and paste the values for `--bootnodes` and `--p2p-discovery-bootnodes` from the testnet-all folder directly into the docker-compose file.

If you have any question I would be glad to help!

Happy testing!🥳