How to Set Up BTCPay Server on Ubuntu 22.04/20.04 with Docker

BTCPay server is an open-source, self-hosted cryptocurrency payment processor. With BTCPay Server, you don’t need to pay fees to a third-party payment processor, and since it’s peer-to-peer payment, it’s resistant to censorship. This tutorial will be showing you how to set up BTCPay server on Ubuntu.

BTCPay Server Features

  • Your own Bitcoin payment processor.
  • No need to worry about account closure by a third party like Paypal.
  • Get rid of unreasonable fees set by third-party payment processors.
  • Integration with Common eCommerce platforms like Magento, Shopify, WooCommerce, Joomla Virtuemart, Prestashop and Shopware.
  • You can add an unlimited amount of users and stores.
  • Supports the Bitcoin Lightning Network
  • Accepts altcoins.
  • Integration with Quickbooks Online Accounting.
  • Plugins
  • Powerful APIs

Note: With BTCPay Server, you don’t need to pay fees to third-party payment processors (like BitPay) anymore, but there are still Bitcoin transaction fees, which can be reduced by using a Lightning node and another tool called payout processor in BTCPay Server.

Server Requirement

  • At least 2 CPU cores and 4GB RAM
  • 600 GB disk for data storage

We will be using the BTCPay Docker, which simplifies the setup process. It’s not recommended to set up BTCPay manually in a production environment.

Step 1: Install Docker on Ubuntu 22.04 Server

Docker is included in the Ubuntu software repository. However, to ensure that we have the latest version, we will have to install it from Docker’s APT repository. Log into your server via SSH, then run the following command to add the Docker repository to your Ubuntu server.

echo "deb [signed-by=/etc/apt/keyrings/docker.gpg.key arch=amd64] $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list

Next, run the following command to import the Docker GPG key to Ubuntu system so that APT can verify package integrity during installation.

wget --quiet -O - | sudo tee /etc/apt/keyrings/docker.gpg.key

And because this repository uses HTTPS connection, which I recommend all software repositories should be using, we also need to install apt-transport-https and ca-certificates package.

sudo apt install apt-transport-https ca-certificates

Finally, update the package index on your Ubuntu system and install docker-ce (Docker Community Edition).

sudo apt update

sudo apt install docker-ce

Once Docker is installed, the Docker daemon should be automatically started. You can check its status with:

systemctl status docker

Ubuntu Docker Application Container Engine

If it’s not running, then start the daemon with the following two commands:

sudo systemctl restart docker.socket
sudo systemctl restart docker.service

And enable autostart at boot time:

sudo systemctl enable docker

Check Docker version.

docker -v

Sample output:

Docker version 20.10.18, build 370c289

Step 2: Install and Start the BTCPay Docker Container

This step must be executed as the root user, so switch to root.

sudo su -

Clone the BTCPay Server Github repository.

sudo apt install git

cd ~

git clone

It will be saved under the ~/btcpayserver-docker/ directory. Change to this directory.

cd ~/btcpayserver-docker/

Before starting the BTCPay Docker container, we need to set several environment variables by running the following commands one by one.

export BTCPAY_HOST=""

export NBITCOIN_NETWORK="mainnet"

export BTCPAYGEN_CRYPTO1="btc"





export is a Linux shell command that set environment variables.


  • BTCPAY_HOST: You need to replace with your preferred hostname for your BTCPay instance. For example, I use
  • NBTICOIN_NETWORK: choose to run on mainnet, testnet or regnet. You need to run on mainnet in production environment.
  • BTCPAYGEN_CRYPTO01: Choose the crypto coin your BTCPAY instance will support. For now, you can choose BTC. Altcoins can be added later.
  • BTCPAYGEN_REVERSEPROXY: You can choose among nginx, traefix and emtpy: We don’t want the Docker container to act as reverse proxy. We can use existing Nginx web server as reverse proxy.
  • BTCPAYGEN_EXECLUDE_FRAMENTS: We don’t want the Docker container to generate TLS certificates. We will obtain and install a free Let’s Encrypt TLS certificate later.
  • BTCPAYGEN_LIGHTING: You can use lnd or clightning for lightning networking support
  • BTCPAY_ENABlE_SSH: Allow BTCPAY to manage SSH authorized keys.

To check the value of an environment variable, you can use the echo command. For example.


Next, run the following command to install and start the BTCPay Docker container.

. ./ -i

Sample output:

Installed to /usr/local/bin: Command line for your Bitcoin instance
Installed to /usr/local/bin: Command line for your Bitcoin LND instance
Installed to /usr/local/bin: Command line for deleting old unused docker images
Installed to /usr/local/bin: Command line for stopping all services related to BTCPay Server
Installed to /usr/local/bin: Command line for restarting all services related to BTCPay Server
Installed to /usr/local/bin: Command line for restarting all services related to BTCPay Server
Installed to /usr/local/bin: Command line for starting all services related to BTCPay Server
Installed to /usr/local/bin: Command line for some administrative operation in BTCPay Server
Installed to /usr/local/bin: Command line for updating your BTCPay Server to the latest commit of this repository
Installed to /usr/local/bin: Command line for changing the external domain of your BTCPay Server

Check systemd service status:

sudo systemctl status btcpayserver.service


ubuntu btcpay server systemd service

Check Docker containers:

sudo docker ps


btcpay server docker containers

As you can see, the btcpayserver/btcpayserver Docker container doesn’t expose the port to the host OS. Edit the Docker Compose file.

nano ~/btcpayserver-docker/Generated/docker-compose.generated.yml

Add the following lines in the btcpayserver section.

    - "49392:49392"

Like this:

btcpay server docker container export network port to host

Save and close the file. Then restart btcpayserver.service.

sudo systemctl restart btcpayserver

Now check the Docker container status again.

sudo docker ps

You will see that the host OS port 49392 is mapped to the Docker port 49392.

CONTAINER ID   IMAGE                              COMMAND                  CREATED          STATUS          PORTS                      
cf182b7d5e6f   btcpayserver/btcpayserver:1.6.11   "/app/docker-entrypo…"   14 minutes ago   Up 14 minutes>49392/tcp

If made an error in the environment variables, you can change them, then run the setup script again and restart btcpayserver.service.

Step 3: Configure Nginx Reverse Proxy

Install Nginx web server from the default Ubuntu software repository.

sudo apt install -y nginx

Create an Nginx virtual host file for BTCPay Server.

sudo nano /etc/nginx/conf.d/btcpay-server.conf

Add the following lines in this file.

# If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the
# scheme used to connect to this server
map $http_x_forwarded_proto $proxy_x_forwarded_proto {
  default $http_x_forwarded_proto;
  ''      $scheme;
# If we receive X-Forwarded-Port, pass it through; otherwise, pass along the
# server port the client connected to
map $http_x_forwarded_port $proxy_x_forwarded_port {
  default $http_x_forwarded_port;
  ''      $server_port;
# If we receive Upgrade, set Connection to "upgrade"; otherwise, delete any
# Connection header that may have been passed to this server
map $http_upgrade $proxy_connection {
  default upgrade;
  '' close;
# Apply fix for very long server names
server_names_hash_bucket_size 128;
# Prevent Nginx Information Disclosure
server_tokens off;
# Default dhparam
# Set appropriate X-Forwarded-Ssl header
map $scheme $proxy_x_forwarded_ssl {
  default off;
  https on;

gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
log_format vhost '$host $remote_addr - $remote_user [$time_local] '
                 '"$request" $status $body_bytes_sent '
                 '"$http_referer" "$http_user_agent"';
access_log off;
# HTTP 1.1 support
proxy_http_version 1.1;
proxy_buffering off;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;
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 $proxy_x_forwarded_proto;
proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
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;
# Mitigate httpoxy attack (see README for details)
proxy_set_header Proxy "";

server {
        listen 80;

        access_log /var/log/nginx/btcpay.access;
	error_log /var/log/nginx/btcpay.error;
        client_max_body_size 100M;

        # Here is the main BTCPay Server application
        location / {

        # Include the next two stanzas if and only if you want to expose your lightning gRPC & RPC interfaces to the internet
        #location /lnrpc.Lightning {
        #        grpc_pass grpcs://;

        #location /lnd-rest/btc/ {
        #        rewrite ^/lnd-rest/btc/(.*) /$1 break;
        #        proxy_pass;

        # Include this stanza if you are planning to set up Ride The Lightning (RTL)
        location /rtl/ {

Save and close the file. Then test Nginx configurations.

sudo nginx -t

If the test is successful, reload Nginx.

sudo systemctl reload nginx

Step 4: Enable HTTPS

To encrypt HTTP traffic, we can enable HTTPS by installing a free TLS certificate issued from Let’s Encrypt. Run the following command to install Let’s Encrypt client (certbot) on Ubuntu server.

sudo apt install certbot python3-certbot-nginx

Next, run the following command to obtain and install TLS certificate.

sudo certbot --nginx --agree-tos --redirect --hsts --staple-ocsp --email [email protected] -d


  • --nginx: Use the nginx plugin.
  • --agree-tos: Agree to terms of service.
  • --redirect: Force HTTPS by 301 redirect.
  • --hsts: Add the Strict-Transport-Security header to every HTTP response. Forcing browser to always use TLS for the domain. Defends against SSL/TLS Stripping.
  • --staple-ocsp: Enables OCSP Stapling. A valid OCSP response is stapled to the certificate that the server offers during TLS.

The certificate should now be obtained and automatically installed.

btcpay server https certbot

Step 5: Using the BTCPay Server Web Interface

Now you can go to to register an admin account.

Create admin account btcpay server

Once the admin account is created, BTCPay Server automatically disables new user registration. You can re-enable it if you want to.

On the bottom-right corner, you can check the Bitcoin node syncing status.

btcpay server bitcoin node syncing

It’s recommended to wait for this process to finish before doing anything else in the BTCPay server dashboard.

Step 6:

Now you need to

  • create a store
  • create a wallet
  • set up lighting node

Click the Create Store button to get started. If you don’t own an e-commerce store, you can still create a store on BTCPAY server. A store is an entity that will recieve payment from others.

btcpay create store

Next, click the Set up a wallet button.

btcpay set up a wallet

You can import your existing wallet or create a new wallet. Even though I have an existing Bitcoin, I still prefer to create a new wallet on BTCPAY Server.

btcpay watch only wallet

There are two types of wallets you can create:

  • Hot wallet
  • Watch-only wallet

I choose to create a watch-only wallet as it’s more secure.

btcpay server create watch-only wallet

There are 4 address types:

  • Segwit
  • Segwit Wrapped
  • Legacy
  • Taproot

I choose the recommended Segwit address type. You can also set a passphrase for your wallet to make it more secure.

btcpay wallet address type

Then BTCPAY will display the recover phrase for your wallet. You need to write it down on paper and store it safely. Click the Done button and the wallet is created.

Next, click the set up a lighting node button. You can choose to use the BTCPAY internal lightning node or use a custom lightning node. I choose the easy route: Use internal node. Click the Save button.

btcpay set up lightning node

In the BTC Lightning Settings page, you can enable Lightning URL (LNURL) for invoices.

btcpay server LNURL for invoice

How to Upgrade BTCPAY Server

When a new version of BTCPay Server is released, run the following command as root to update it.

Then edit the Docker Compose file.

sudo nano /root/btcpayserver-docker/Generated/docker-compose.generated.yml

Add the following lines in the btcpayserver section.

    - "49392:49392"

Like this:

btcpay server docker container export network port to host

Save and close the file. Then restart btcpayserver.service.

sudo systemctl restart btcpayserver

Wrapping Up

I hope this tutorial helped you set up BTCPAY on Ubuntu. As always, if you found this post useful, then subscribe to our free newsletter to get more tips and tricks. Take care 🙂

Rate this tutorial
[Total: 7 Average: 5]

5 Responses to “How to Set Up BTCPay Server on Ubuntu 22.04/20.04 with Docker

  • Hello,
    How do we accept other crypto like USDT Tron| USDT ERC20,, how do we accept ETH for example? is there a way to do it ?

    • Sorry, I just noticed that it’s CRYPTO and not CRYPT0(zero)… 🙂

  • Hi, im using ubuntu server 22.04 and got an error:
    BTCPAYGEN_CRYPT01 should not be empty
    But when I do:
    I got:
    Any advice?

  • You don’t have to edit /root/btcpayserver-docker/Generated/docker-compose.generated.yml after each update. It’s possible to create a custom fragment which will keep ports exposed after updates. To do so you should create a fragment inside /root/btcpayserver-docker/docker-compose-generator/docker-fragments. For example, create fragment named opt-expose-btcpayserver.custom.yml(it’s important that fragment ends with .custom.yml). Inside fragment add:
    – “49392:49392″

    Save file and then do following:
    . ./ -i

  • AgainsTurb
    7 months ago

    whe i try to execute sudo certbot –nginx –agree-tos –redirect –hsts –staple-ocsp –email [email protected] -d
    (I have replaced my email in my code)
    I get
    nginx restart failed:
    nginx: [emerg] “server_names_hash_bucket_size” directive is duplicate in /etc/nginx/conf.d/btcpay.againsturb.domain
    how can i fix this?

Leave a Comment

  • Comments with links are moderated by admin before published.
  • Your email address will not be published.
  • Use <pre> ... </pre> HTML tag to quote the output from your terminal/console.
  • Please use the community ( for questions unrelated to this article.
  • I don't have time to answer every question. Making a donation would incentivize me to spend more time answering questions.

The maximum upload file size: 2 MB. You can upload: image. Links to YouTube, Facebook, Twitter and other services inserted in the comment text will be automatically embedded. Drop file here