Introduction
Recently a situation came up where a community project suddenly found itself exceeding the 100,000 requests per day limit of their Infura Core (Free) plan and in fact it looked like they were on track to hit over even the Developer plan (200,000) leaving them in a situation where they needed to either pay Infura $225/mo for 1,000,000 requests per day, or find another solution.
Luckily this ecosystem is not without all kinds of projects and services offering free or Freemium Ethereum endpoints!
In fact there’s a list of them located https://ethereumnodes.com.
We can debate all day if Infura pricing is reasonable or not *cough* AWS *cough* but then this blog post wouldn’t be any fun!
Dshackle – An Application Load Balancer for Ethereum
While I’m sure the big boys over at Infura and Alchemy have some pretty cool load balancing and caching services available to them, and you can do wonderful things with cloud services, we’re trying to save a buck here. Enter Dshackle – a Fault Tolerant Load Balancer for Blockchain API.
Dshackle is the only application aware load balancer for Ethereum that I’m aware of, and it’s pretty great. Usually.
Now, I’m not going to answer the question of “Where do I run it?” here, because that answer could be different for everyone. In the case of ArchiveNode.io we run multiple front ends on cheap unmetered (no bandwidth costs) VPS servers. I also run one at home on a machine I have sitting around. You could run it in the cloud, I guess, if you like paying that kind of money…
Two of my favorite choices though are Afterburst and Black Host and the good news is that Dshackle isn’t all that resource intensive. You could probably get away 2GB of RAM.
Docker All The Things
I’m a fan of using Docker here, because there’s official Docker Hub images AND it just makes things easy…
I’m not going to explain all the different ways there are to utilize docker or how to install docker but I’ll give a short crash course for people who might not know how to do anything with Docker.
I’m going to assume Ubuntu here and go with the installation instructions right off their website:
# Remove the out of date docker packages that come with Ubuntu
sudo apt-get remove docker docker-engine docker.io containerd runc
# Add the official docker repo keys
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# Get the Ubuntu Codename
UBUNTU_CODENAME=$(lsb_release -cs)
# Add the official docker repo to apt
sudo add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/ubuntu ${UBUNTU_CODENAME} stable"
# Update apt
sudo apt-get update
# Install Docker
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
Alright, we’ve got docker installed and it’s the latest and greatest version. Nice.
Configuring Dshackle
So the first thing that we need to do is create a Dshackle configuration. Dshackle config is a yaml file and you can find all the details about how to configure Dshackle in their github. But I’m going to go with a basic config here, and then get more creative later.
Let’s make a file called dshackle.yaml
host: 0.0.0.0
port: 2449
tls:
enabled: false
cache:
redis:
enabled: false
proxy:
host: 0.0.0.0
port: 8080
tls:
enabled: false
routes:
- id: eth
blockchain: ethereum
cluster:
defaults:
- chains:
- ethereum
upstreams:
- id: infura
chain: ethereum
options:
disable-validation: true
connection:
ethereum:
rpc:
url: "https://mainnet.infura.io/v3/${INFURA_USER}"
ws:
url: "wss://mainnet.infura.io/v3/${INFURA_USER}"
- id: chainstack
chain: ethereum
options:
disable-validation: true
connection:
ethereum:
rpc:
url: "https://nd-000-000-000.p2pify.com"
basic-auth:
username: fake-username
password: fake-password-fake-password-fake-password
ws:
url: "wss://ws-nd-000-000-000.p2pify.com"
basic-auth:
username: fake-username
password: fake-password-fake-password-fake-password
Alright, good enough for now. This should give you a decent starting point. We’ve configured dshackle to listen on all interfaces (host: 0.0.0.0
) which is important if we’re running in docker. It’s listening on port 2449
for gRPC (if you’re into that kind of thing) and on port 8080
for JSON-RPC which is what you’re probably looking for.
We didn’t configure any SSL/TLS certificates here, and there’s a few reasons for that. I’ll get into those reasons in Part 3. However, if all your traffic is local, and/or you’re not managing local accounts on local nodes, then there’s little reason to add that overhead at this point. Dshackle has a number of limitations that will force us to put an NGIX or HAProxy instance in front of it to make it useful to use with Dapps and Browsers, and we’ll add encryption there, in Part 3.
We’re also not enabling redis caching, if you were going to deploy a cluster I’d say do it, but if you don’t know what redis is, you probably don’t need it.
The example above is using 2 Freemium services, Infura and Chainstack, I chose them because Infura is the most common and Chainstack requires basic-auth so you could see how that’s done.
We’re using the disable-validation: true
parameter because these are cloud services, and it’s a waste of API calls to track them to make sure they have minimum peers, or they’re at the tip of the chain, etc. It’s really only needed if you’re pointing to actual individual nodes (like nodes you’re running yourself).
You’ll notice for Infura I left the key out and used ${INFURA_USER} and for Chainstack I just entered the fake-username fake-password, I’ll cover why in a second.
But that’s it, that’s the dshackle config.
Starting a Dshackle Node
Here’s where people’s preference for docker is going to vary wildly…
You could either make a Dockerfile that does a COPY of your config into the Dshackle image and build it:
FROM emeraldpay/dshackle:0.9.1
COPY ./dshackle.yaml /etc/dshackle/dshackle.yml
Or just mount it in a volume…
Either way you gotta hit it with a docker run like this:
export INFURA_USER=<your_api_key>
docker run -p 2449:2449 -p 8080:8080 -v /path/to/dshackle.yaml:/etc/dshackle/dshackle.yaml -e "INFURA_USER=$INFURA_USER" emeraldpay/dshackle:0.9.1
In the above example I used an environment variable to set the ${INFURA_USER} which is how we get our key into the dshackle config if you want to go that route.
After it boots up you should be able to hit it with:
curl -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' http://localhost:8080/eth
Assuming that worked, boom, you’re now load balancing requests from Infura and Chainstack AND you’re also caching some of those requests too! Instant reduction in RPC requests to the provider, and you essentially doubled your rate limits! (I have no idea what Chainstack rate limits are).
In Part 2 I’ll show a more advanced configurations of Dshackle. In Part 3 I’ll talk about some pitfalls and limitations as well as how to use NGINX in front of it to handle some of those limitations including TLS/SSL and CORS support.
PART 2 HERE
[…] Load Balancing Freemium Ethereum Endpoints […]
This is really helpful! We are starting to use dshackle recently and it’s great.