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:
- UNB22 - 01 - Overview
- UNB22 - 02 - Planning Preparation and Installation of Ubuntu
- UNB22 - 03 - Ubuntu Familiarisation
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.