How I’m running a Bitcoin Full Node on Digital Ocean for $35 a month

Enjoyed the story? Leave some claps 👏 here on Medium and share it with your bitcoin-curious friends. Want to stay up-to-date on the latest in bitcoin? Follow me on Twitter here

NOTE: This post has been updated to reflect Digital Ocean’s updated Droplet configurations as of Jan 18, 2018
ANOTHER NOTE: If you’ve run into issues with your storage volume filling up, I’ve written an additional article on how to expand the volume storage space and get your full node back up and running

In the last couple months, I’ve become obsessed with Bitcoin and have been tinkering with different full node setups. A full node is a node that fully enforces all of the rules of the blockchain, and one that ensures that I give value to the protocol that I deem valid.

A “node” is just a fancy word for running the bitcoin protocol in the form of a software program on a computer connected to other computers running the bitcoin protocol

$40/mo is kinda expensive when compared with the free wallet services that you can get from custodial providers, but the real advantage of bitcoin is the ability to control complete validation of the ledger and to write code that interacts with the blockchain instead of being limited by a third-party API provider.

When you run a full node, you get to tinker with a database worth over $117,000,000,000

The problem is, running a full node is resource intensive. It requires (as of Nov 2017) almost 180G of space to store the entire bitcoin blockchain, the unspent transaction index, and other transaction indexes for fast transaction lookup. It’s memory needs are modest (1–2 GB of RAM), but it can eat through bandwidth pretty quickly, and I wanted it to be running 24/7, so I could connect to it through an SPV wallet of my choice.

Digital Ocean has a new(ish) feature called “Volumes” that allows you to attach storage to a droplet to extend the storage space. A 200GB volume costs $20 a month; combine that with a droplet running Ubuntu 16.04 with 2 CPUs, 2GB of RAM, and 3TB of data transfer for $20 and the final cost is “only” $40 a month. Without volumes, you would have to run a $320/month droplet to get enough storage space to run a proper full node.

If you’d like to run a similar setup, I’ve included detailed instructions below. Note that I’m running the Full Node with the wallet functionality disabled, although there is no reason to do this if you aren’t planning on using the wallet to store any bitcoins. If you do want a full node to use the wallet functionality, I’d suggest a more secure solution than a Virtual Machine on a cloud provider.

Step 1: Prepare your SSH keys

We’re going to be SSHing into the droplet later using a public/private key, so the first thing we need to do is generate a new SSH Key and upload the public key to Digital Ocean.

Open your Terminal on your local computer and issue the following command to generate a new public/private key pair:

# ssh-keygen -t rsa
NOTE: In the above line, there is no need to enter the hashtag character #. It’s merely there to denote a terminal command. The entire command is just ssh-keygen -t rsa

You’ll be asked a few questions, such as what you’d like to name the files and a passphrase. I’ve left the passphrase out and I saved my public/private key files to ~/.ssh/digtal_ocean_droplet. The output of running this command should look like something this:

Note the “Enter file in which to save the key” line. Everything after the colon will be entered by you to select where to store the files. Of course your home directory probably won’t be under /Users/eric

Next up we need to upload the public key to Digital Ocean. Back in your terminal output the contents of the public key by issuing the following command:

# cat ~/.ssh/digital_ocean_droplet.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC74S3oh79sKw3zEqS5Y+CG7ZMcNLi9IuJ+WQws1HkeQZ8tKiaVZ62jpkNRtlxvADGv/LwJ9lAUdQ9nDa5GJt99bz9tV3Hsc5iUkPBsQaDQIYfstxkQpxbUvpmDNmSNfMVF95TFcyGPs3lTvvr9s7dIE4G/Y5Ov5H3fsUUEvZgpjB8/XnQDcfQTN9ocoIj6Sj15bLeSomEHoudwi7LKGRmABRrv2w44Ml0k5GzjdQdVu5cUsKlSyzsciENhh506kJrLeht6acdwQHAe0u1drCYEMEQpUfcm2VV8Hldm/ob/wH/8FHrhf1op9JpeX+/XfxrEG9N/SbWjnswjjioIsCLd eric@Erics-MacBook-Pro-4.local

Copy the entire output and then in your browser, navigate over to the Security settings in Digital Ocean and click the “Add SSH Key” button. Paste the previously copied public key contents and give your key a name, like so:

Finally, back on your machine in the terminal, add the private key to your SSH agent to allow you to later SSH into the droplet by issuing the following command:

# ssh-add ~/.ssh/digital_ocean_droplet
Identity added: /Users/eric/.ssh/digital_ocean_droplet (/Users/eric/.ssh/digital_ocean_droplet)

Step 2: Create droplet and volume

Now that we have our SSH key setup, it’s time to create the droplet and storage volume. Head over to the New Droplet page and select the following options:

These instructions are specifically for Ubuntu, but feel free to choose another OS and adapt the instructions as needed.
This article has been updated to use Digital Ocean’s new droplet options. Previously, I was using a $20/month droplet, but now we can get the same performance while saving $5 a month!
Select the custom volume size option and enter 200GB for the size.
To reduce latency, select the region that is closest to you. Some options aren’t available because not all regions support storage volumes as of writing.
Make sure you select the SSH key we aded earlier.
Here I gave my droplet the hostname “bitcoin-full-node-1”. If you enter a different hostname just be sure to adapt the following instructions wherever you see “bitcoin-full-node-1”

Step 3: Initial Server Setup

After a few minutes your new droplet will be ready to go. Head over to the droplet page and copy the IP address for the droplet as shown here:

Before we can do anything too interesting, we need to do the initial server setup by creating a new linux user “bitcoin”, giving it sudo priveledges, and allowing us to SSH in to the server as “bitcoin” and not the default “root” user.

NOTE: In the following instructions, any command that is preceded by just a # signifies a command run on your local machine, and a command that is preceded by user@bitcoin-full-node-1:~# signifies a command run on the droplet.

First, SSH into the droplet using the IP Address you copied previously using this command:

# ssh root@138.68.177.109

You’ll be shown a prompt that “The authencity of host X can’t be established”. When asked if you want to continue just type “YES” and hit Enter.

If everything was done correctly up until this point, after a lovely welcome message from Ubuntu is displayed, you should be shown a prompt like the following:

root@bitcoin-full-node-1:~#

You’re in! The first thing we need to do is stop using the root user to login to our server and instead create a new bitcoin user and give it sudo access:

root@bitcoin-full-node-1:~# adduser bitcoin
root@bitcoin-full-node-1:~# usermod -aG sudo bitcoin

When executing the adduser command you’ll be asked to supply a new password. I suggest generating a strong password and using a password manager (e.g. 1Password). adduserwill also ask for a bunch of other information but feel free to just leave that blank.

Next up we’ll need to add our public SSH key to the bitcoin user’s authorized_key file so we can SSH into the droplet using bitcoin instead of root. Copy the public key again following the same instructions in Step 1, and then, as root on the droplet, become the bitcoin user:

root@bitcoin-full-node-1:~# su - bitcoin

Create the .ssh directory and give it the correct permissions:

bitcoin@bitcoin-full-node-1:~# mkdir ~/.ssh
bitcoin@bitcoin-full-node-1:~# chmod 700 ~/.ssh
NOTE: Notice how root@ became bitcoin@, this denotes that you are running the command as the bitcoin user instead of root.

Next we’re going to use the vi editor to create the authorized_keys file and add paste in the SSH key contents:

The authorized_keys file needs the correct permissions, so issue the following command:

bitcoin@bitcoin-full-node-1:~# chmod 600 ~/.ssh/authorized_keys

Now logout of the droplet by issuing two exit commands:

bitcoin@bitcoin-full-node-1:~# exit
root@bitcoin-full-node-1:~# exit

You should now be able to SSH into the droplet using the bitcoin user:

# ssh bitcoin@138.68.177.109

Step 4: Format and attach the volume

The 200GB storage volume we created in Step 2 still needs some configuration before we can use it to store our bitcoin blockchain. The first thing we need to do is find out the name of the volume in the Digital Ocean dashboard. Navigate to your droplet and click the Volumes link and you can find the name of your volume here:

Your volume name will most likely not be “volume-lon1-03”

Now, as the bitcoin user on your droplet, run the following commands, but make sure you replace all instances of volume-lon1-03 with your volume name:

NOTE: I’ve stopped prepending terminal commands with bitcoin@bitcoin-full-node-1:~# because all commands from here on out will be run on the droplet as the bitcoin user.
NOTE: Anytime you run a command with the sudo prefix it means you may need to enter the bitcoin password you created in Step 2.

You’ll now have a 197GB volume mounted at the /mtn/volume-lon1-03-part1 directory. We’ll be using it as our Data Directory when we configure Bitcoin Core in Step 6. But first, we need to install Bitcoin Core.

Step 5: Install Bitcoin Core

Installing Bitcoin Core is easy using the apt-get utility provided by Ubuntu. Follow the commands below to install the latest version of Bitcoin Core (at the time of this writing the latest release available is 0.15.1)

If prompted to confirm when running install, type Y for “Yes” and hit Enter. You should now have bitcoind installed; test and make sure by issuing the bitcoind --version command.

Step 6: Configure Bitcoin Core

Before we can start running bitcoind and doing our initial synchronisation with the network, we’ll need to create the Data Directory, set our options in bitcoin.conf, and create a Ubuntu service to make it easier to start/stop/restart our bitcoind executable and ensure it runs even if the machine reboots.

First, we’ll create the Data Directory we’re we’ll store the blockchain and all related files, inside the volume we configured above:

mkdir /mnt/volume-lon1-03-part1/Bitcoin

Next, we’ll create the ~/.bitcoin directory where our bitcoin.conf file will be stored:

mkdir ~/.bitcoin

Now, using vi, create the ~/.bitcoin/bitcoin.conf file and paste in this configuration:

Make sure to replace the enterpasswordhere text with a strong password, especially if you’d like to make RPC calls to this full node from a remote client.

Also note the dbcache=1000 option. This is specifying, in megabytes, how much space you’d like the database cache size to be. The larger this value, the faster the initial sync will be, but it depends on the amount of RAM on the machine. Since I’m using the 2GB droplet, I’ve set the index size to be ~1GB. With an 8GB machine, and a dbcache=6000 set, the initial sync took just under 8 hours.

Finally, create the bitcoin.service file at /lib/systemd/system/bitcoin.service using vi like so:

sudo vi /lib/systemd/system/bitcoin.service

And paste in the following contents:

Again, make sure you replace any instance of volume-lon1-03 with the name of your volume.

Step 7: Run Bitcoin

After all that, it’s time to fire up the bitcoin process and start the initial sync:

sudo service bitcoin start

After a minute or so, you should be able to query the node for information about the blockchain and view your progress:

bitcoin-cli getblockchaininfo

Which will give you output similar to this:

And see how many other nodes you are connected to with this command:

bitcoin-cli getnetworkinfo | grep connections

Which will be at most 8 until the synchronisation process is complete. You can now logout of your service with exit and come back about 36 hours later to see a fully validated bitcoin blockchain. Once that happens, you can test to see if you can connect to your full node using the “Join the Network” tester on Bitnodes:

Remember, your node will only accept incoming connections once it’s fully validated and up-to-date.

Some improvements to this setup that I’d like to make is to configure my node always to hold open an incoming connection for my SPV wallet, adding a firewall for more protection, and also do a little more research around the possibility of running wallet services on a VM.

There is also the issue of the growth in storage requirements. With a fully validated blockchain at height 493,617, my 200GB volume has about 20G of room left. With 10 minute blocks, that gives me about ~4–5 months before I’ll need to increase the volume storage, and more likely it’ll need to happen before that to account for index size and to leave some buffer.

And that doesn’t take into account the possible 2x hard fork coming at block 494,784. If for some reason the 2x fork “wins” and most of the users of bitcoin switch to the 2x chain, then the increase will have to come even sooner in as little as 50–60 days. And the storage requirements for the full blockchain and indexes will grow approximately 120–150GB per year, not to mention bandwidth increases which may price out the $20/mo droplet.

For this reason and a few others, I’m going to be voting with my node to try and keep the 1x chain the dominant chain. With the instructions above, and a little bit of money, you can too.