Deploying BTCPay Server
BTCPay Server is a self-hosted open-source payment processor. No processor fees, no third-party dependency, full control over keys. Supports Bitcoin, Lightning Network, Monero, Litecoin, and dozens of other coins via plugins. Well suited for stores, donations, invoice issuance.
This is not a trivial CRUD deployment. BTCPay pulls Bitcoin Core (or Neutrino), NBXplorer (custom indexer), Postgres, and optionally LND/CLN/Eclair for Lightning. The full stack on Docker Compose takes 15–30 GB on disk and requires 4+ GB RAM just for syncing.
Server Requirements
| Configuration | RAM | Disk | CPU |
|---|---|---|---|
| Minimum (mainnet, no Lightning) | 4 GB | 700 GB HDD / 500 GB SSD | 2 vCPU |
| Recommended (with Lightning) | 8 GB | 700 GB SSD | 4 vCPU |
| For high load | 16+ GB | 1 TB NVMe | 8 vCPU |
Bitcoin Core on mainnet requires ~600–650 GB for a full node. You can use a pruned node (saves space), but then BTCPay cannot rescan — if an address is added after sync, old transactions won't be visible. For receiving new payments, a pruned node works correctly.
OS: Ubuntu 22.04 LTS or Debian 12 — officially supported.
Installation via BTCPay Server Configurator (Docker)
The official and recommended way:
# Install dependencies
apt-get update && apt-get install -y curl git
# Download and run installer
curl -sSL https://btcpayserver.org/install.sh | sudo bash
This runs an interactive configurator. But it's better to understand what's happening under the hood and do it manually:
# Clone configs
git clone https://github.com/btcpayserver/btcpayserver-docker
cd btcpayserver-docker
# Set environment variables
export BTCPAY_HOST="pay.yourdomain.com"
export NBITCOIN_NETWORK="mainnet"
export BTCPAYGEN_CRYPTO1="btc"
export BTCPAYGEN_LIGHTNING="lnd" # or clightning, eclair
export BTCPAYGEN_REVERSEPROXY="nginx" # nginx with automatic Let's Encrypt
export BTCPAYGEN_ADDITIONAL_FRAGMENTS="opt-save-storage" # pruned node
# For additional coins:
# export BTCPAYGEN_CRYPTO2="ltc"
. ./btcpay-setup.sh -i
The opt-save-storage flag enables pruned Bitcoin Core (256 MB pruning). If you need a full node — don't add this fragment.
DNS and HTTPS Configuration
BTCPay requires a domain name — without it, a Let's Encrypt certificate won't generate, and without HTTPS, Lightning won't work (requires WSS). Delegate DNS before installation:
pay.yourdomain.com A <server-ip>
Check before deploy:
dig +short pay.yourdomain.com
# Should return server IP
Let's Encrypt via certbot is integrated into Docker Compose config automatically when using nginx reverse proxy.
Lightning Network: LND vs CLN
LND (Lightning Network Daemon, Go) — more common, better documented for developers, has REST and gRPC API, integrations with most tools. I recommend for new projects.
CLN (Core Lightning, C) — more lightweight, modular architecture via plugins, more closely follows BOLT specs. Preferred if you need custom plugins or a routing node.
Both work correctly with BTCPay. The difference is noticeable when integrating third-party services — LND support is more common.
Initial Lightning Setup
After Bitcoin Core syncs:
# Enter LND container
docker exec -it $(docker ps -q -f name=lnd) bash
# Create wallet (seed phrase — save in cold storage!)
lncli create
# Get address for funding
lncli newaddress p2wkh
# After funding: open channels
lncli connect 03...@host:9735
lncli openchannel --node_key=03... --local_amt=1000000 # 0.01 BTC in satoshis
For production Lightning node you need liquidity. Minimum — 3–5 channels with well-connected nodes (ACINQ, WalletOfSatoshi, Bitfinex). For inbound liquidity (receiving payments), you need inbound channels — buy via Lightning Pool or Amboss Magma.
Backups
Three components requiring regular backup:
Bitcoin Core wallet — not critical if used only as a node (keys stored in BTCPay/NBXplorer).
LND channel backups (SCB) — critical. Static Channel Backup allows closing channels if the node is lost. Automatically updated on each channel change:
# Path to SCB file in container
/root/.lnd/data/chain/bitcoin/mainnet/channel.backup
# Set up cron to copy to S3/Backblaze
0 * * * * docker cp $(docker ps -q -f name=lnd):/root/.lnd/data/chain/bitcoin/mainnet/channel.backup /backup/lnd-$(date +%Y%m%d-%H%M).backup
PostgreSQL database — BTCPay stores all store data, invoices, configuration:
# Dump database
docker exec -t btcpayserver_postgres pg_dump -U postgres btcpayserver | gzip > /backup/btcpay-$(date +%Y%m%d).sql.gz
Monitoring
After deploy, add monitoring via BTCPay Health endpoint:
# Health check
curl https://pay.yourdomain.com/health
# Or via API for Grafana/Prometheus monitoring
BTCPay Server has a built-in /server/services page with the status of all services. I recommend setting up external uptime monitoring (UptimeRobot, BetterUptime) on this endpoint.
Complete deploy from zero to working state: server setup + DNS config + BTCPay deploy — 2–4 hours. Bitcoin Core mainnet sync — 12–48 hours depending on disk speed. Lightning setup with channels — another day.







