This guide walks you through setting up your own Ethereum Mainnet node with both execution and consensus layers. You will:
- Install Docker, Nginx, and Certbot
- Configure Geth (execution) and Prysm (consensus) clients
- Set up reverse proxy with SSL
- Monitor and maintain your node
This setup provides you with your own dedicated RPC endpoints for Ethereum Mainnet (ETH & Beacon).
1. Hardware requirements
| Component | Requirement | Recommended |
|---|---|---|
| CPU | 4 Core | 8 Core |
| RAM | 16 GB | 32 GB |
| Storage | 2 TB NVMe SSD | 4 TB NVMe SSD |
| Network | 25 Mbps stable | 100+ Mbps |
Check our Server Provider List for recommended options.
2. Installation
a. Install dependencies
Ensure you have the required software installed:
Install Nginx:
sudo apt update -qy
sudo apt install nginx -y Start and enable Nginx:
sudo systemctl start nginx
sudo systemctl enable nginx Check status:
sudo systemctl status nginx Install Certbot for SSL:
sudo apt install certbot python3-certbot-nginx -y b. Setup Ethereum node
Create project directory:
mkdir ethereum-rpc && cd ethereum-rpc Create required directories:
mkdir -p data/geth-mainnet data/prysm-beacon Generate JWT secret:
openssl rand -hex 32 > data/jwt.hex Create Docker Compose file:
nano docker-compose.yml Add Docker Compose configuration:
services:
geth:
image: ethereum/client-go:v1.16.7
container_name: geth-mainnet
restart: unless-stopped
ports:
- "127.0.0.1:8545:8545" # HTTP RPC
- "127.0.0.1:8546:8546" # WS RPC
- "30303:30303" # P2P TCP
- "30303:30303/udp" # P2P UDP
volumes:
- ./data/geth-mainnet:/root/.ethereum
- ./data/jwt.hex:/root/jwt.hex:ro
command: >
--mainnet
--syncmode snap
--cache 32768
--http
--http.addr 0.0.0.0
--http.port 8545
--http.api eth,net,web3
--http.vhosts "*"
--http.corsdomain "*"
--ws
--ws.addr 0.0.0.0
--ws.port 8546
--ws.api eth,net,web3
--ws.origins "*"
--authrpc.addr 0.0.0.0
--authrpc.port 8551
--authrpc.jwtsecret /root/jwt.hex
--authrpc.vhosts=*
--maxpeers 100
--verbosity 3
prysm:
image: gcr.io/prysmaticlabs/prysm/beacon-chain:stable
container_name: prysm-beacon
restart: unless-stopped
depends_on:
- geth
ports:
- "127.0.0.1:3500:3500" # HTTP API (beacon)
- "4000:4000" # P2P
volumes:
- ./data/prysm-beacon:/data
- ./data/jwt.hex:/root/jwt.hex:ro
command: >
--datadir=/data
--accept-terms-of-use
--execution-endpoint=http://geth-mainnet:8551
--jwt-secret=/root/jwt.hex
--p2p-max-peers=100
--p2p-host-ip=0.0.0.0
--monitoring-host=127.0.0.1
--checkpoint-sync-url=https://beaconstate-mainnet.chainsafe.io
networks:
default:
name: eth-mainnet-network
driver: bridge c. Initialize and start services
Start the services:
docker compose up -d View Geth logs:
docker logs -f geth-mainnet View Prysm logs:
docker logs -f prysm-beacon Monitor both services:
docker compose logs -f 3. Nginx reverse proxy setup
a. Configure Nginx for Geth (execution layer)
Create Nginx configuration:
sudo nano /etc/nginx/sites-available/eth-mainnet-rpc Add the following configuration:
server {
server_name eth.yourdomain.com;
access_log /var/log/nginx/eth_mainnet_rpc_access.log;
error_log /var/log/nginx/eth_mainnet_rpc_error.log;
location / {
# IP whitelist - replace with your actual IPs
allow 172.16.0.0/12; # Docker networks
allow 10.0.0.0/8; # Private networks
allow 192.168.0.0/16; # Private networks
allow 203.0.113.1; # Your specific IP
allow 198.51.100.0/24; # Your network range
# Deny all other traffic
deny all;
proxy_pass http://127.0.0.1:8545;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
client_max_body_size 1M;
limit_req zone=api burst=10 nodelay;
}
} b. Configure Nginx for Prysm (consensus layer)
Create Nginx configuration:
sudo nano /etc/nginx/sites-available/beacon-mainnet-rpc Add the following configuration:
server {
server_name beacon.yourdomain.com;
access_log /var/log/nginx/beacon_mainnet_rpc_access.log;
error_log /var/log/nginx/beacon_mainnet_rpc_error.log;
location / {
# IP whitelist - same as above
allow 172.16.0.0/12;
allow 10.0.0.0/8;
allow 192.168.0.0/16;
allow 203.0.113.1;
allow 198.51.100.0/24;
deny all;
proxy_pass http://127.0.0.1:3500;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
client_max_body_size 1M;
limit_req zone=api burst=10 nodelay;
}
} c. Enable Nginx sites
Add rate limiting to main Nginx config:
sudo nano /etc/nginx/nginx.conf Add this inside the http block:
# Rate limiting zone
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; Create symbolic links:
sudo ln -s /etc/nginx/sites-available/eth-mainnet-rpc /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/beacon-mainnet-rpc /etc/nginx/sites-enabled/ Test configuration:
sudo nginx -t Reload Nginx:
sudo systemctl reload nginx d. Setup SSL with Certbot
Obtain SSL certificate for Geth endpoint:
sudo certbot --nginx -d eth.yourdomain.com Obtain SSL certificate for Prysm endpoint:
sudo certbot --nginx -d beacon.yourdomain.com Test certificate renewal:
sudo certbot renew --dry-run 4. Service configuration details
a. Geth (execution client)
- Image:
ethereum/client-go:v1.16.7 - Network: Ethereum mainnet
- Sync Mode: Snap sync
- RPC Endpoint:
https://eth.yourdomain.com - WebSocket Endpoint:
wss://eth.yourdomain.com - Available APIs: eth, net, web3
- Cache: 32768 MB
b. Prysm (consensus client)
- Image:
gcr.io/prysmaticlabs/prysm/beacon-chain:stable - Network: Ethereum mainnet
- HTTP API:
https://beacon.yourdomain.com - Checkpoint Sync: Enabled for faster initial sync
c. Port configuration
| Service | Port | Protocol | Purpose | Access |
|---|---|---|---|---|
| Geth | 8545 | HTTP | JSON-RPC API | Localhost + Nginx |
| Geth | 8546 | WS | WebSocket RPC | Localhost + Nginx |
| Geth | 30303 | TCP/UDP | P2P networking | Public |
| Prysm | 3500 | HTTP | Beacon API | Localhost + Nginx |
| Prysm | 4000 | TCP | P2P networking | Public |
5. Verification and testing
a. Check sync status
Check Geth sync status:
Direct (localhost)
curl -s -X POST --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}' \ -H "Content-Type: application/json" http://localhost:8545 | jqThrough Nginx proxy
curl -s -X POST --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}' \ -H "Content-Type: application/json" https://eth.yourdomain.com | jqExpected output when synced:
{ "jsonrpc": "2.0", "id": 1, "result": false }Check Prysm sync status:
Direct (localhost)
curl -s http://localhost:3500/eth/v1/node/syncing | jqThrough Nginx proxy
curl -s https://beacon.yourdomain.com/eth/v1/node/syncing | jqExpected output when synced:
{ "data": { "head_slot": "10000000", "sync_distance": "0", "is_syncing": false, "is_optimistic": false, "el_offline": false } }
b. Health checks
Geth block number
curl -s -X POST --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
-H "Content-Type: application/json" https://eth.yourdomain.com | jq Prysm health
curl -s https://beacon.yourdomain.com/eth/v1/node/health 6. Monitoring and maintenance
a. Check service status
Docker containers status
docker compose ps Container resource usage
docker stats geth-mainnet prysm-beacon Container logs
docker compose logs --tail=100 geth
docker compose logs --tail=100 prysm b. Service management
Restart all services:
docker compose restart Restart individual services:
docker compose restart geth
docker compose restart prysm Update services:
docker compose pull
docker compose up -d c. Data persistence
All blockchain data is persisted in the ./data directory:
./data/geth-mainnet/: Geth blockchain data./data/prysm-beacon/: Prysm beacon chain data./data/jwt.hex: JWT secret for client authentication
d. Backup strategy
Create quick backup (while services running):
tar -czf eth-backup-$(date +%Y%m%d).tar.gz data/ Create full backup (consistent, services stopped):
docker compose down
tar -czf eth-full-backup-$(date +%Y%m%d).tar.gz data/
docker compose up -d Restore from backup:
docker compose down
tar -xzf eth-backup-YYYYMMDD.tar.gz
docker compose up -d 7. Troubleshooting
a. Common issues
1. Port conflicts
Check port usage:
netstat -tulpn | grep -E ':(8545|8546|3500|30303|4000)' Kill processes using required ports:
sudo lsof -ti:8545 | xargs kill -9 2. Insufficient memory
Check system memory:
free -h Check Docker memory limits:
docker stats Increase swap if needed:
sudo fallocate -l 8G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile 3. Sync issues
Check network connectivity:
ping beaconstate-mainnet.chainsafe.io Reset and resync (WARNING: deletes data):
docker compose down
sudo rm -rf data/geth-mainnet data/prysm-beacon
mkdir -p data/geth-mainnet data/prysm-beacon
docker compose up -d 4. SSL certificate issues
Check certificate status:
sudo certbot certificates Renew certificates manually:
sudo certbot renew Test Nginx configuration:
sudo nginx -t 5. Access denied (403)
Check your IP:
curl https://ipinfo.io/ip Update Nginx IP whitelist and reload:
sudo nano /etc/nginx/sites-available/eth-mainnet-rpc
sudo systemctl reload nginx b. Log analysis
Search for errors in container logs
docker compose logs geth | grep -i error
docker compose logs prysm | grep -i error Check Nginx logs
sudo tail -f /var/log/nginx/eth_mainnet_rpc_access.log
sudo tail -f /var/log/nginx/eth_mainnet_rpc_error.log Check system logs
sudo journalctl -f -u docker
sudo journalctl -f -u nginx c. Recovery commands
Full service restart
docker compose down
docker compose up -d Full service restart with image updates
docker compose down
docker compose pull
docker compose up -d --force-recreate Emergency cleanup (removes all data)
docker compose down -v
sudo rm -rf data/geth-mainnet data/prysm-beacon
mkdir -p data/geth-mainnet data/prysm-beacon
openssl rand -hex 32 > data/jwt.hex
docker compose up -d 8. Security considerations
a. Network security
- Local Binding: RPC endpoints bound to localhost only
- Reverse Proxy: Nginx provides controlled external access
- IP Whitelisting: Only specified IPs can access endpoints
- SSL/TLS: All external traffic encrypted
- Rate Limiting: Protection against abuse
b. Firewall configuration
Allow SSH
sudo ufw allow ssh Allow Nginx (HTTP/HTTPS)
sudo ufw allow 'Nginx Full' Allow P2P ports for blockchain
sudo ufw allow 30303
sudo ufw allow 4000 Deny all other traffic
sudo ufw --force enable c. Access control best practices
- Regular Updates: Keep Docker images and system updated
- Strong Authentication: Use SSH keys, disable password auth
- Monitor Access: Review Nginx logs regularly
- Backup Security: Encrypt backups, store securely
- Network Segmentation: Consider VPN for additional security
d. Monitoring setup
Set up log rotation
sudo nano /etc/logrotate.d/eth-mainnet-logs Add content:
/var/log/nginx/eth_mainnet_rpc_*.log
/var/log/nginx/beacon_mainnet_rpc_*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 644 www-data www-data
postrotate
systemctl reload nginx
endscript
} 9. Sync time expectations
- Initial Sync: 6-12 hours depending on hardware and network
- Geth Snap Sync: Faster than full sync
- Prysm Checkpoint Sync: Starts from recent checkpoint, much faster
- Storage Growth: ~50-80GB per month for mainnet
10. Post-setup checklist
Verify the following before considering your setup complete:
- Both Geth and Prysm are syncing successfully
- RPC endpoints respond to health checks
- SSL certificates are installed and working
- IP whitelist configured correctly
- Firewall rules are properly configured
- Log rotation is set up
- Backup strategy is implemented
- Monitoring is in place
11. Resources
- Documentation: Geth Documentation ยท Prysm Documentation
- Explorer: Ethereum Beacon Chain Explorer
- Checkpoint Sync: Ethereum Checkpoint Sync
- Web Server: Nginx Documentation