Apache Reverse Proxy to Tor for LNBits or BTCPay Server

Apache Reverse Proxy to Tor for LNBits or BTCPay Server

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).

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.

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)
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

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

Webserver setup

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 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

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.

Let me know if you experience any issues or need an update.
Doug — find me at https://BrewsBitcoin.com and on Twitter @brewsbitcoin

2 Likes

A followup here - if you want to do this for multiple apps on Tor, then create a separate conf file for each service like lnbits or btcpayserver. In the conf file, keep the Proxy_Port as 9050 and just change to Local_Port to a new number such as 9082. Then replace lnbits for btcpayserver thru the rest of the configs and you should be good to go. You’ll end up with one instance of TOR running and several SOCAT running depending on how many apps you have proxied - check this with the NETSTAT -TUNLP | GREP SOCAT (or TOR) command.

2 Likes
sudo a2enmod rewrite

and

sudo a2enmod headers

Was required. to get apache to restart.

Noted. I think had that enabled prior to writing this. I’ll add to the doc. Thanks!

I was able to access the domain at first, but now it is only accessible using the .local. Do I need to change the server settings - domain name to the tor address? How would I do that through embassy?

Update, it wasn’t accessible after a reboot due to proxy not running; ran

systemctl enable http-to-socks-proxy@btcpayserver

To start on reboot. Great guide! Thanks for making this.