# ethereum-rpc-docker — Blockchain RPC Node Configurations

**ethereum-rpc-docker** provides production-ready Docker Compose configurations for running
blockchain RPC nodes. Whether you're running a single Ethereum node or a fleet of L2s,
this repository has everything you need to get started quickly.

For **debugging and troubleshooting**, see [VIBE.md](VIBE.md) — the automated operations guide.

---

## 1. What This Repository Is

This is a collection of Docker Compose files and supporting scripts for operating blockchain
RPC nodes. Each compose file defines a complete node configuration including:

- **Client** (execution layer): Geth, Erigon, Reth, Nethermind, Besu, etc.
- **Node** (consensus layer): op-node, lighthouse, prysm, nitro, etc.
- **Relay** (data availability): eigenda-proxy, op-alt, celestia, etc.
- **Proxy** (access layer): nginx for HTTP/WS unification
- **Monitoring**: Prometheus metrics, Grafana dashboards

You can run a single node or combine multiple compose files to create a full fleet.

---

## 2. Quick Start

### Prerequisites

- Docker and Docker Compose installed
- Docker daemon running
- Public IP address (for P2P connectivity)
- At least 500GB free disk for Ethereum mainnet pruned nodes

### Step 1: Create Your Environment File

Create a `.env` file in this directory. Here's a complete example:

```bash
# === REQUIRED: Network Settings ===
# Your public IP address (required for P2P on most chains)
IP=203.0.113.42

# Docker internal subnet for chain containers
CHAINS_SUBNET=192.168.0.0/26

# === REQUIRED: SSL Settings ===
# Domain for Traefik SSL certificates (use traefik.me for testing)
DOMAIN=203-0-113-42.traefik.me

# Email for Let's Encrypt notifications
MAIL=your-email@example.com

# IP whitelist (CIDR notation, 0.0.0.0/0 allows all)
WHITELIST=0.0.0.0/0

# === OPTIONAL: SSL ===
# Disable SSL for local testing (remove for production)
# NO_SSL=true

# === OPTIONAL: Fallback RPC Endpoints ===
# These are used by nodes for initial sync and as fallbacks
ETHEREUM_MAINNET_EXECUTION_RPC=https://ethereum-rpc.publicnode.com
ETHEREUM_MAINNET_EXECUTION_WS=wss://ethereum-rpc.publicnode.com
ETHEREUM_MAINNET_BEACON_REST=https://ethereum-beacon-api.publicnode.com

ETHEREUM_SEPOLIA_EXECUTION_RPC=https://ethereum-sepolia-rpc.publicnode.com
ETHEREUM_SEPOLIA_EXECUTION_WS=wss://ethereum-sepolia-rpc.publicnode.com

ARBITRUM_SEPOLIA_EXECUTION_RPC=https://arbitrum-sepolia-rpc.publicnode.com
```

**To get your public IP:**
```bash
curl ipinfo.io/ip
```

**For traefik.me domain:** Replace dots with hyphens in your IP:
```bash
IP=203.0.113.42
DOMAIN=203-0-113-42.traefik.me
```

### Step 2: Select Which Nodes to Run

Add compose files to the `COMPOSE_FILE` variable in your `.env`. Always include
`base.yml` and `rpc.yml` first, then add your node configurations:

```bash
# Example: Run Ethereum mainnet with Geth (pruned)
COMPOSE_FILE=base.yml:rpc.yml:ethereum-mainnet-geth-pruned.yml

# Example: Run multiple nodes
COMPOSE_FILE=base.yml:rpc.yml:ethereum-mainnet-geth-pruned.yml:arbitrum-one.yml:optimism-mainnet.yml

# Example: Include monitoring
COMPOSE_FILE=base.yml:rpc.yml:monitoring.yml:ethereum-mainnet-geth-pruned.yml
```

### Step 3: Start Your Nodes

```bash
# Start all configured nodes
docker compose up -d

# Check status of all nodes
./show-status.sh

# View logs for a specific node
./logs.sh ethereum-mainnet-geth-pruned
```

### Step 4: Access Your RPC Endpoints

Once your nodes are running, access them at:

```
# HTTPS (via Traefik)
https://<your-domain>/ethereum-mainnet-geth-pruned

# HTTP (if NO_SSL=true)
http://<your-domain>/ethereum-mainnet-geth-pruned

# WebSocket
wss://<your-domain>/ethereum-mainnet-geth-pruned
```

---

## 3. Configuration Guide

### Environment Variables Reference

#### Required Variables

| Variable | Description | Example |
|---|---|---|
| `IP` | Your public IP address | `203.0.113.42` |
| `DOMAIN` | Your domain for SSL | `203-0-113-42.traefik.me` |
| `MAIL` | Email for Let's Encrypt | `admin@example.com` |
| `COMPOSE_FILE` | Which compose files to load | `base.yml:rpc.yml:ethereum-mainnet.yml` |

#### Optional Variables

| Variable | Description | Default |
|---|---|---|
| `WHITELIST` | IP whitelist (CIDR) | `0.0.0.0/0` (all) |
| `CHAINS_SUBNET` | Docker network subnet | `192.168.0.0/26` |
| `NO_SSL` | Disable SSL | Not set (SSL enabled) |

#### Chain-Specific Variables

These are automatically used by nodes that support them:

| Variable | Description |
|---|---|
| `ETHEREUM_*_EXECUTION_RPC` | Fallback JSON-RPC endpoint |
| `ETHEREUM_*_EXECUTION_WS` | Fallback WebSocket endpoint |
| `ETHEREUM_*_BEACON_REST` | Fallback Beacon API endpoint |
| `OP_NODE_NETWORK` | OP Stack network identifier |
| `OP_NODE_L1_RPC_URL` | L1 RPC endpoint for OP Stack |

### Static Compose Files

These files provide infrastructure and should always be included:

| File | Purpose | Required? |
|---|---|---|
| `base.yml` | Base Docker networking | ✅ Yes |
| `rpc.yml` | RPC gateway configuration | ✅ Yes |
| `monitoring.yml` | Prometheus + Grafana stack | ❌ No |
| `prometheus.yml` | Prometheus configuration | ❌ No |
| `nodeexporter.yml` | Node metrics exporter | ❌ No |
| `cadvisor.yml` | Container metrics | ❌ No |
| `drpc.yml` | DRPC gateway | ❌ No |
| `drpc-free.yml` | DRPC free tier | ❌ No |
| `backup-http.yml` | Backup HTTP server | ❌ No |
| `logging-proxy.yml` | Logging infrastructure | ❌ No |
| `portainer.yml` | Portainer UI | ❌ No |
| `benchmark-proxy.yml` | Latency testing | ❌ No |

---

## 4. Available Networks

### Layer 1 Networks

#### Major Networks
- **Ethereum**: Mainnet, Sepolia, Holesky
- **BSC** (Binance Smart Chain): Mainnet
- **Polygon**: Mainnet, Amoy
- **Avalanche**: C-Chain Mainnet
- **Gnosis**: Mainnet, Chiado

#### Alternative L1s
- **Fantom**: Mainnet, Testnet
- **Core**: Mainnet
- **Berachain**: Mainnet, Testnet
- **Ronin**: Mainnet
- **Viction**: Mainnet
- **Fuse**: Mainnet
- **Tron**: Mainnet
- **ThunderCore**: Mainnet

#### Emerging L1s
- **Goat**: Mainnet, Testnet
- **AlephZero**: Mainnet
- **Haqq**: Mainnet, Testnet
- **Taiko**: Mainnet
- **Rootstock**: Mainnet

### Layer 2 Networks

#### OP Stack
- Optimism: Mainnet, Sepolia
- Base: Mainnet, Sepolia
- Zora: Mainnet
- Mode: Mainnet
- Blast: Mainnet
- Fraxtal: Mainnet
- Bob: Mainnet
- Boba: Mainnet, Testnet
- Worldchain: Mainnet
- Metal: Mainnet
- Ink: Mainnet
- Lisk: Mainnet, Sepolia
- SNAX: Mainnet
- Celo: Mainnet

#### Arbitrum Ecosystem
- Arbitrum One: Mainnet
- Arbitrum Nova: Mainnet
- Everclear: Mainnet
- Playblock: Mainnet
- Real: Mainnet
- Connext: Mainnet
- OpenCampusCodex: Mainnet

#### Other L2s
- Linea: Mainnet
- Scroll: Mainnet, Sepolia
- zkSync Era: Mainnet
- Metis: Mainnet
- Moonbeam: Mainnet
- Starknet: Mainnet
- zkEVM: Mainnet
- Immutable zkEVM: Mainnet
- Polygon zkEVM: Mainnet

### Node Types Available

For most networks, you can choose from:

| Sync Mode | Database | Client | Use Case |
|---|---|---|---|
| Pruned | Various | Geth, Erigon, Reth | Standard production |
| Archive | Various | Geth, Erigon, Reth | Full history, analytics |
| Archive-Trace | Various | Reth, Erigon | Full history + transaction tracing |

---

## 5. Accessing Your Nodes

### URL Patterns

Each node is accessible via Traefik reverse proxy at:

```
https://<your-domain>/<config-name>
```

Where `<config-name>` is the compose filename without `.yml`, e.g.:
- `ethereum-mainnet-geth-pruned`
- `op-base-sepolia-op-reth-pruned-trace`
- `arbitrum-one-arbnode-archive`

### Ports

| Service | Port | Protocol | Notes |
|---|---|---|---|
| Traefik HTTP | 80 | TCP | Redirects to HTTPS |
| Traefik HTTPS | 443 | TCP | SSL termination |
| Docker internal | Various | TCP/UDP | P2P and internal communications |

**Note:** P2P ports are randomized to avoid conflicts. Check your compose file
for specific port mappings.

### Local Access (Without SSL)

For local development/testing, set `NO_SSL=true` in your `.env`:

```bash
# Access locally without SSL
echo "NO_SSL=true" >> .env
docker compose up -d

# Then access at:
http://localhost:<port>
```

Find the port in your compose file or use:
```bash
./get-local-url.sh <config-name>
```

---

## 6. Resource Requirements

### Hardware Recommendations

| Node Type | Disk | RAM | CPU | Notes |
|---|---|---|---|---|
| Ethereum Pruned | 500GB - 1TB | 8GB | 2+ cores | Standard production |
| Ethereum Archive | 2TB - 4TB | 16GB+ | 4+ cores | Full history |
| Ethereum Archive-Trace | 4TB - 8TB | 32GB+ | 8+ cores | Full + tracing |
| BSC Pruned | 500GB - 800GB | 8GB | 2+ cores | |
| BSC Archive | 2TB - 3TB | 16GB | 4+ cores | |
| Polygon Pruned | 300GB - 500GB | 8GB | 2+ cores | |
| Polygon Archive | 1TB - 2TB | 16GB | 4+ cores | |
| L2 Pruned (OP Stack) | 100GB - 300GB | 4-8GB | 2+ cores | Base, Optimism, etc. |
| L2 Archive (OP Stack) | 500GB - 1TB | 8-16GB | 4+ cores | |
| L2 Pruned (Arbitrum) | 200GB - 500GB | 4-8GB | 2+ cores | |
| L2 Archive (Arbitrum) | 1TB - 2TB | 8-16GB | 4+ cores | |

### Storage Recommendations

- **Use SSD or NVMe**: HDDs are too slow for blockchain nodes
- **Separate volumes**: Consider separating chain data from OS
- **Monitor usage**: Use `./show-db-size.sh` to track growth
- **Plan for growth**: Archive nodes grow ~1-2GB/day for Ethereum

### Performance Tips

- **CPU**: More cores = faster sync, but diminishing returns after 8 cores
- **RAM**: Archive nodes need sufficient RAM for state
- **Disk I/O**: NVMe > SSD > HDD. RAID 0 can help for multiple nodes
- **Network**: 1Gbps+ recommended for multiple nodes

---

## 7. SSL Certificates and Domain Setup

### Traefik.me (Testing/Development)

For quick testing, use the free traefik.me service:

```bash
# Get your IP
IP=$(curl -s ipinfo.io/ip)

# Create domain by replacing dots with hyphens
DOMAIN=$(echo $IP | tr . -).traefik.me

# Add to .env
echo "DOMAIN=$DOMAIN" >> .env
echo "MAIL=your-email@example.com" >> .env
```

Traefik.me automatically provides valid SSL certificates. No additional setup needed.

### Let's Encrypt (Production)

For production, use your own domain with Let's Encrypt:

```bash
# Set your domain
DOMAIN=yourdomain.com

# Set your email for notifications
MAIL=admin@yourdomain.com

# Add to .env
echo "DOMAIN=$DOMAIN" >> .env
echo "MAIL=$MAIL" >> .env
```

Traefik will automatically obtain and renew certificates from Let's Encrypt.

### Disabling SSL

For local development, you can disable SSL:

```bash
# In .env
echo "NO_SSL=true" >> .env

# Then restart
docker compose up -d
```

---

## 8. DRPC Integration — Monetize Your RPC

[DRPC](https://drpc.org/) allows you to sell excess RPC capacity and earn revenue.

### Quick Setup

1. **Enable DRPC in your `.env`:**
   ```bash
   # Add to .env
   GW_DOMAIN=your-gateway-domain.com
   GW_REDIS_RAM=2gb
   DRPC_VERSION=0.64.16
   ```

2. **Add DRPC to COMPOSE_FILE:**
   ```bash
   COMPOSE_FILE=base.yml:rpc.yml:drpc.yml:ethereum-mainnet-geth-pruned.yml
   ```

3. **Generate upstreams configuration:**
   ```bash
   ./upstreams.sh
   ```

The `upstreams.sh` script automatically detects all running nodes on your machine and
generates the configuration for the dshackle load balancer.

### Configuration Options

| Variable | Description | Default |
|---|---|---|
| `GW_DOMAIN` | Your gateway domain | Required |
| `GW_REDIS_RAM` | Redis memory limit | `2gb` |
| `DRPC_VERSION` | DRPC version to use | Latest |

### Multi-Server Setup

For running DRPC across multiple servers:

1. On each server, run nodes with DRPC enabled
2. On your gateway server, run `./upstreams.sh` to generate combined config
3. Deploy the dshackle configuration to your gateway

For more information, visit [drpc.org](https://drpc.org/).

---

## 9. Backup and Restore System

### Why Backups Matter

- **Database corruption**: Power loss or bugs can corrupt your chain data
- **Quick recovery**: Restore from backup instead of re-syncing from scratch
- **Migration**: Move nodes between servers efficiently
- **Cloning**: Create identical nodes for redundancy

### Local Backups

```bash
# Create a backup of a node
./backup-node.sh ethereum-mainnet-geth-pruned

# Backup is stored in /backup directory
# List available backups
./list-backups.sh

# Restore from latest backup
./restore-volumes.sh ethereum-mainnet-geth-pruned
```

### Remote Backups (WebDAV)

For multi-server setups, use WebDAV for remote backups:

```bash
# Backup to remote WebDAV
./backup-node.sh ethereum-mainnet https://backup-server.tld/dav

# Restore from remote WebDAV
./restore-volumes.sh ethereum-mainnet https://backup-server.tld/backup/
```

### HTTP Backup Server

Expose your backups via HTTP for easy access:

```bash
# Add to COMPOSE_FILE
COMPOSE_FILE=base.yml:rpc.yml:backup-http.yml:ethereum-mainnet.yml

# Access backups at:
# - HTTP: https://yourdomain.tld/backup
# - WebDAV: https://yourdomain.tld/dav
```

### Cross-Server Transfers

Transfer node data between servers without SSH:

```bash
# On Server A (source):
./backup-node.sh ethereum-mainnet https://server-a.domain.tld/dav

# On Server B (destination):
./restore-volumes.sh ethereum-mainnet https://server-a.domain.tld/backup/
```

### Cloning Nodes

Clone a running node to create a replica:

```bash
# Clone node state
./clone-node.sh ethereum-mainnet-geth-pruned

# Clone peer connections (faster sync)
./clone-peers.sh ethereum-mainnet-geth-pruned
```

---

## 10. Security and Network Configuration

### Firewall Configuration

Many chains require specific ports for P2P discovery. Docker will bind to these
ports on all interfaces (0.0.0.0).

**Critical:** You must configure your firewall to:
1. Allow inbound connections to P2P ports (UDP/TCP)
2. Allow outbound connections from containers
3. Block containers from reaching local networks (security)

### iptables Rules

Here's a systemd service and script for managing Docker firewall rules:

**`/etc/systemd/system/iptables-firewall.service`:**
```ini
[Unit]
Description= iptables firewall docker fix
After=docker.service

[Service]
ExecStart=/usr/local/bin/iptables-firewall.sh start
RemainAfterExit=true
StandardOutput=journal

[Install]
WantedBy=multi-user.target
```

**`/usr/local/bin/iptables-firewall.sh`:**
```bash
#!/bin/bash
PATH="/sbin:/usr/sbin:/bin:/usr/bin"

# Flush existing rules
iptables -F DOCKER-USER

# Block local networks from containers
# (prevents containers from reaching your LAN)
iptables -I DOCKER-USER -s {{ chains_subnet }} -d 192.168.0.0/16  -j REJECT
iptables -I DOCKER-USER -s {{ chains_subnet }} -d 172.16.0.0/12 -j REJECT
iptables -I DOCKER-USER -s {{ chains_subnet }} -d 10.0.0.0/8 -j REJECT

# Allow containers to reach each other
iptables -I DOCKER-USER -s {{ chains_subnet }} -d {{ chains_subnet }} -j ACCEPT

# Allow specific external networks if needed
iptables -I DOCKER-USER -s {{ chains_subnet }} -d 10.13.13.0/24 -j ACCEPT
```

Replace `{{ chains_subnet }}` with your `CHAINS_SUBNET` value (default: `192.168.0.0/26`).

### IP Whitelist

Control which IPs can access your RPC endpoints:

```bash
# In .env - allow all
WHITELIST=0.0.0.0/0

# Allow specific IPs
WHITELIST=192.0.2.0/24,203.0.113.0/24

# Update whitelist without restart
./update-whitelist.sh
```

---

## 11. Daily Operations

### Starting and Stopping Nodes

```bash
# Start a specific node
./start.sh ethereum-mainnet-geth-pruned

# Stop a specific node
./stop.sh ethereum-mainnet-geth-pruned

# Restart a node (keeps volumes)
./force-recreate.sh ethereum-mainnet-geth-pruned
```

### Monitoring Node Health

```bash
# Check all nodes
./show-status.sh

# Check specific node
./sync-status.sh ethereum-mainnet-geth-pruned

# Get latest block
./latest.sh ethereum-mainnet-geth-pruned

# Check disk usage
./show-db-size.sh

# Check memory usage
./show-ram.sh ethereum-mainnet-geth-pruned
```

### Viewing Logs

```bash
# View logs for a node
./logs.sh ethereum-mainnet-geth-pruned

# View logs with follow
./logs.sh ethereum-mainnet-geth-pruned -f

# View all container logs
docker compose logs -f
```

### Checking Peers

```bash
# Check peer count for all nodes
./peer-count.sh

# Check specific node peers
./peer-count.sh | grep ethereum-mainnet
```

---

## 12. Node Structure and Naming

### Understanding Node Components

A typical node consists of one or more of these components:

| Component | Purpose | Example Implementations |
|---|---|---|
| **Client** | Execution layer (handles transactions) | Geth, Erigon, Reth, Nethermind, Besu |
| **Node** | Consensus/derivation layer | op-node, lighthouse, prysm, nitro, beacon-kit |
| **Relay** | Data availability | eigenda-proxy, op-alt, celestia |
| **Proxy** | HTTP/WS unification | nginx |
| **Database** | External database | Postgres |

### Naming Conventions

**Config names** (compose filenames) follow this pattern:
```
{network}-{chain}-{client}-{syncmode}-{dbtype}.yml
```

Examples:
- `ethereum-mainnet-geth-pruned.yml` — Ethereum mainnet, Geth client, pruned
- `op-base-sepolia-op-reth-archive-trace.yml` — Base sepolia, op-reth, archive with tracing
- `arb-arbitrum-one-arbnode-archive.yml` — Arbitrum One, arbnode, archive

**Short names** (used in URLs and container labels):
```
{network}-{chain}[-{client}][-{syncmode}][-{dbtype}]
```

**Volume names**:
```
<config-name>_<service>_<type>
```
Example: `ethereum-mainnet-geth-pruned_client_data`

### Defaults

- **Default client**: geth (Ethereum), op-geth (OP Stack), arbnode (Arbitrum)
- **Default sync mode**: pruned
- **Default database**: Depends on client (leveldb, pebble, etc.)
- **Default node**: op-node (OP Stack), prysm (Ethereum beacon), etc.

---

## 13. Syncing and Initial Setup

### Sync Modes

| Mode | Description | Speed | Storage |
|---|---|---|---|
| **Snap Sync** | Download recent state, verify | Fast | Medium |
| **Fast Sync** | Download blocks, verify headers | Medium | Medium |
| **Full Sync** | Verify all blocks from genesis | Slow | Full |
| **Archive** | Full sync + keep all state | Slowest | Largest |

Most nodes use **snap sync** or **fast sync** by default for pruned nodes.

### Using Checkpoints

Some nodes support checkpoint sync for faster startup:

```bash
# Check if checkpoint is configured
grep checkpoint <config-file>.yml
```

Checkpoints are typically provided by trusted community members or node operators.

### Snapshots

For even faster sync, some nodes support snapshot downloads:

```bash
# Check snapshot configuration
grep snapshot <config-file>.yml
```

Snapshots are large files containing the entire chain state at a point in time.

### Initial Sync Time

| Network | Pruned | Archive |
|---|---|---|
| Ethereum Mainnet | 1-3 days | 1-2 weeks |
| BSC Mainnet | 1-2 days | 3-5 days |
| Polygon Mainnet | 6-12 hours | 1-2 days |
| L2 Networks | Minutes - hours | Hours - 1 day |

Times vary based on hardware, network connection, and chain state.

---

## 14. Common Issues and Solutions

### Container Won't Start

**Symptom:** Container exits immediately or fails to start.

**Check:**
```bash
./logs.sh <config-name>
docker ps -a | grep <config-name>
```

**Common fixes:**
- Check `.env` file has all required variables
- Validate compose syntax: `docker compose -f <file>.yml config`
- Ensure ports aren't conflicting
- Pull images: `docker compose pull`

### Not Syncing / Stuck

**Symptom:** Node shows 0 peers or stuck at low block.

**Check:**
```bash
./sync-status.sh <config-name>
./peer-count.sh | grep <config-name>
./logs.sh <config-name> | grep -i error
```

**Common fixes:**
- Set `IP=` in `.env` (required for P2P)
- Check firewall allows P2P ports
- Verify checkpoint/snapshot URLs are reachable
- Restart with fresh volumes

### RPC Endpoint Not Accessible

**Symptom:** Can't connect to RPC endpoint.

**Check:**
```bash
./show-status.sh
curl http://localhost:<port>
docker ps | grep traefik
```

**Common fixes:**
- Check Traefik is running
- Verify DOMAIN is set correctly
- Check SSL configuration
- Test with NO_SSL=true for debugging

### High Resource Usage

**Symptom:** Node using too much CPU, memory, or disk.

**Check:**
```bash
./show-ram.sh <config-name>
./show-db-size.sh
./show-cpu.sh
```

**Common fixes:**
- Reduce max peers
- Upgrade hardware
- Switch to pruned mode
- Limit specific resources in compose file

### For More Debugging

For detailed debugging workflows, error patterns, and advanced troubleshooting,
see [VIBE.md](VIBE.md).

---

## 15. Utility Scripts Overview

This repository includes many scripts for managing your nodes. For the complete
debugging reference, see [VIBE.md](VIBE.md).

### Most Useful for Daily Operations

| Script | What It Does |
|---|---|
| `show-status.sh` | Show health of all running nodes |
| `show-running.sh` | List running containers |
| `logs.sh <name>` | View node logs |
| `sync-status.sh <name>` | Check sync progress |
| `latest.sh <name>` | Get latest block |
| `stop.sh <name>` | Stop a node |
| `start.sh <name>` | Start a node |
| `force-recreate.sh <name>` | Restart a node |
| `backup-node.sh <name>` | Create backup |
| `restore-volumes.sh <name>` | Restore from backup |

---

## 16. Learning More

- **[VIBE.md](VIBE.md)** — Complete debugging and operations guide for automated tools
- **[DRPC Documentation](https://drpc.org/)** — For monetization setup
- **[Traefik Documentation](https://doc.traefik.io/traefik/)** — For SSL and reverse proxy
- **[Docker Compose Documentation](https://docs.docker.com/compose/)** — For compose file reference

---

*For debugging and troubleshooting, see [VIBE.md](VIBE.md).*
*For the complete script reference and advanced operations, see [VIBE.md](VIBE.md).*
