Accessing your Electrum Server in the Wild
view this post on our onion site
5 min read

Accessing your Electrum Server in the Wild

Accessing your Electrum Server in the Wild

Are State Actors DDoS'ing Tor making it hard for you to connect to your Electrum Server in a Sovereign way? Are you already far enough down the rabbit-hole that you have a VPS purchased privately using Bitcoin as well as a home server running Bitcoin Core + ElectrumX? In this guide I will walk you through how you make your locally hosted Bitcoin Electrum Server accessible via the public domain without exposing your home IP address.

Pre-requisites

I used @k3tan's Ministry of Nodes Guide 01 to 05 as the basis of my local machine setup.

Setup a Local machine with +1TB SSD:

Setup Bitcoin Core on Local machine:

Setup Fulcrum Server OR ElectrumX Server on Local machine:

In addition to the above you will also need a remote server:

Local Machine Setup

This guide assumes you have a local machine running Debian-based Linux Distro with a fully sync-ed Bitcoin Node and Bitcoin indexer either ElectrumX or Fulcrum (ElectRS is another option but ElectrumX is many times faster than this).

The way we are going to expose our Bitcoin indexer to the public is via a Reverse SSH tunnel from our local machine to a remote server.

This guide from @openoms covers some of this but not specifically from the perspective of tunnelling your Electrum Server.

You should have ssh keys setup and copied over to your remote server. For this ssh tunnel daemon to work smoothly you will need ssh keys without a passphrase.

First install autossh which is a wrapper on ssh:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install autossh

Then create a .service file to run your ssh tunnel daemon:

sudo vim /etc/systemd/system/ssh-tunnel.service

Here is a template of this .service file:

[Unit]
Description=Remote SSH tunnel for Electrum Server
After=network.target

[Service]
User=statue
Group=statue
Environment="AUTOSSH_GATETIME=0"
ExecStart=/usr/bin/autossh -C -M 0 -v -N -o "ServerAliveInterval=60" -R <remote-port>:localhost:50001 <remote-username>@<remote-ip-or-domain>
Restart=always
RestartSec=60
StandardOutput=journal

[Install]
WantedBy=multi-user.target

Note: Remote port should not be equal to 50001 or 50002 to avoid potential binding issues on your remote server.

The port you are tunneling should be the regular TCP port 50001 and not the SSL port 50002. This is because the remote server will be performing the SSL encryption via nginx when exposing the data to the public. You want to edit the config file for your Electrum Server and make sure the line relating to enabling tcp is uncommented. In fulcrum.conf this is near line ~120 tcp = 0.0.0.0:50001.

Once the daemon file ssh-tunnel.service has been created you will need to
reload, enable and start:

sudo systemctl daemon-reload
sudo systemctl enable ssh-tunnel.service
sudo systemctl start ssh-tunnel.service

You should then check the status:

sudo systemctl status ssh-tunnel.service

or logs:

journalctl -fu ssh-tunnel.service

This important line in the logs you should be looking for is this:

autossh[<process-id>]: debug1: remote forward success for: listen <remote-port>, connect localhost:50001

Remote Server Setup

The remote server should be running a debian-based headless distro. You will need nginx installed. If you got your server from 1984Hosting they have the option to pre-install some packages including nginx.

As per @openoms guide you should login as root or run:

sudo su

edit the sshd config:

vim /etc/ssh/sshd_config

Make sure the following entries are active. You can search for them in the config and remove the # to activate them or if they are not included just paste them on the end of the file:

RSAAuthentication yes
PubkeyAuthentication yes
GatewayPorts yes
AllowTcpForwarding yes
ClientAliveInterval 60

Restart the sshd service (WARNING: you can lose access at this point if the config is wrong):

systemctl restart sshd

Log back onto your remote server and check that the reverse ssh-tunnel is working:

lsof -i :<remote-port>

This should return:

COMMAND     PID USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
sshd   <pid-v4> root    7u  IPv4 00000000      0t0  TCP *:<remote-port> (LISTEN)
sshd   <pid-v6> root    8u  IPv6 00000000      0t0  TCP *:<remote-port> (LISTEN)

You can also use:

netstat -tulpn | grep <remote-port>

which should return:

tcp        0      0 0.0.0.0:<remote-port>           0.0.0.0:*               LISTEN      <pid-v4>/sshd: <remote-username>  
tcp6       0      0 :::<remote-port>                :::*                    LISTEN      <pid-v6>/sshd: <remote-username>

Now you will need to edit your nginx config (use sudo if not logged in as root):

vim /etc/nginx/nginx.conf

Then add this section before the http{} part of the config:

stream {
  server {
     listen [::]:50002 ssl;
     listen 50002 ssl;
     proxy_pass localhost:<remote-port>;
     ssl_certificate /etc/ssl/<remote-ip-or-domain>/server.crt;
     ssl_certificate_key /etc/ssl/<remote-ip-or-domain>/server.key;
     error_log /var/log/nginx/error.log;
  }
}

Now you might be wondering where to get the ssl_certificate and ssl_certificate_key. If you already setup ssl on your Electrum server on your local machine then you can use scp to copy those certificate and keys to your remote server and reuse them.

Otherwise you can create a fresh set of keys (add sudo if not logged in as root):

apt install openssl
mkdir /etc/ssl/<remote-ip-or-domain> 
cd /etc/ssl/<remote-ip-or-domain>/
openssl genrsa -des3 -out server.pass.key 2048
openssl rsa -in server.pass.key -out server.key
rm server.pass.key
openssl req -new -key server.key -out server.csr
openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt
rm server.csr

Now you need to check that you haven't messed up your nginx.conf by running:

nginx -t

This should return:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Now reload the daemon and restart nginx:

systemctl daemon-reload
systemctl restart nginx

Now you should check the status of nginx:

systemctl status nginx

If you get something like this:

nginx: [emerg] bind() to 0.0.0.0:50002 failed (98: Address already in use)

Then it means you are re-using one of your ports. Stop nginx and have a look at:

lsof -i :50002

with nginx stopped there shouldn't be anything running on your remote server over that port. If there is then you might need to change the listen port in your stream nginx config.

Now in order for someone to use your public facing Electrum server they will need to enter use <remote-ip-or-domain>:50002. This means that you will need to open traffic over port 50002:

apt install ufw
ufw status
ufw allow 50002
ufw status

You will also want to look into some basic server security:

Acknowledgements

Thanks to wiz and emzy for helping me when I was setting this up for myself.

Issues

If you need help with this guide you can create an issue here and I will help you there.

🧡
Found this post helpful? Consider sending the author a tip
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ