- Add VIBE.md as primary debugging reference for automated tools - Rewrite README.md as human-focused operator guide - Fix README.md inaccuracies (remove show-networks.sh references, fix typo) - Split content: README for humans, VIBE for agents Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
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 — 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:
# === 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:
curl ipinfo.io/ip
For traefik.me domain: Replace dots with hyphens in your IP:
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:
# 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
# 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-prunedop-base-sepolia-op-reth-pruned-tracearbitrum-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:
# 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:
./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.shto 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:
# 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:
# 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:
# In .env
echo "NO_SSL=true" >> .env
# Then restart
docker compose up -d
8. DRPC Integration — Monetize Your RPC
DRPC allows you to sell excess RPC capacity and earn revenue.
Quick Setup
-
Enable DRPC in your
.env:# Add to .env GW_DOMAIN=your-gateway-domain.com GW_REDIS_RAM=2gb DRPC_VERSION=0.64.16 -
Add DRPC to COMPOSE_FILE:
COMPOSE_FILE=base.yml:rpc.yml:drpc.yml:ethereum-mainnet-geth-pruned.yml -
Generate upstreams configuration:
./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:
- On each server, run nodes with DRPC enabled
- On your gateway server, run
./upstreams.shto generate combined config - Deploy the dshackle configuration to your gateway
For more information, visit 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
# 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:
# 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:
# 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:
# 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:
# 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:
- Allow inbound connections to P2P ports (UDP/TCP)
- Allow outbound connections from containers
- 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:
[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:
#!/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:
# 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
# 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
# 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
# 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
# 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, prunedop-base-sepolia-op-reth-archive-trace.yml— Base sepolia, op-reth, archive with tracingarb-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:
# 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:
# 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:
./logs.sh <config-name>
docker ps -a | grep <config-name>
Common fixes:
- Check
.envfile 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:
./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:
./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:
./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.
15. Utility Scripts Overview
This repository includes many scripts for managing your nodes. For the complete debugging reference, see 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 — Complete debugging and operations guide for automated tools
- DRPC Documentation — For monetization setup
- Traefik Documentation — For SSL and reverse proxy
- Docker Compose Documentation — For compose file reference
For debugging and troubleshooting, see VIBE.md. For the complete script reference and advanced operations, see VIBE.md.