Every business that accepts crypto eventually notices the same contradiction. The whole point of being paid in Bitcoin or Monero is that no institution stands between you and the customer — and yet the ordinary way to accept it is to sign up with a company that takes the payment first, holds it, converts it, verifies you, and forwards what is left. You have swapped a bank for a startup with a shorter memory and a longer list of prohibited businesses.
The alternative is not exotic. A self-hosted payment gateway is a piece of open-source software on a server you rent: it generates a fresh address per order, watches the chain for the money, tells your website when the invoice is paid, and never has the authority to move a single coin. It has been production-grade for years. What follows is the whole build — what it removes, what it does not, how to size the machine, and where the sharp edges are.
What a payment processor actually costs you
The fee is the least interesting line item. What you are really buying from a hosted crypto processor is a set of dependencies, and it is worth naming them before deciding they are acceptable.
| What the processor takes | Why it matters |
|---|---|
| Custody, for minutes or for days | Between the customer paying and you being paid, the money is theirs. Every insolvency, freeze and exit scam in this industry has happened in that gap |
| An account, with identity attached | The processor knows your legal name, your bank, your volume and your customers’ payment patterns. A no-KYC host in front of a KYC checkout is a locked door in a glass wall |
| The right to decide what you sell | Acceptable-use policies change without warning and are enforced retroactively. The account that worked last quarter is the account frozen this quarter |
| A dependency you cannot inspect | Their downtime is your checkout being down; their rate source is your pricing; their bug is your missing order |
| A permanent record of every sale | A subpoena to them produces your entire order book. You will not be told |
None of that is an accusation of bad faith. It is simply the shape of an intermediary. If your business is uncontroversial, well capitalised and happy to be identified, an intermediary is a perfectly rational trade — you get refunds, support and someone else’s uptime. The rest of this guide is for everyone whose answer to that trade is no.

What self-hosting gives you — and what it doesn’t
Be precise about the win, because overstating it is how people build the wrong threat model. Self-hosting a gateway changes exactly three things, and leaves several important things untouched.
What genuinely changes. The money goes straight from the customer to an address only you control, so there is no custodian and no freeze to survive. No third party is told who your customers are or what you sell. And nobody can revoke your ability to take payments, because there is no account to revoke — only software you run.
What does not change. The Bitcoin blockchain is still a public ledger, and every address your server hands out is still visible forever. Your tax and reporting obligations are exactly what they were. And the moment you convert those coins into your local currency, you meet a regulated exchange that will want your passport — which is why the cash-out, not the checkout, is where most people’s privacy actually ends.
The single best property, stated plainly: a correctly configured self-hosted gateway holds no private keys. If the server is compromised, seized or simply repossessed, the attacker gets your invoice history and a list of your addresses — not the ability to spend one satoshi. That is a very different disaster from losing a hot wallet, and it is the reason this architecture is worth the effort.
The stack: what BTCPay Server actually is
The de-facto answer is BTCPay Server: free, MIT-licensed, self-hosted, and built after a well-known processor’s policy decisions annoyed enough merchants to produce a replacement. It is not one program but a small stack of containers that come up together, and it helps to know which piece does what before something breaks at two in the morning.
- A Bitcoin node. Your own copy of the chain. This is what makes the setup trustless — you are not asking anyone else whether you were paid, and no one else learns which addresses you are watching.
- An indexer that tracks the addresses derived from your wallet and reports what lands on them, so the node itself does not need to hold a wallet.
- The BTCPay application — the part you actually see. Stores, invoices, exchange rates, a point-of-sale page, payment buttons, crowdfunding pages, refunds, the REST API and the webhooks.
- A database holding stores, invoices and settings. This is the only irreplaceable state on the machine, which matters enormously when you get to backups.
- A reverse proxy with automatic TLS, so the checkout is served over HTTPS without you assembling it by hand.
- Optional daemons — a Lightning node, a Monero node and wallet, other chains — each of which adds real weight to the machine. Add them deliberately, not by default.
Deployment is a Docker Compose stack driven by an environment file: you declare which optional pieces you want, run the setup script, and the composition is generated for you. That is a genuine advantage over hand-assembling six services, and it is also the reason the machine wants more disk than you would guess.
Sizing the server: the disk is the whole decision
CPU is almost never the constraint. A gateway that processes a few hundred invoices a day is idle most of the time; the load is the initial block download and then a trickle. Memory matters more, and disk decides everything. Work out which row you are in before you order anything.
| Configuration | Disk to plan for | Sensible RAM | Who it is for |
|---|---|---|---|
| Pruned Bitcoin node, on-chain only | ~40–60 GB total, including the operating system | 4 GB | Most merchants. The correct default |
| Pruned node plus Lightning | ~60–80 GB | 8 GB | Small, frequent payments where fees would otherwise dominate |
| Full, unpruned Bitcoin node | ~1 TB, with headroom for years of growth | 8 GB | People who also want the node for other software, or who value having the whole chain |
| Adding a Monero node | Add ~120 GB pruned, ~300 GB unpruned | +4 GB | Anyone who wants payments the public ledger does not narrate |
| Everything at once, unpruned | 1.5 TB and upwards | 16 GB | Rare, and usually a sign the gateway should be split across two machines |
Two details catch people out, and both cost time rather than money. First, pruning saves disk, not bandwidth: the node still downloads and verifies the entire chain during the initial sync, then discards the old blocks it no longer needs. Budget several hundred gigabytes of transfer for that first sync regardless of the final footprint — which is exactly why unmetered bandwidth belongs on the requirements list. Second, NVMe is not a luxury here. Initial block download is brutally random-access; the same sync that takes a day on NVMe can take a week on spinning disk, and you will spend that week wondering whether it is broken.
Prune first, expand later — the reverse is painful. Going from a pruned node to a full one means resyncing from genesis. Going from full to pruned is a configuration change and a restart. If you are unsure, start pruned: the gateway behaves identically, and the only thing you lose is the ability to serve historic blocks to other peers.
Step 1 — Provision and harden the host
Order the server before you need it and let the chain sync while you do everything else. A KVM VPS with full root is the right shape: you need kernel-level control for Docker, and you want the machine to be yours rather than a container on someone’s shared platform. Pay for it the same way you intend to be paid — our walkthrough of buying a VPS with Bitcoin covers that end, and the jurisdiction guide covers where to put it.
Harden it while it is still empty, because it will not be empty for long and this machine is, by design, a public advertisement that money passes through it. Keys-only SSH, no password authentication, a default-deny firewall with only 22, 80 and 443 open, unattended security upgrades, and the SSH port itself restricted to addresses you control if you can manage that. The first-hour hardening checklist is precisely this list, and doing it before the gateway exists takes twenty minutes rather than an afternoon.
Point a hostname at the machine before you install — the setup script wants a domain so it can request a certificate on first boot. A dedicated subdomain is fine and is what most people use. Bear in mind that this hostname becomes part of your public checkout, so it will appear in Certificate Transparency logs the moment the certificate is issued, permanently and searchably. Choose a name you are content to have indexed forever, and if the association between that name and your main site is itself sensitive, read our note on what a hostname reveals before you pick one.
Step 2 — Install the gateway
Installation is deliberately boring: clone the deployment repository, export a handful of environment variables describing what you want, and run the setup script. The variables that matter are the host name, the chains you want, and the optional fragments — which Lightning implementation, whether to prune, whether to add other daemons. There is a full-featured web installer too, but the environment-variable route is the one you can reproduce from your notes six months later, and reproducibility is worth more than convenience here.
What happens next is a wait. The stack comes up in a couple of minutes; the Bitcoin node then spends anywhere from several hours to a couple of days catching up with the chain, and BTCPay will honestly tell you it is still syncing rather than pretending to work. Do not create invoices during this window and do not judge anything by it. Use the time productively: create your admin account and turn on two-factor authentication immediately, because this interface is the control panel for your revenue and it is reachable from the entire internet.
Two settings deserve attention while you wait. Set the invoice expiry to something that respects real-world confirmation times — the default is a quarter of an hour, which is fine for Lightning and tight for an on-chain payment during a fee spike. And set the payment tolerance, which decides whether an invoice that arrives a few cents short is settled or left hanging. Zero tolerance generates support tickets; a small percentage generates none. That single field prevents more customer emails than any other.
Step 3 — Connect a wallet without putting keys on the server
This is the step that determines whether self-hosting was worth doing, and it is the one most often got wrong in a hurry.
BTCPay can generate a wallet for you, on the server, with the private keys on the server. Do not do this for a store that takes real money. The correct approach is to create the wallet elsewhere — a hardware wallet, or a desktop wallet on a machine that is not this one — and give the server only the extended public key, the xpub. That single string lets the gateway derive an unlimited sequence of receiving addresses and watch them, while remaining mathematically incapable of spending anything. Your keys stay where you put them; the server becomes a very well-informed observer.
Once connected, verify it rather than assuming. Create a one-cent invoice, pay it from a wallet you control, and confirm three things: the address appears in the wallet you own, the invoice settles in BTCPay, and the funds are visible and spendable from your own wallet software rather than only in the gateway interface. That three-way check is how you discover a wrong derivation path in five minutes instead of after your first real customer.
Do not spend from that account with a second wallet. The indexer watches a limited window of unused addresses ahead of the last one it saw used. If another wallet quietly consumes addresses from the same account, the gateway can be looking at the wrong part of the sequence and miss a payment that did arrive. Keep the store’s account for the store, and if you need a hot balance for refunds or payouts, use a separate wallet with a small float rather than compromising the main one.
Step 4 — Add Lightning and Monero, if you need them
Both are worth having and neither is free, so add them because a customer asked, not because the checkbox exists.
Lightning makes small payments viable — instant, effectively free, and immune to the fee spikes that make a four-dollar on-chain invoice absurd. The catch is not the software, which the stack installs for you; it is inbound liquidity. You can only be paid what your channels have room to receive, so a freshly launched node with no inbound capacity cannot accept anything at all until you open channels, buy inbound capacity or use a liquidity service. Budget an afternoon and some capital. And treat the node’s backups as a separate problem from everything else on the box: Lightning channel state is live state, a restore from an old snapshot can cost you the channel balance, and the recovery file that protects you must be kept current and off the machine.
Monero is the opposite trade: no channels, no liquidity, no routing — just a second blockchain and its daemon, and payments that the public ledger does not narrate to anyone watching. BTCPay supports it through a plugin backed by your own Monero node and a view-only wallet, which is the same principle as the xpub: you hand the server the address and the private view key so it can see incoming payments, and keep the spend key elsewhere. Two operational facts to plan around: Monero funds require ten confirmations before they are spendable, roughly twenty minutes, so your invoice expiry and your order-fulfilment logic must tolerate that; and the daemon adds substantial disk. If you are weighing which coins to offer at all, our comparison of Monero, Bitcoin and USDT is the shorter path to a decision.
Step 5 — Wire it into your site
The gateway is useless until your application knows an invoice was paid. There are three integration routes, in ascending order of effort and control.
- A plugin, if you run one of the common e-commerce platforms. Install it, paste an API key, done in an afternoon. This covers the majority of real deployments and there is no prize for avoiding it.
- Payment buttons or a hosted checkout page, if you sell a handful of things or take donations. Copy an HTML snippet, and BTCPay handles the entire payment flow on its own domain.
- The REST API, if you have a custom application. Create invoices programmatically, receive webhooks when they change state, and control the whole experience.
Whichever route you take, the rule for fulfilment is the same and it is not negotiable: never ship on the basis of a webhook you have not verified. Webhooks are signed with a shared secret — check the signature on every request, and then call back to the API to confirm the invoice really is in the state the webhook claims. An unauthenticated endpoint that marks orders paid is a free-goods generator, and it will be found by someone with a scanner long before it is found by you.
Then decide what “paid” means for your business. Settling on an unconfirmed transaction is instant and exposes you to replacement; waiting for one confirmation costs the customer ten minutes on average and removes almost all of that risk. Digital goods delivered instantly deserve a confirmation. A physical item shipped tomorrow does not — the parcel will not move before the block does.
Running it: backups, upgrades and the failure modes
A payment gateway is infrastructure, and infrastructure is judged on the bad day rather than the good one. Three habits cover almost every way this goes wrong.
Back up the right things. The blockchain is not one of them — it is several hundred gigabytes that the internet will happily send you again. What is irreplaceable is the database of stores, invoices and settings, the configuration, and any Lightning material. The deployment ships a backup script that captures exactly this; the discipline is to run it on a schedule, ship the result somewhere else, encrypt it before it leaves, and restore it once to prove it works. An off-site encrypted backup is the same pattern as everywhere else on this site, and here the archive is a full record of your revenue — so the encryption is not optional.
Upgrade on purpose. The stack has an update script and it is well behaved, but a gateway that updates itself unattended is a gateway that can be down while you sleep. Read the release notes, take a database backup first, and update at a quiet hour. Never during a promotion.
Know what an outage actually costs. This is the reassuring part. If the gateway is down, new customers cannot generate invoices — an availability problem, and a real one. But money already sent to your addresses is not lost, delayed or at risk: it is sitting in a wallet whose keys were never on the machine, and it will be there when the node comes back and rescans. Downtime costs you sales, not funds. That distinction is worth internalising, because it turns a three-in-the-morning emergency into something that can wait until breakfast.
The privacy reality: what the chain still shows
Removing the processor removes the processor. It does not make Bitcoin private, and a self-hosted gateway can quietly make your on-chain privacy worse if you are not paying attention.
| What leaks | Why | What to do about it |
|---|---|---|
| Your entire revenue history, to anyone holding the xpub | One extended public key derives every address your store will ever use | Treat the xpub as a business secret. Never paste it into a block explorer or a support ticket |
| Which customers paid you, linked together | Consolidating many invoice payments into one transaction proves the same entity received all of them | Consolidate rarely, in large batches, at quiet times — or not at all |
| The link between your checkout and your main site | Certificate Transparency, DNS records and the page that embeds the payment form | Assume the association is public. If it must not be, that constraint belongs in the design, not in a later patch |
| Your own admin sessions | Server access logs record who administers the machine and from where | Never touch the gateway from an address that identifies you. Our server OpSec guide is the long version |
| Everything, eventually, at the exchange | Conversion to fiat is the regulated chokepoint, and it sees the coins’ history | Nothing technical fixes this. Plan for it, or accept payment in something the ledger does not publish |
Two mitigations are worth the effort and are built in. Turning on a payjoin-style collaborative payment breaks the naive assumption that all the inputs of a transaction belong to one person, which is the single most useful heuristic chain analysts rely on. And offering Monero alongside Bitcoin means the customers who care most simply never write anything to a public ledger in the first place. Neither is a magic trick; both raise the cost of watching you.
The legal part nobody enjoys
Short version, and not legal advice: running the software is not the regulated act. What you do with the money can be.
In most jurisdictions, accepting crypto as payment for your own goods and services is an ordinary commercial transaction. You are a merchant being paid, not a financial institution. The obligations that follow are the ones you already have: recognise the revenue at its value on the day you received it, apply the same sales tax or VAT you would have applied to a card payment, and keep records that survive an audit. A self-hosted gateway makes that easier rather than harder, because the invoice history is yours and complete.
Where the line moves is when you start handling money for other people. Converting, transmitting or holding crypto on behalf of third parties is a licensed activity almost everywhere, and “but I self-host it” is not a defence. Sanctions obligations also survive the change of architecture entirely. And accepting payment without KYC is a very different question from accepting payment you know to be criminal — the first is legal in most of the world, the second is not, anywhere. Our guide on whether offshore hosting is legal works through the same distinction in more depth.
The whole build, on one page
Stripped of the reasoning, this is a weekend project of which most is waiting:
- Decide the shape: pruned or full node, Lightning or not, Monero or not. This sets the disk, and the disk sets the plan.
- Order the server — NVMe, unmetered bandwidth, full root — and pay for it in the currency you intend to accept.
- Harden it while it is empty, then point a hostname at it and let the certificate issue.
- Deploy the stack from the environment file, then wait for the node to sync. Do not judge anything during the sync.
- Create the wallet elsewhere and give the server only the extended public key. Verify with a one-cent invoice before anything else.
- Add Lightning or Monero only if a customer will use them, and budget the liquidity or the disk accordingly.
- Integrate by plugin, button or API — and verify every webhook signature against the API before you ship a single order.
- Schedule the backup, encrypt it, send it off the machine, and restore it once so you know it works.
What you end up with is unglamorous and quietly significant: a checkout with no company in it. The money arrives at addresses only you can spend from, no account can be closed because there is no account, and the cost of the whole arrangement is one small server. If you want the same independence for the machine underneath it, that is what hosting paid for in Bitcoin exists for — and the two decisions are, satisfyingly, the same decision made twice.