Setting up a Bitcoin node can be a bit daunting, especially considering the amount of disc space required and that the node needs to be always connected. However, once configured maintenance can be relatively hands-off. For more information about the minimum requirements please see here.
This tutorial will be split into two stages. One: configuring the server itself to be relatively secure and resilient against basic attacks and two: configuring the Bitcoin daemon on the server.
Stage one: securing the server
Let’s get the system up to date and then configure the stateful firewall.
# yum upgrade
# yum install vim iptables-service
And we’ll move SSH to a different port so we can reduce the number of login attempts considerably. As this is CentOS, SELinux will need to be informed of the change to allow the SSH daemon to bind to the new port.
# vim /etc/ssh/sshd_config
Set Port to 1234 or something non-standard
# semanage port -a -t ssh_port_t -p tcp 1234
# systemctl reload sshd
And log back in using the new port to take a look at the network interfaces.
[user@local] $ ssh root@bitcoin -p 1234
$ ip addr
Now let's understand the current network topology.
1: lo: mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 92:53:fb:96:86:27 brd ff:ff:ff:ff:ff:ff
inet 128.199.93.101/18 brd 128.199.127.255 scope global eth0
valid_lft forever preferred_lft forever
inet 10.15.0.5/16 brd 10.15.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 2400:6180:0:d0::1f6:2001/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::9053:fbff:fe96:8627/64 scope link
valid_lft forever preferred_lft forever
We can see there are two network interfaces – lo, the loopback interface, and eth0, the Internet facing interface. For the loopback (lo), it’s assigned the address 127.0.0.1/8 (IPv4) and ::1/128 (IPv6). For the Ethernet (eth0), it has four addresses. The first two are the public and private IPv4 addresses and the second two are the public and private IPv6 addresses, respectively.
We won’t be needing an networking within a private LAN so we’ll remove the internal addresses from the list of routes.
# ip addr del 10.15.0.5/16 dev eth0 # ip addr del fe80::9053:fbff:fe96:8627/64 dev eth0
Next we’ll enable a simple stateful firewall to prevent errant access to the box. Copy this to the root directory and use `iptables-restore < iptables` to use it. Make sure you set the correct SSH port as you’ll be needing it to log into the box.
# iptables IPv4 simple config (bitcoin node)
# v0.0.1
# use at your own risk
*filter
# 1. Basics, loopback communication, ICMP packets, established connections
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp --icmp-type any -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# 2. Ensuring connections made are valid (syn checks, fragments, xmas, and null packets)
-A INPUT -p tcp ! --syn -m state --state NEW -j DROP
-A INPUT -f -j DROP
-A INPUT -p tcp --tcp-flags ALL ALL -j DROP
-A INPUT -p tcp --tcp-flags ALL NONE -j DROP
# 3. Connections for various services, including SSH and Bitcoin
-A INPUT -p tcp -m conntrack --ctstate NEW --dport 5555 -j ACCEPT
-A INPUT -p tcp -m conntrack --ctstate NEW --dport 8333 -j ACCEPT
-A INPUT -p tcp -m conntrack --ctstate NEW --dport 18333 -j ACCEPT
#4. Log problems and set default policies for anything else
-A INPUT -j LOG --log-level 7 --log-prefix "iptables dropped: "
-P OUTPUT ACCEPT
-P FORWARD DROP
-P INPUT DROP
COMMIT
Once loaded, make sure the iptables service starts on every boot.
# yum install iptables-services
# systemctl start iptables
# systemctl enable iptables
# iptables-restore < iptables
# iptables -L
You should now see the policies enabled. Let’s do the same for IPv6.
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -p ipv6-icmp -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -d fe80::/64 -p udp -m udp --dport 546 -m state --state NEW -j ACCEPT
-A INPUT -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j DROP
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j DROP
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-A INPUT -p tcp -m conntrack --ctstate NEW -m tcp --dport 5555 -j ACCEPT
-A INPUT -p tcp -m conntrack --ctstate NEW -m tcp --dport 8333 -j ACCEPT
-A INPUT -p tcp -m conntrack --ctstate NEW -m tcp --dport 18333 -j ACCEPT
-A INPUT -j LOG --log-prefix "ip6tables dropped: " --log-level 7
-A INPUT -j REJECT --reject-with icmp6-adm-prohibited
-A FORWARD -j REJECT --reject-with icmp6-adm-prohibited
COMMIT
Good so far. Let’s make these the default rules.
# iptables-restore > /etc/sysconfig/iptables
# ip6tables-restore > /etc/sysconfig/ip6tables
Stage two: configuring the Bitcoin node
Now, let’s get started with configuring the Bitcoin node. Begin by creating a local user account you’ll use to manage the service from now on.
# adduser user
# passwd user
# gpasswd -a u er wheel
# visudo // check that wheel is enabled on Centos
Login as the user and download and configure Bitcoin.
$ curl -O https://bitcoin.org/bin/bitcoin-core-0.15.1/bitcoin-0.15.1-x86_64-linux-gnu.tar.gz
$ curl -O https://bitcoin.org/laanwj-releases.asc
$ curl -O https://bitcoin.org/bin/bitcoin-core-0.15.1/SHA256SUMS.asc
$ gpg --quiet --with-fingerprint laanwj-releases.asc
$ gpg --import laanwj-releases.asc
$ gpg --verify SHA256SUMS.asc
The blockchain will be stored on an attached 250GB storage drive. We’ll mount it, format it, and configure it for hosting the blockchain. Additionally, we’ll add it to fstab so it is attached at boot.
$ sudo mkfs.ext4 -F /dev/disk/by-id/scsi-01
$ sudo mkdir -p /mnt/xbt-blockchain
$ sudo mount /dev/disk/by-id/scsi-01 /mnt/xbt-blockchain
$ sudo chown user:user /mnt/xbt-blockchain
$ echo '/dev/disk/by-id/scsi-01 /mnt/xbt-blockchain ext4 defaults 0 0' | sudo tee -a /etc/fstab
Next, we’ll configure bitcoin.conf to starting the daemon on the testnet first.
$ tar xf bitcoin-0.15.1-x86_64-linux-gnu.tar.gz ~/
$ touch /mnt/xbt-blockchain/bitcoin.conf
$ vim /mnt/xbt-blockchain/bitcoin.conf
# bitcoin.conf
# v0.0.1
# Use at your own risk
listen=1
server=1
rpcport=8332
rpcallowip=127.0.0.1
listenonion=0
maxconnections=16
datadir=/mnt/xbt-blockchain
testnet=1
disablewallet=1
# if low on memory
dbcache=20
maxmempool=300
Let’s test the configuration.
$ ~/bitcoin-0.15.1/bin/bitcoind -datadir=/mnt/xbt-blockchain &
$ ~/bitcoin-0.15.1/bin/bitcoin-cli -datadir=/mnt/xbt-blockchain
> uptime
Everything should be looking good at this point. Now, let’s enable the daemon to connect to mainnet. Set the testnet=1 boolean to 0 in the bitcoin.conf file and restart the daemon.
Congratulations — you’ve configured a full node. It will take a while to sync.