Reverse Tor Proxy; Use for BTCPay Server, LNBits, and VaultWarden

Author:

The current BTCPayServer documentation shows how to create an Nginx reverse proxy to a Tor site, and it is well-documented and works great. However, I needed (and saw that others also needed) an Apache method of doing this also. I like Nginx but as a DevOp, a lot of my VPS installs already are fully configured with Apache. It would take additional admin overhead to manage an Nginx build on the same box having to remember that I built it, had a different http port assigned, and so on. I also wanted to do this for an LNBits install on a Start9 Embassy server hosted on Tor (it works the exact same way). It works the exact same way for an Umbrel too once you have the BTCPay Server or LNbits onion address by logging into your Umbrel over Tor.

You can also run this for multiple services running concurrently— both LNbits and BTCPay Server (or any other hidden application on Tor) using the same setup with a little modification below. The directions below are written for BTCPay Server but just replace lnbits in each btcpayserver reference and you should be good to go. To run both concurrently, they will need their own conf files and ports but that will be noted below.

The Reverse Proxy setup for Apache is very similar but does have a few differences.

Note: I wrote these in the same format as the BTCPayServer directions so credit to them for doing it well. These directions assume you are using a Start9 Embassy server. Adjust as needed to get your Tor onion address on your own specific server, but you can also use these directions to add your Umbrel clearnet IP after opening up a port forward on your router to the Umbrel using the Dynamic DNS directions (just change out the onion address to the clearnet IP in the SOCAT http-to-socks config file below).

Advantages

  • no port forwarding needed on the LAN of the host
  • encrypted connection
  • hides the IP of the host

Requirements

  • a Virtual Private Server (VPS) — eg. a minimal package on Lunanode for ~3.5$/month. My business uses DigitalOcean.com, and you can get up to $200 in credit over 60 days for using this link to sign up with a Digital Ocean VPS service.
  • root access on the VPS — you need to set up a web server and install packages
  • a domain or subdomain — this will be setup on the proxy web server

Get the Tor .onion address of your BTCPay Server via the Start9 Embassy — click Services, then BTCPay Server, then scroll down and click the Interfaces tab. Copy the Tor Address with the .onion extension.

VPS Setup

You will create an Apache reverse proxy and a socat service, which forwards requests to your BTCPay Server.

Login as root and install the required dependencies: (example assumes a Debian/Ubuntu based Linux system)

# switch to root user (if not logged in as root or use sudo before the commands)
sudo su -

# install dependencies (assumes you don't have apache2 installed)
apt update
apt install -y certbot apache2 socat tor

#add apache proxy modules
a2enmod proxy
a2enmod proxy_http

Socat setup

Create the service file /etc/systemd/system/http-to-socks-proxy@.service:

nano /etc/systemd/system/http-to-socks-proxy@.service

#add the following to the file

[Unit]
Description=HTTP-to-SOCKS proxy
After=network.target

[Service]
EnvironmentFile=/etc/http-to-socks-proxy/%i.conf
ExecStart=/usr/bin/socat tcp4-LISTEN:${LOCAL_PORT},reuseaddr,fork,keepalive,bind=127.0.0.1 SOCKS4A:${PROXY_HOST}:${REMOTE_HOST}:${REMOTE_PORT},socksport=${PROXY_PORT}

[Install]
WantedBy=multi-user.target

#exit and save
ctrl-x, y

Create the configuration for the service in /etc/http-to-socks-proxy/btcpayserver.conf:

# create the directory
mkdir -p /etc/http-to-socks-proxy/

# create the file with the content below
nano /etc/http-to-socks-proxy/btcpayserver.conf

# replace the REMOTE_HOST and adapt the ports as needed
PROXY_HOST=127.0.0.1
PROXY_PORT=9050
LOCAL_PORT=9081
REMOTE_HOST=heregoesthebtcpayserverhiddenserviceaddress.onion
REMOTE_PORT=80

If you want to also connect to another service such as LNbits, create the identical file above but name it lnbits.conf — change the LOCAL_PORT to another number such as 9082. Keep PROXY_PORT the same (9050) as that calls Tor. You will have one Tor instance running no matter how many SOCAT services you create and one SOCAT instance running for each service you connect (one for LNbits and one for BTCPay Server).

Create a symlink in /etc/systemd/system/multi-user.target.wants to enable the service and start it:

# build the symbolic link
ln -s /etc/systemd/system/http-to-socks-proxy\@.service /etc/systemd/system/multi-user.target.wants/http-to-socks-proxy\@btcpayserver.service

# start
systemctl start http-to-socks-proxy@btcpayserver

# check service status
systemctl status http-to-socks-proxy@btcpayserver

# check if tunnel is active
netstat -tulpn | grep socat
# should give something like this:
# tcp 0 0 127.0.0.1:9081 0.0.0.0:* LISTEN 951/socat

#Duplicate the above steps and replace btcpayserver for lnbits if you run them both.
#With the netstat command, you will see two lines for socat on two different ports.

Point domain to the VPS

Create the A record on the DNS server of your domain/subdomain and point it to your VPS IP address. The following directions assume a domain routes directly to BTCPayServer — adjust accordingly.

Prepare Apache, SSL and Let’s Encrypt

Create a config file for the domain, e.g. /etc/apache2/sites-available/btcpayserver.conf

NOTE: don’t forget to update your actual domain name in 3 locations marked <yourdomain> below.

#build the file
nano /etc/apache2/sites-available/btcpayserver.conf

#insert the following for http:80
<VirtualHost *:80>
ServerName <yourdomain>.com
ServerAdmin admin@<yourdomain>.com

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

RewriteEngine on
RewriteCond %{SERVER_NAME} =<yourdomain>.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

#exit and save
ctrl-X, y

We will let Apache create/configure the https file once we obtain the SSL certificate.

Enable the web server config by creating a symlink and restarting apache2:

#build the symbolic link
ln -s /etc/apache2/sites-available/btcpayserver.conf /etc/apache2/sites-enabled/btcpayserver.conf

#confirm the link is built
cd /etc/apache2/sites-enabled
ls -l
#you should see a listing of btcpayserver.conf in blue
#pointing to the sites-available btcpayserver reference

#restart apache
systemctl restart apache2

Obtain SSL certificate via Let’s Encrypt

Run the following command and verifications:

cd /etc/apache2/sites-available
certbot --apache -d <yourdomain>.com
#Follow the prompts to accept Terms of Service and add your admin email

#Once completed, check the directory for the SSL/https version of your config file
ls -l
#you should see two files now
-rw-r--r-- 1 root root 1090 Dec 14 21:53 btcpayserver-le-ssl.conf
-rw-r--r-- 1 root root 412 Nov 29 21:47 btcpayserver.conf

Edit the btcpayserver-le-ssl.conf file

nano /etc/apache2/sites-available/btcpayserver-le-ssl.conf

# note that <yourdomain> should be pre-filled here by the Certbot process
# when creating the SSL certificate
#you should see
<IfModule mod_ssl.c>
<VirtualHost *:443>

ServerName <yourdomain-alreadyfilled>.com
ServerAdmin admin@<yourdomain-alreadyfilled>.com

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

RewriteEngine on
# Some rewrite rules in this file were disabled on your HTTPS site,
# because they have the potential to create redirection loops.

# RewriteCond %{SERVER_NAME} =<yourdomain-alreadyfilled>.com
# RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

SSLCertificateFile /etc/letsencrypt/live/<yourdomain-alreadyfilled>.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/<yourdomain-alreadyfilled>.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf

</VirtualHost>
</IfModule>

Add the following text to the blank line above </VirtualHost>

ProxyRequests Off
ProxyPreserveHost On
<Proxy *>
AddDefaultCharset Off
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://127.0.0.1:9081/
ProxyPassReverse / http://127.0.0.1:9081/
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"

Your file should look like this now:

<IfModule mod_ssl.c>
<VirtualHost *:443>

ServerName <yourdomain-alreadyfilled>.com
ServerAdmin admin@<yourdomain-alreadyfilled>.com

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined


RewriteEngine on
# Some rewrite rules in this file were disabled on your HTTPS site,
# because they have the potential to create redirection loops.

# RewriteCond %{SERVER_NAME} =<yourdomain-alreadyfilled>.com
# RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

SSLCertificateFile /etc/letsencrypt/live/<yourdomain-alreadyfilled>.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/<yourdomain-alreadyfilled>.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf

ProxyRequests Off
ProxyPreserveHost On
<Proxy *>
AddDefaultCharset Off
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://127.0.0.1:9081/
ProxyPassReverse / http://127.0.0.1:9081/
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"

</VirtualHost>
</IfModule>

Restart Apache2

systemctl restart apache2

Now, visiting <yourdomain>.com should show your BTCPay Server instance.

Leave a Reply