BTCPay Server Setup Guide With Private WebHost



Last updated: April 12th, 2026

 btcpay-server-setup

A complete walkthrough of setting up your own BTCPay Server from scratch — no third-party processors, no KYC, and full custody of every payment from day one.

Video

01) Why Self-Host BTCPay Server?

Most payment processors sit between you and your customer. They hold your funds, collect transaction data, require identity verification, and can terminate your account without notice. BTCPay Server eliminates every one of those risks.

  • No third-party fees — you keep 100% of every payment. No processor cut.
  • No KYC — customer payment data never touches a third-party server.
  • Full custody — payments go directly to your wallet. No intermediary holds funds.
  • No censorship risk — no payment processor can deplatform or freeze you.
  • Privacy — all transaction data stays on your own infrastructure.
  • Open source — the code is fully auditable. Nothing is hidden.
  • Monero-native — BTCPay is one of the few self-hosted options with proper XMR support, making it ideal for merchants who want to accept privacy payments without relying on custodial services.

02) Choosing a VPS

BTCPay Server runs a full Monero node alongside its own services, so you need a reasonably specified server. The specs used in this guide:

Spec Value
RAM 4096 MB
CPU 4 Cores
Storage 160 GB
Traffic 1024 GB/month
IPv4 SERVER_IP
Hostname YOURSUBDOMAIN.YOURDOMAIN.com

160 GB is sufficient for a pruned Monero node. 4 GB RAM handles the wallet RPC and BTCPay services comfortably. 4 CPU cores keeps sync time reasonable during the initial blockchain scan.

Direct link to the Standard plan: https://privateweb.is/cart.php?a=add&pid=570 (affiliate)

Note: BTCPay Server runs Monero as a pruned node by default, which significantly reduces storage requirements compared to a full archive node.

03) DNS Configuration with Bunny.net

Before running the BTCPay install script, your domain must already be pointing at the server. The installer uses the domain to provision a Let's Encrypt SSL certificate — if DNS isn't resolving correctly at install time, the cert will fail and setup will error out.

  1. Log into your Bunny.net DNS panel.
  2. Create an A record for btcpay.YOURDOMAIN.com (or whatever you want it to be) pointing to your server's IPv4 address.
  3. Allow a few minutes for propagation before proceeding.
  4. Verify the domain resolves to your server IP before running the installer.

04) Installing the OS

Select Ubuntu LTS (22.04 or 24.04) when provisioning your server. BTCPay Server's Docker-based install is tested and documented for Ubuntu LTS and it is the most reliable choice.

Provision the server through your hosting panel. Once it shows as online, proceed to set up SSH access before doing anything else.

05) SSH Key Setup & First Login

Logging in with an SSH key is more secure than a password and eliminates brute-force risk. Generate a key locally before touching the server.

On Windows (PowerShell)

PowerShell
ssh-keygen -t ed25519 -C "btcpay"
type $env:USERPROFILE\.ssh\id_ed25519.pub

On Linux

Bash
ssh-keygen -t ed25519 -C "btcpay"
cat ~/.ssh/id_ed25519.pub

Copy the output of the pub file. Add it to your server either through your hosting panel's SSH key manager, or by pasting it into ~/.ssh/authorized_keys on the server.

Connect to the server

Bash
ssh root@YOUR_SERVER_IP

06) Preparing the Server

Before installing BTCPay, update all packages and configure the firewall.

Update the system

Bash
apt update && apt upgrade -y
reboot

Wait for the server to come back online after the reboot, then reconnect via SSH.

Configure the firewall

Bash
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw allow http
ufw allow https
ufw enable
Important: Make sure ufw allow ssh is run before ufw enable, or you will lock yourself out of the server.

07) Installing BTCPay Server

BTCPay Server is installed via a Docker-based setup script. Clone the repository, set your environment variables, then run the installer.

Bash
git clone https://github.com/btcpayserver/btcpayserver-docker
cd btcpayserver-docker
export BTCPAY_HOST="btcpay.yourdomain.com"
export BTCPAYGEN_CRYPTO1="xmr"
export BTCPAYGEN_ADDITIONAL_FRAGMENTS="opt-add-tor"
export BTCPAYGEN_REVERSEPROXY="nginx"
export BTCPAY_ENABLE_SSH=true
. ./btcpay-setup.sh -i

Replace btcpay.yourdomain.com with your actual domain. The installer will pull all required Docker images, configure Nginx as a reverse proxy, and provision your SSL certificate automatically via Let's Encrypt.

BTCPAYGEN_CRYPTO1="xmr" sets Monero as the primary currency. BTCPay will spin up a Monero daemon and wallet RPC container alongside its own services.

08) Accessing the Portal & Creating an Account

Once the installer finishes, navigate to your domain in a browser. You'll be presented with the BTCPay Server registration page. The first account created automatically becomes the server admin — fill in your details and create it.

There is no email verification by default. You are in full control of the instance from this point.

09) Creating a Store

Stores in BTCPay Server are the containers for your payment configuration. Each store has its own wallet, invoice settings, and API keys.

  1. From the dashboard, click Create a new store.
  2. Give the store a name and set your preferred display currency (e.g. USD, EUR).
  3. Configure invoice expiry and payment tolerance as needed.
  4. Save the store — you'll connect the wallet in the next step.

10) Setting Up the Wallet with the Right Block Height

This is the most critical step of the entire setup. Getting it wrong means the wallet will fail to sync and invoices will not work.

BTCPay Server runs a pruned Monero node. A pruned node does not store the full blockchain from block zero — it only stores data from a certain block height onwards. When you restore a wallet, the wallet RPC needs to know which block to start scanning from. If you tell it to scan from a block that the pruned node does not have data for, the sync will fail.

Critical: Always check the pruned node's oldest block height before entering a restore height. Use the command below and look for the blockchain offset value — in this guide it was 3516300. Enter this value (or higher) as your restore height when setting up the wallet.

Check node sync status and blockchain offset

Bash
docker exec btcpayserver_monerod monerod status

Look for the pruning seed and blockchain offset in the output. Use the offset value as your restore height — do not use the current sync height, use the oldest block the pruned node holds.

Check wallet logs

Bash
docker logs btcpayserver_monero_wallet --tail 30

Verify wallet primary address

Bash
docker exec btcpayserver_monero_wallet curl -s http://localhost:18082/json_rpc \
  -d '{"jsonrpc":"2.0","id":"0","method":"get_address","params":{"account_index":0,"address_index":[0]}}' \
  -H 'Content-Type: application/json'

This confirms the wallet container is running and returns the primary address. Cross-check this against the address shown in BTCPay's store wallet settings.

Reset wallet if restore height was set incorrectly

If you entered the wrong restore height and the wallet is stuck, you need to delete the wallet files and clear the invoice address table before starting fresh:

Bash
docker stop btcpayserver_monero_wallet
rm -f /var/lib/docker/volumes/generated_xmr_wallet/_data/wallet
rm -f /var/lib/docker/volumes/generated_xmr_wallet/_data/wallet.keys
rm -f /var/lib/docker/volumes/generated_xmr_wallet/_data/password
docker exec -it $(docker ps -q -f name=postgres) psql -U postgres \
  -d btcpayservermainnet \
  -c "DELETE FROM \"AddressInvoices\";"
docker start btcpayserver_monero_wallet
Warning: This clears all wallet data and address assignments. Only do this before any live payments have been processed, or if you are deliberately replacing the wallet with a new one.

11) Waiting for Sync

After the wallet is configured with the correct restore height, the Monero wallet RPC will begin scanning the blockchain from that block forward. This process takes time — in this guide it took approximately 4 days on the hardware listed above.

Monitor progress via the wallet logs:

Bash
docker logs btcpayserver_monero_wallet --tail 30
Important: Invoices will not detect payments until the wallet RPC has fully scanned the blockchain up to the current tip. Do not go live until sync is complete.

12) Creating an Invoice

Once synced, you can create invoices manually from the BTCPay dashboard or programmatically via the API.

To create one manually: navigate to your store, click Invoices in the sidebar, then Create Invoice. Set the amount and currency, optionally add an order ID or buyer email, and click save. BTCPay generates a Monero address and payment QR code automatically.

Payments are detected on-chain and the invoice status updates in real time once the wallet is fully synced.

13) API Keys & Webhooks

Generate an API key

  1. Go to AccountManage AccountAPI Keys.
  2. Click Generate Key and select the permissions your application needs (e.g. create invoices, view stores).
  3. Copy and store the key securely — it is only shown once.

Set up a webhook

  1. In your store, go to SettingsWebhooksCreate Webhook.
  2. Enter your endpoint URL — this is the URL BTCPay will POST to when events occur.
  3. Select the events to listen for — at minimum InvoiceSettled and InvoiceExpired.
  4. BTCPay signs webhook payloads with HMAC-SHA256 using a secret you define. Validate this signature on your server.

Create an invoice via the API

Example — Create Invoice (curl)
curl -X POST "https://btcpay.yourdomain.com/api/v1/stores/YOUR_STORE_ID/invoices" \
  -H "Authorization: token YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "10.00",
    "currency": "USD",
    "metadata": { "orderId": "order_123" }
  }'

14) Point of Sale

BTCPay's Point of Sale app creates a public-facing storefront with product listings and a checkout flow — no custom development required.

  1. In your store, go to AppsCreate App → select Point of Sale.
  2. Add products with names, prices, and optional images.
  3. BTCPay generates a public URL for the storefront automatically.
  4. Customers browse products, add to cart, and checkout — a Monero invoice is created for each order.
  5. Place a test order to confirm the full payment flow end-to-end.
  6. Confirmed orders appear in the BTCPay dashboard under Invoices with full payment details.

15) Maintenance

Service management

Bash
btcpay-down.sh        # Stop all services
btcpay-up.sh          # Start all services
btcpay-restart.sh     # Restart all services
btcpay-update.sh      # Update BTCPay Server

Upgrading BTCPay Server

Always review the release notes before upgrading. Look for any breaking changes, particularly around wallet configuration or Docker image changes that could affect Monero node compatibility.

Run the update script, then verify that the server, node, and wallet are all functioning correctly before considering the upgrade complete.

Bash
btcpay-update.sh

Full reset (preserving blockchain data)

If you need to reset BTCPay's application data without re-downloading the Monero blockchain:

Bash
btcpay-down.sh
docker volume rm generated_btcpay_datadir
docker volume rm generated_btcpay_pluginsdir
docker volume rm generated_xmr_wallet
btcpay-up.sh
Note: This removes all BTCPay application data and wallet files but leaves the Monero blockchain data intact, so you won't need to re-sync the node. You will however need to reconfigure your wallet restore height again after the reset.

16) Changing the Wallet

If you need to swap the wallet attached to a store — for example to move to a new seed — go to Store SettingsMoneroModify.

Enter your new wallet seed and, critically, set the correct restore height for the replacement wallet. The same rule applies as during initial setup: use the blockchain offset from the pruned node, not the current sync height.

Bash — Check blockchain offset before entering restore height
docker exec btcpayserver_monerod monerod status
Reminder: The blockchain offset in this guide is 3516300. Enter this value or higher as the restore height when setting up any replacement wallet on the same node. Entering a block lower than the pruned node's oldest block will cause the wallet to fail to sync.


Comments

No Comments

CAPTCHA



Subscribe To Our Newsletter!

Monero Directory | Monerica Blog Sitemap | Contact


Disclaimer: some links may be affiliate links, in which we receive compensation.