Run your personal Bitcoin and Lightning Network node, self-host open source apps, cut out the middlemen, and use Bitcoin to its full potential. For free. — Umbrel
Update (May 23rd, 2023): This guide has been popular for nearly two years! However, Umbrel has changed significantly since it was written. People have informed me that these instructions are no longer directly compatible. Please use this guide for general direction and understanding the concepts, but do not follow it as exact step-by-step instructions for current Umbrel versions.
Running BTCPay Server on your Umbrel node is fantastic, but accessing it securely from outside your home network using a custom domain requires a bit more setup. This guide walks through how I configured NGINX as a reverse proxy along with a free Let's Encrypt SSL certificate to achieve just that.
Prerequisites
Before we start, make sure you have:
- A fully installed and running Umbrel node.
- The BTCPayServer app installed and enabled via the Umbrel UI.
- A domain name you own and can manage DNS for.
For the examples below, I'll use these placeholder values (replace them with your own!):
- Your home's public IP:
100.100.100.100 - Umbrel's internal IP:
10.10.10.10 - Your domain name:
jorijn.com - The desired subdomain for BTCPay Server:
btcpay.jorijn.com
Step 1: Pointing your domain to your home IP
Head over to your domain registrar's control panel or DNS provider. You need to
edit the DNS zone for your domain (jorijn.com in my example) and add a new A
record. This record should point your chosen subdomain (btcpay part) to your
home's public IP address (100.100.100.100).

Important: DNS changes can take time to propagate across the internet – sometimes up to 24 hours, though often much faster. Only proceed once you can confirm the change is live globally.
Step 2: Verifying the DNS change
You can use an online tool like dnschecker.org to see if your new A record has propagated.
Simply enter your full BTCPay Server domain (e.g., btcpay.jorijn.com), select
'A' record type, and hit Search. You should see your home IP address appearing
across most locations.
https://dnschecker.org/#A/btcpay.jorijn.com
Step 3: Setting up port forwarding on your router
To allow external access for issuing the SSL certificate (Let's Encrypt) and later for accessing BTCPay Server, we need to forward specific ports from your internet router to your Umbrel node's internal IP address. The exact steps depend heavily on your router's make and model – consult its manual or interface.
First, find your Umbrel's internal IP. You can usually find this in your
router's connected devices list, or by logging into Umbrel via SSH and running a
command like ip addr show wlan0 (if on WiFi) or ip addr show eth0 (if
wired).
umbrel@umbrel:~ $ ip addr show wlan0
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether dc:a6:32:a4:91:8c brd ff:ff:ff:ff:ff:ff
inet **10.10.10.10**/24 brd 192.168.121.255 scope global dynamic noprefixroute wlan0
# [...]
In this example, the internal IP is 10.10.10.10.
Now, create two port forwarding rules in your router settings:
- HTTP Traffic for NGINX & Let's Encrypt:
- Name:
NGINX HTTP(or similar) - Forward external port
80(standard HTTP) to Umbrel IP10.10.10.10on internal port15080. - Protocol:
TCP
- Name:
- HTTPS Traffic for NGINX & Let's Encrypt:
- Name:
NGINX HTTPS(or similar) - Forward external port
443(standard HTTPS) to Umbrel IP10.10.10.10on internal port15443. - Protocol:
TCP
- Name:
(Why these internal ports? We'll configure NGINX to listen on 15080 and 15443 later to avoid conflicts with Umbrel's main web server which already uses 80 and 443 internally).
Step 4: Installing NGINX & Certbot on Umbrel
Now, let's SSH into your Umbrel node again. First, it's always a good idea to update the package list:
umbrel@umbrel:~ $ sudo apt update
# ... (output omitted) ...
Next, install NGINX (the reverse proxy) and Certbot (for Let's Encrypt SSL certificates) along with their dependencies:
umbrel@umbrel:~ $ sudo apt install python3-acme python3-certbot python3-mock python3-openssl python3-pkg-resources python3-pyparsing python3-zope.interface python3-certbot-nginx nginx
# ... (output omitted) ...
Don't worry if the installation seems to fail or hang at the end! This is expected because Umbrel's main web server is already using port 80 internally, which NGINX tries to bind to by default.
We need to tell NGINX to use a different default port. Edit the default NGINX configuration file:
umbrel@umbrel:~ $ sudo sed -i 's/80 default_server/15080 default_server/g' /etc/nginx/sites-available/default
(This command replaces 80 default_server with 15080 default_server in the
file).
Now, finish the installation process (this usually fixes dependencies and completes the setup):
umbrel@umbrel:~ $ sudo apt install -f
After this, you should be able to access the default NGINX welcome page by
Browse to your Umbrel's internal IP on port 15080, e.g.,
http://10.10.10.10:15080/.
Step 5: Creating the NGINX configuration for BTCPay Server
We need to tell NGINX how to handle requests for your btcpay.jorijn.com domain
and pass them through to the internal BTCPay Server application running on
Umbrel (which typically listens on port 3003).
Create a new NGINX configuration file specifically for your BTCPay site:
umbrel@umbrel:~ $ sudo nano /etc/nginx/sites-available/btcpay
Paste the following configuration into the editor. Make sure to replace
btcpay.jorijn.com with your actual domain!
# Set higher buffer sizes for BTCPay Server potentially large headers/requests
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
client_header_buffer_size 500k;
large_client_header_buffers 4 500k;
http2_max_field_size 500k;
http2_max_header_size 500k;
# Required for WebSocket support (used by BTCPay)
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
# IMPORTANT: Change this to your domain
server_name btcpay.jorijn.com;
location / {
# Forward requests to the internal BTCPay Server app
proxy_pass [http://127.0.0.1:3003](http://127.0.0.1:3003);
# Set headers to pass correct information to BTCPay
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket headers
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
# Listen on the internal port we forwarded earlier (for HTTP)
listen 15080;
listen [::]:15080; # Also listen on IPv6
# SSL configuration will be added here by Certbot later
}
Save the file (CTRL+O in nano, then Enter) and exit the editor (CTRL+X).
Now, enable this new configuration by creating a symbolic link:
umbrel@umbrel:~ $ sudo ln -s /etc/nginx/sites-available/btcpay /etc/nginx/sites-enabled/
Test that your NGINX configuration syntax is still correct:
umbrel@umbrel:~ $ sudo nginx -t
# Expect output like: nginx: configuration file /etc/nginx/nginx.conf test is successful
If the test is successful, reload NGINX to apply the new configuration:
umbrel@umbrel:~ $ sudo systemctl reload nginx.service
Step 6: Requesting your SSL certificate with Certbot
Now we use Certbot to automatically obtain a free SSL certificate from Let's Encrypt and configure NGINX to use it for HTTPS.
Run the following command, replacing btcpay.jorijn.com with your domain and
jorijn@jorijn.com with your email address (Let's Encrypt uses this for
renewal reminders).
umbrel@umbrel:~ $ sudo certbot --nginx -d btcpay.jorijn.com -m jorijn@jorijn.com --agree-tos --no-eff-email --tls-sni-01-port 15443 --http-01-port 15080
--nginx: Use the NGINX plugin to automatically configure NGINX.-d: Specify the domain name.-m: Your email address.--agree-tos: Agree to the Let's Encrypt Terms of Service.--no-eff-email: Optional: Avoid subscribing to the EFF newsletter.--tls-sni-01-port 15443: Tell Certbot to perform validation challenges via the internal HTTPS port we forwarded earlier.--http-01-port 15080: Tell Certbot to use the internal HTTP port for validation if needed.
Certbot will likely ask if you want to redirect HTTP traffic to HTTPS. For now, choose option 1: No redirect. We will configure this manually in the next step for better control.
If successful, Certbot will tell you it has deployed the certificate and updated your NGINX configuration.
Step 7: Manually adding the HTTP-to-HTTPS redirect
To ensure all visitors use the secure HTTPS connection, we'll manually add a
redirect rule. This forces any traffic hitting the non-secure port 15080 for
your domain to be redirected to the secure port 15443 (which your router
forwards from 443).
Open your BTCPay NGINX configuration file again:
umbrel@umbrel:~ $ sudo nano /etc/nginx/sites-available/btcpay
Certbot should have added lines related to SSL and listening on port 15443
inside the original server { ... } block. We need to add a new server
block below the existing one to handle the redirect.
Paste the following block at the end of the file. Remember to replace
btcpay.jorijn.com twice with your domain!
# This new server block handles the redirect
server {
listen 15080;
listen [::]:15080;
# IMPORTANT: Change this to your domain
server_name btcpay.jorijn.com;
# If the host matches, permanently redirect to HTTPS
if ($host = btcpay.jorijn.com) {
return 301 https://$host$request_uri;
}
# Return 404 for other requests to this port (optional but good practice)
return 404;
}
Save the file (CTRL+O, Enter) and exit (CTRL+X).
Finally, test the configuration again and reload NGINX:
umbrel@umbrel:~ $ sudo nginx -t
# Expect success message
umbrel@umbrel:~ $ sudo systemctl reload nginx.service
That's it! Your BTCPay Server should now be securely accessible via HTTPS at
your custom domain, e.g., https://btcpay.jorijn.com/.
The Pay Button and Beyond
Now that NGINX is handling the domain and SSL, BTCPay Server should
automatically generate the correct embed codes (like the Pay Button code) using
your https://btcpay.jorijn.com domain. You can grab these from your BTCPay
Server interface and integrate them into your website.
Hopefully, this guide helps you get your own secure setup running! Remember this guide might be outdated for the latest Umbrel versions, so adapt as needed.
