Ubuntu 22.04 安装 BTCPay Server 2.4.5 指南
在 Ubuntu 22.04 上以源码构建与 systemd 托管方式从零部署 BTCPay Server 2.4.5 全链路(PostgreSQL、.NET 10、Bitcoin Core 31.1、NBXplorer、主程序),含完整实测回显与九类排障实录。
Ubuntu 22.04 安装 BTCPay Server 2.4.5 指南
目标:在 Ubuntu 22.04 服务器上以「源码构建 + systemd 托管」的手动部署方式,从零完成 BTCPay Server 2.4.5 全链路安装——PostgreSQL 数据库、.NET 运行时、Bitcoin Core 全节点、NBXplorer 链上索引器、BTCPay Server 主程序,最终注册管理员并通过健康检查与管理面验证。全部命令与回显均在 Ubuntu 22.04.5 服务器实测;链的验证环节采用 regtest 私有测试链(秒级出块、无需等待主网同步),并给出切换主网的准确改法。
一、环境信息与版本选型
1.1 实测环境
| 项目 | 值 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS |
| 主机名 | btcpay245 |
| 内核架构 | x86_64 |
| 网络 | 可直连 Ubuntu 源、GitHub 与 bitcoincore.org |
| 部署方式 | 源码构建(dotnet publish)+ systemd 托管 |
| 验证链 | regtest(私有测试链,预挖 101 块) |
1.2 组件版本选型
BTCPay Server 不是单一程序,而是一条四组件依赖链,安装顺序为:PostgreSQL → .NET 运行时 → Bitcoin Core → NBXplorer → BTCPay Server。
| 组件 | 实测版本 | 安装来源 | 说明 |
|---|---|---|---|
| PostgreSQL | 14.24(Ubuntu 源 14.24-0ubuntu0.22.04.1) | apt 官方源 | Ubuntu 22.04 默认源版本,实测可用 |
| .NET SDK/运行时 | 10.0.402 | 官方 dotnet-install.sh | BTCPay Server v2.4.5 目标框架为 net10.0 |
| Bitcoin Core | v31.1.0 | bitcoincore.org 官方二进制 | 与官方部署栈锁定的 31.1 版本一致 |
| NBXplorer | 2.6.19 | GitHub v2.6.19 标签 | BTCPay 官方配套链上索引器 |
| BTCPay Server | 2.4.5 | GitHub v2.4.5 标签 | 本文主角 |
版本选型依据:BTCPay Server 主程序、NBXplorer、Bitcoin Core 的版本组合应跟随官方部署栈锁定(官方 v2.4.5 部署栈为 BTCPay Server 2.4.5 + NBXplorer 2.6.19 + Bitcoin Core 31.1 + PostgreSQL 18.6);PostgreSQL 本身版本要求宽松,Ubuntu 22.04 源内的 14.24 实测完整跑通全链。组件定位与选型背景详见《BTCPay Server 2.4.5 介绍与选型指南》。
💡 说明:官方另有 Docker Compose 一键部署形态(生成整套编排、内置 Let's Encrypt 证书签发),适合希望减少手工装配的场景,见《BTCPay Server 2.4.5 Docker Compose 部署指南》。本篇的手动部署适合需要完全掌控进程边界、进程管理与目录布局的运维。
1.3 依赖链与端口规划
┌──────────────────────────── 服务器 btcpay245 ────────────────────────────┐
│ │
│ 浏览器 ──HTTP:23000──▶ BTCPay Server(.NET 10,User=btcpay) │
│ │ │ │
│ PostgreSQL 14 ◀────┘ ▼ │
│ 127.0.0.1:5432 NBXplorer 2.6.19(User=btcpay) │
│ 两套库:btcpayservermainnet │ HTTP API 127.0.0.1:24446 │
│ nbxplorermainnet ▼ │
│ Bitcoin Core 31.1(User=bitcoin) │
│ RPC 127.0.0.1:18443(regtest) │
│ P2P 127.0.0.1:18444(regtest) │
└──────────────────────────────────────────────────────────────────────────┘
各端口说明(regtest 网络):
| 端口 | 归属 | 用途 |
|---|---|---|
| 23000 | BTCPay Server | Web 管理面 + Greenfield API(对外) |
| 24446 | NBXplorer | REST API(BTCPay Server 内部对接) |
| 18443 | Bitcoin Core | RPC(NBXplorer 对接) |
| 18444 | Bitcoin Core | P2P(NBXplorer 订阅新区块) |
| 5432 | PostgreSQL | 两套数据库 |
⚠️ 注意:NBXplorer 的 API 端口随网络变化——mainnet 为 24444,regtest 为 24446。BTCPay Server 的
--btcexplorerurl必须与链网络匹配,端口对不上会出现连接拒绝。生产主网端口对照见第九章。
二、安装 PostgreSQL 数据库
2.1 apt 安装
Ubuntu 22.04 官方源自带 PostgreSQL 14,直接安装主包与 contrib 扩展包:
apt update
DEBIAN_FRONTEND=noninteractive apt-get install -y postgresql postgresql-contrib
实测回显(末尾节选):
Setting up postgresql-contrib (14+238) ...
Setting up postgresql (14+238) ...
Processing triggers for libc-bin (2.35-0ubuntu3.15) ...
2.2 启动并设置开机自启
systemctl enable --now postgresql
systemctl status postgresql --no-pager | head -6
实测回显:
Synchronizing state of postgresql.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable postgresql
● postgresql.service - PostgreSQL RDBMS
Loaded: loaded (/lib/systemd/system/postgresql.service; enabled; vendor preset: enabled)
Active: active (exited) since Thu 2026-10-22 18:09:35 UTC; 2s ago
Main PID: 5620 (code=exited, status=0/SUCCESS)
💡 说明:
postgresql.service是版本无关的总入口,状态显示active (exited)属正常(它只负责拉起具体版本实例)。查看真实实例状态用systemctl status postgresql@14-main。
2.3 确认版本
su - postgres -c "psql -c 'SELECT version();'" | head -3
实测回显:
version
------------------------------------------------------------------------------------------------------------------------------------------
PostgreSQL 14.24 (Ubuntu 14.24-0ubuntu0.22.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0, 64-bit
2.4 创建业务账号与两套数据库
BTCPay Server 与 NBXplorer 各用一套数据库。创建专用账号 btcpay(示例密码 q1w2e3r4,生产请替换为强口令):
su - postgres -c "psql -c \"CREATE USER btcpay WITH PASSWORD 'q1w2e3r4';\""
su - postgres -c "createdb -O btcpay btcpayservermainnet"
su - postgres -c "createdb -O btcpay nbxplorermainnet"
实测回显:
CREATE ROLE
验证建库结果:
su - postgres -c "psql -l" | grep -E "btcpayservermainnet|nbxplorermainnet"
实测回显:
btcpayservermainnet | btcpay | UTF8 | C.UTF-8 | C.UTF-8 |
nbxplorermainnet | btcpay | UTF8 | C.UTF-8 | C.UTF-8 |
⚠️ 注意:
CREATE DATABASE不能与其他语句合并在同一条psql -c里执行(会报CREATE DATABASE cannot run inside a transaction block),必须逐条执行或使用createdb工具,本文采用createdb。
三、安装 .NET 运行时
3.1 确认 Ubuntu 源内没有 .NET 10
BTCPay Server v2.4.5 的目标框架是 net10.0,而 Ubuntu 22.04 官方源最高只到 .NET 8:
apt-cache search -n "^dotnet-sdk" | grep -v dbg | grep -v artifacts
实测回显:
dotnet-sdk-6.0 - dotNET 6.0 Software Development Kit
dotnet-sdk-8.0 - .NET 8.0 Software Development Kit
dotnet-sdk-7.0 - dotNET 7.0 Software Development Kit
因此主方案采用微软官方 dotnet-install.sh 脚本安装 .NET 10 SDK(含运行时)。
3.2 用官方脚本安装 .NET 10 SDK
curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh
chmod +x /tmp/dotnet-install.sh
/tmp/dotnet-install.sh --channel 10.0 --install-dir /usr/share/dotnet
实测回显(末尾节选):
dotnet-install: Adding to current process PATH: `/usr/share/dotnet`. Note: This change will be visible only when sourcing script.
dotnet-install: Note that the script does not resolve dependencies during installation.
dotnet-install: To check the list of dependencies, go to https://learn.microsoft.com/dotnet/core/install, select your operating system and check the "Dependencies" section.
dotnet-install: Installation finished successfully.
3.3 链接到 PATH 并验证
ln -sf /usr/share/dotnet/dotnet /usr/local/bin/dotnet
dotnet --version
实测回显:
10.0.402
四、安装 Bitcoin Core 全节点
4.1 下载官方二进制
从 bitcoincore.org 下载 31.1 版本的 x86_64 Linux 二进制包:
cd /tmp
curl -fSL -o bitcoin-31.1.tar.gz https://bitcoincore.org/bin/bitcoin-core-31.1/bitcoin-31.1-x86_64-linux-gnu.tar.gz
ls -lh bitcoin-31.1.tar.gz
sha256sum bitcoin-31.1.tar.gz
实测回显:
100 86.1M 100 86.1M 0 0 5559k 0 0:00:15 0:00:15 --:--:-- 6918k
-rw-r--r-- 1 root root 87M Oct 22 18:10 bitcoin-31.1.tar.gz
b80d9c3e04da78fb6f0569685673418cf686fadba9042d926d13fb87ff503f9e bitcoin-31.1.tar.gz
💡 说明:生产环境应将
sha256sum输出与 bitcoincore.org 该版本目录下SHA256SUMS签名文件核对后再安装。
4.2 解压安装
该 tarball 解压后目录为 bitcoin-31.1/,内含 bin/、libexec/、share/(无 include/、lib/ 目录)。安装到 /opt/bitcoin 并建立软链:
cd /tmp
tar -xzf bitcoin-31.1.tar.gz
mkdir -p /opt/bitcoin
cp -r bitcoin-31.1/{bin,libexec,share} /opt/bitcoin/
ln -sf /opt/bitcoin/bin/bitcoind /opt/bitcoin/bin/bitcoin-cli /opt/bitcoin/bin/bitcoin-wallet /opt/bitcoin/bin/bitcoin-tx /usr/local/bin/
bitcoind --version | head -2
实测回显:
Bitcoin Core daemon version v31.1.0 bitcoind
Copyright (C) 2009-2026 The Bitcoin Core developers
4.3 创建专用系统用户与目录
Bitcoin Core 以专用系统用户 bitcoin 运行(与后文 NBXplorer/BTCPay Server 的 btcpay 用户分离,缩小进程权限面):
useradd -r -s /usr/sbin/nologin bitcoin
mkdir -p /etc/bitcoin /var/lib/bitcoind
chown -R bitcoin:bitcoin /var/lib/bitcoind
4.4 编写 bitcoin.conf
写入 /etc/bitcoin/bitcoin.conf(验证网络为 regtest):
cat > /etc/bitcoin/bitcoin.conf <<'EOF'
# BTCPay Server 配套 Bitcoin Core(验证环境用 regtest 链;生产切换见本节末尾)
regtest=1
server=1
txindex=0
datadir=/var/lib/bitcoind
[regtest]
rpcbind=127.0.0.1
rpcport=18443
rpcallowip=127.0.0.1
rpcuser=btcpayrpc
rpcpassword=btcpayrpc-pass-245
EOF
cat /etc/bitcoin/bitcoin.conf | head -5 实测回显:
# BTCPay Server 配套 Bitcoin Core(验证环境用 regtest 链;生产切换见本节末尾)
regtest=1
server=1
txindex=0
datadir=/var/lib/bitcoind
生产主网改法(结构完全一致):
regtest=1改为mainnet=1;[regtest]段头改为[main];- RPC 端口由 18443 改为 8332(P2P 相应为 8333);
- 主网首次启动需要完整同步链数据,磁盘与时间预算见《BTCPay Server 2.4.5 介绍与选型指南》第一章资源口径。
4.5 编写 systemd 服务单元
写入 /etc/systemd/system/bitcoind.service:
cat > /etc/systemd/system/bitcoind.service <<'EOF'
[Unit]
Description=Bitcoin Core daemon
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/bitcoind -conf=/etc/bitcoin/bitcoin.conf -datadir=/var/lib/bitcoind
User=bitcoin
Group=bitcoin
TimeoutSec=300
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now bitcoind
⚠️ 排障实录(Type=notify 卡 activating):bitcoind 服务单元最初用
Type=notify,启动后systemctl is-active bitcoind一直显示activating,且 RPC 实际已可响应——官方 tarball 编译的bitcoind不支持向 systemd 发送 sd_notify 就绪通知,Type=notify会一直等不到 READY,直至TimeoutSec=300后被 systemd 判定失败并误杀进程。修复:把Type=notify改为Type=simple,重新daemon-reload并restart即恢复正常。
4.6 验证服务与链状态
systemctl status bitcoind --no-pager -n 0 | head -7
bitcoin-cli -conf=/etc/bitcoin/bitcoin.conf getblockchaininfo | head -4
实测回显:
● bitcoind.service - Bitcoin Core daemon
Loaded: loaded (/etc/systemd/system/bitcoind.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2026-10-22 18:14:52 UTC; 3s ago
Main PID: 6455 (bitcoind)
Tasks: 36 (limit: 94371)
Memory: 39.2M
{
"chain": "regtest",
"blocks": 0,
"headers": 0,
4.7 初始化钱包并预挖验证块
regtest 链初始高度为 0 且无区块数据,Bitcoin Core 31 起默认不再自动创建钱包,需要手动建钱包并挖出初始块(这一步同时是后文 NBXplorer 索引验证的前提):
bitcoin-cli -conf=/etc/bitcoin/bitcoin.conf createwallet mining
实测回显:
{
"name": "mining"
}
ADDR=$(bitcoin-cli -conf=/etc/bitcoin/bitcoin.conf -rpcwallet=mining getnewaddress)
bitcoin-cli -conf=/etc/bitcoin/bitcoin.conf generatetoaddress 101 "$ADDR" | tail -3
bitcoin-cli -conf=/etc/bitcoin/bitcoin.conf getblockchaininfo | grep -E '"blocks"|"chain"'
实测回显(区块列表末尾节选):
"38a75cecc30a39d17f772843d19eae2bff2030ede0afbcf80525a13203efba64",
"6d0f3cd91a789480f666c746076c0241fef835d5f27ca64b519ad26432e8c66e"
]
"chain": "regtest",
"blocks": 101,
💡 说明:regtest 规则下 101 块即完成 coinbase 成熟度解锁。生产主网无需此步,bitcoind 启动后自动开始同步主网区块(以天计,CPU 与磁盘速度决定时长)。
五、构建 NBXplorer 链上索引器
5.1 克隆源码
mkdir -p /usr/local/src
git clone --branch v2.6.19 https://github.com/NicolasDorier/NBXplorer.git /usr/local/src/NBXplorer
cd /usr/local/src/NBXplorer && git log -1 --format="%H %d %s"
实测回显:
a858b187a9025634787dce6b19e6bea66ecbb815 (HEAD, tag: v2.6.19, tag: Client/v5.0.11) Merge pull request #570 from btcpayserver/bump-dependencies-september-2026
💡 说明:该仓库同一提交上同时挂了
v2.6.19与Client/v5.0.11两个标签(客户端库与索引器双标签体系),以v2.6.19为准。
5.2 编译发布
构建依赖第三章的 .NET 10 SDK,发布产物落到 /opt/nbxplorer:
cd /usr/local/src/NBXplorer
dotnet publish NBXplorer/NBXplorer.csproj -c Release -o /opt/nbxplorer
实测回显(末尾两行):
NBXplorer -> /usr/local/src/NBXplorer/NBXplorer/bin/Release/net10.0/NBXplorer.dll
NBXplorer -> /opt/nbxplorer/
5.3 首次启动(排障实录:参数名)
⚠️ 排障实录:部分老教程让 NBXplorer 用
--btcconf指向 bitcoin.conf 自动读取 RPC 凭据。2.6.19 已不支持该参数,直接启动会报错:
cd /opt/nbxplorer && ./NBXplorer --btcconf=/etc/bitcoin/bitcoin.conf --network=regtest
实测报错回显:
info: Configuration: NBXplorer version 2.6.19
Specify --help for a list of available options and commands.
fail: Explorer:
Unrecognized option '--btcconf=/etc/bitcoin/bitcoin.conf'
正确做法是用 --help 查清参数后显式传入(可用方法为 --btcrpcuser/--btcrpcpassword、--btcrpccookiefile、--btcrpcauth 三种)。查看关键参数:
cd /opt/nbxplorer && ./NBXplorer --help 2>&1 | grep -E "^\s+--(btcrpcuser|btcrpcpassword|btcrpcurl|btcnodeendpoint|postgres|nowarmup)"
实测回显:
--nowarmup If true and on regtest, no block will be generated by NBXplorer when the tip got stalled or if no block has been mined (default: false)
--btcrpcuser RPC authentication method 1: The RPC user (default: using cookie auth from default network folder)
--btcrpcpassword RPC authentication method 1: The RPC password (default: using cookie auth from default network folder)
--btcrpcurl The RPC server url (default: default rpc server depended on the network)
--btcnodeendpoint The p2p connection to a Bitcoin node, make sure you are whitelisted (default: default p2p node on localhost, depends on network)
--postgres Use PostgreSQL backend. Set the connection string of the postgres backend (For example: "User ID=postgres;Host=postgres;Port=5432;Application Name=nbxplorer;Database=nbxplorer", more options on https://www.npgsql.org/doc/connection-string-parameters.html)
5.4 手动启动验证
先用临时进程验证配置正确(日志写 /var/log/nbxplorer.log):
cd /opt/nbxplorer
nohup ./NBXplorer \
--btcrpcuser=btcpayrpc \
--btcrpcpassword=btcpayrpc-pass-245 \
--btcrpcurl=http://127.0.0.1:18443 \
--btcnodeendpoint=127.0.0.1:18444 \
--postgres="User ID=btcpay;Password=q1w2e3r4;Host=127.0.0.1;Database=nbxplorermainnet" \
--network=regtest > /var/log/nbxplorer.log 2>&1 &
约 10 秒后查看日志:
grep -E "NBXplorer version|listening|detected|Node state changed" /var/log/nbxplorer.log | head -6
实测回显:
info: Configuration: NBXplorer version 2.6.19
info: Configuration: Now listening on: http://127.0.0.1:24446
info: NBXplorer.Indexer.BTC: Full node version detected: 310100
info: NBXplorer.Events: BTC: Node state changed: NotStarted => NBXplorerSynching
info: NBXplorer.Events: BTC: Node state changed: NBXplorerSynching => Ready
info: NBXplorer.Events: BTC: New block 6d0f3cd91a789480f666c746076c0241fef835d5f27ca64b519ad26432e8c66e (101)
Full node version detected: 310100 与 => Ready 表明 NBXplorer 已成功连接 Bitcoin Core 31.1 并完成索引(101 块)。
5.5 验证 REST API(排障实录:路由变更与认证)
⚠️ 排障实录(API 路由 404):老文档的查询路径
GET /v1/crypto/btc/status在 2.6.19 已不存在,实测返回 404:
curl -sv --max-time 8 http://127.0.0.1:24446/v1/crypto/btc/status 2>&1 | grep -E "HTTP/|Connected to"
实测回显:
< HTTP/1.1 404 Not Found
< Server: Kestrel
2.6.19 的正确路由是 v1/cryptos/{cryptoCode}/status(复数 cryptos,源码 NBXplorer/Controllers/CommonRoutes.cs 中 BaseCryptoEndpoint = "cryptos/{cryptoCode}")。但直接请求会得到 401:
curl -s --max-time 8 -w "\nHTTP=%{http_code}\n" http://127.0.0.1:24446/v1/cryptos/btc/status
实测回显:
HTTP=401
NBXplorer 的 REST API 默认启用 cookie 认证,凭据写在数据目录的 .cookie 文件里(HTTP Basic,用户名固定为 __cookie__)。用 cookie 认证重试:
curl -s --max-time 8 -u "$(cat /root/.nbxplorer/RegTest/.cookie)" http://127.0.0.1:24446/v1/cryptos/btc/status | head -c 300; echo
实测回显(节选):
{"bitcoinStatus":{"blocks":101,"headers":101,"verificationProgress":1.0,"isSynched":true,"incrementalRelayFee":0.1,"minRelayTxFee":0.1,"externalAddresses":[],"capabilities":{"canScanTxoutSet":true,"canSupportSegwit":true,"canSupportTaproot":true,"canSupportTransactionCheck":true}},"isFullySynched":t
isSynched: true 即索引器状态健康。验证通过后停掉临时进程,转入 systemd 托管:
pkill -f NBXplorer
5.6 systemd 托管
创建专用系统用户与数据目录(NBXplorer 数据目录改放 /var/lib/nbxplorer):
useradd -r -s /usr/sbin/nologin btcpay
mkdir -p /var/lib/nbxplorer /var/lib/btcpay
chown -R btcpay:btcpay /var/lib/nbxplorer /var/lib/btcpay
写入 /etc/systemd/system/nbxplorer.service:
cat > /etc/systemd/system/nbxplorer.service <<'EOF'
[Unit]
Description=NBXplorer - lightweight block explorer for BTCPay Server
After=bitcoind.service postgresql.service
Wants=postgresql.service
[Service]
Type=simple
User=btcpay
Group=btcpay
WorkingDirectory=/opt/nbxplorer
ExecStart=/usr/share/dotnet/dotnet /opt/nbxplorer/NBXplorer.dll \
--datadir=/var/lib/nbxplorer \
--network=regtest \
--btcrpcuser=btcpayrpc --btcrpcpassword=btcpayrpc-pass-245 \
--btcrpcurl=http://127.0.0.1:18443 \
--btcnodeendpoint=127.0.0.1:18444 \
--btcrpcdefaultwallet=mining \
--postgres="User ID=btcpay;Password=q1w2e3r4;Host=127.0.0.1;Database=nbxplorermainnet"
Restart=on-failure
RestartSec=10
TimeoutSec=120
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now nbxplorer
💡 说明:
--btcrpcdefaultwallet=mining让 NBXplorer 以 4.7 节创建的mining钱包上下文启用 RPC wallet 功能。不配置该参数时服务也能启动,但日志会提示 RPC wallet 功能被禁用,BTCPay Server 后续通过界面/API「生成热钱包」的能力会受影响。两个状态的实测日志对比见 5.7。
5.7 验证 systemd 托管后的服务
systemctl is-active nbxplorer
journalctl -u nbxplorer --no-pager -n 5 | tail -3
ls -la /var/lib/nbxplorer/RegTest/.cookie
实测回显:
active
Oct 22 18:19:24 btcpay245 dotnet[7859]: info: NBXplorer.Indexer.BTC: BTC: RPC Wallet loaded
Oct 22 18:19:24 btcpay245 dotnet[7859]: info: NBXplorer.Events: BTC: Node state changed: NotStarted => NBXplorerSynching
Oct 22 18:19:24 btcpay245 dotnet[7859]: info: NBXplorer.Events: BTC: Node state changed: NBXplorerSynching => Ready
-rw-r--r-- 1 btcpay btcpay 75 Oct 22 18:19 /var/lib/nbxplorer/RegTest/.cookie
⚠️ 排障实录(RPC wallet 提示):未加
--btcrpcdefaultwallet时,journalctl -u nbxplorer中会出现:info: NBXplorer.Indexer.BTC: BTC: RPC wallet features are disabled because neither `BTC.rpc.defaultwallet` nor `NBXPLORER_BTC_RPC_DEFAULTWALLET` is configured.补上参数重启后,日志变为
info: NBXplorer.Indexer.BTC: BTC: RPC Wallet loaded。注意数据目录换了位置(--datadir=/var/lib/nbxplorer)后,cookie 文件也在新目录下,第六章 BTCPay Server 的配置要指向它。
六、构建 BTCPay Server 主程序
6.1 克隆源码
git clone --branch v2.4.5 https://github.com/btcpayserver/btcpayserver.git /usr/local/src/btcpayserver
cd /usr/local/src/btcpayserver && git describe --tags
实测回显:
v2.4.5
6.2 编译发布
cd /usr/local/src/btcpayserver
dotnet publish BTCPayServer/BTCPayServer.csproj -c Release -o /opt/btcpayserver
实测回显(末尾两行):
BTCPayServer -> /usr/local/src/btcpayserver/BTCPayServer/bin/Release/net10.0/BTCPayServer.dll
BTCPayServer -> /opt/btcpayserver/
发布产物中含完整的 wwwroot/ 静态资产目录(收银台页面、locale 文件等),后续 systemd 单元的工作目录必须指向它,原因见 6.4 的排障实录。
6.3 编写 systemd 服务单元
写入 /etc/systemd/system/btcpayserver.service:
cat > /etc/systemd/system/btcpayserver.service <<'EOF'
[Unit]
Description=BTCPay Server - self-hosted cryptocurrency payment processor
After=nbxplorer.service postgresql.service
Wants=postgresql.service
[Service]
Type=simple
User=btcpay
Group=btcpay
WorkingDirectory=/opt/btcpayserver
ExecStart=/usr/share/dotnet/dotnet /opt/btcpayserver/BTCPayServer.dll \
--datadir=/var/lib/btcpay \
--network=regtest \
--postgres="User ID=btcpay;Password=q1w2e3r4;Host=127.0.0.1;Database=btcpayservermainnet" \
--btcexplorerurl=http://127.0.0.1:24446 \
--btcexplorercookiefile=/var/lib/nbxplorer/RegTest/.cookie \
--port 23000 \
--bind 0.0.0.0
Restart=on-failure
RestartSec=10
TimeoutSec=120
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now btcpayserver
配置要点:
| 参数 | 值 | 说明 |
|---|---|---|
--network | regtest | 链网络;生产改为 mainnet |
--postgres | btcpayservermainnet | 业务库(与 NBXplorer 的 nbxplorermainnet 分库) |
--btcexplorerurl | http://127.0.0.1:24446 | NBXplorer regtest API;主网为 24444 |
--btcexplorercookiefile | /var/lib/nbxplorer/RegTest/.cookie | NBXplorer cookie 凭据;缺省时会找运行用户 $HOME/.nbxplorer/<网络>/.cookie |
--port / --bind | 23000 / 0.0.0.0 | Web 面端口与监听地址 |
启动日志中可以看到两条关键确认(journalctl -u btcpayserver):
info: Configuration: BTC: Explorer url is http://127.0.0.1:24446/
info: Configuration: BTC: Cookie file is /var/lib/nbxplorer/RegTest/.cookie
info: Configuration: Now listening on: http://0.0.0.0:23000
6.4 首次启动两个排障实录
⚠️ 排障实录一(系统用户缺 home 目录导致 abort):
useradd -r创建系统用户时默认不创建 home 目录,而 BTCPay Server 启动过程要访问运行用户的$HOME。首次启动服务反复重启,journalctl -u btcpayserver报:fail: Configuration: Configuration error Unhandled exception. System.UnauthorizedAccessException: Access to the path '/home/btcpay' is denied. ---> System.IO.IOException: Permission denied ... systemd[1]: btcpayserver.service: Main process exited, code=dumped, status=6/ABRT修复:补建目录并赋属主,然后重启服务:
mkdir -p /home/btcpay && chown btcpay:btcpay /home/btcpay systemctl restart btcpayserver
⚠️ 排障实录二(缺 WorkingDirectory 导致注册/访问 500):home 目录补上后服务能启动、健康检查也通过,但浏览器注册管理员时页面报 500。日志根因是:
System.ArgumentNullException: Value cannot be null. (Parameter 'path1') at System.IO.Path.Combine(String path1, String path2, String path3) at BTCPayServer.Services.LanguageService..ctor(IWebHostEnvironment environment, ILogger`1 logger) in /usr/local/src/btcpayserver/BTCPayServer/Services/LanguageService.cs:line 37
LanguageService启动时要扫描WebRootPath/locales/下的语言文件,而 ASP.NET Core 的WebRootPath默认按「当前工作目录/wwwroot」解析——systemd 单元没写WorkingDirectory时工作目录是/,/wwwroot不存在,WebRootPath解析为 null。修复:在 unit 的[Service]段加WorkingDirectory=/opt/btcpayserver(6.3 的最终版已包含),daemon-reload后重启即恢复。
6.5 健康检查与管理面验证
systemctl is-active btcpayserver
curl -s --max-time 10 http://127.0.0.1:23000/api/v1/health; echo
curl -s -o /dev/null -w "login page HTTP=%{http_code}\n" --max-time 10 http://127.0.0.1:23000/login
实测回显:
active
{"synchronized":true}
login page HTTP=200
/api/v1/health返回{"synchronized":true}:服务自身健康,且链上索引(NBXplorer → Bitcoin Core)已同步;/login返回 200:Web 管理面正常。
⚠️ 排障实录(首启日志里的迁移报错属正常):首次启动日志中可能出现:
fail: Microsoft.EntityFrameworkCore.Database.Command: Failed executing DbCommand (11ms) ... SELECT "MigrationId", "ProductVersion" FROM "__EFMigrationsHistory" ORDER BY "MigrationId";这是 EF Core 首次迁移前探测迁移历史表、表不存在而抛出的内部异常,随后框架自动建表,应用正常起服务。看到这条日志不代表故障,以
/api/v1/health与日志中Now listening on为准。
七、注册管理员并完成部署验证
7.1 浏览器注册首个管理员
浏览器访问 http://<服务器IP>:23000,会自动跳到登录页,点击进入注册页(或直接访问 /register)。首个用户注册即成为服务器管理员。
本文实验使用示例账号:
| 项 | 值 |
|---|---|
| 邮箱 | admin@example.com |
| 密码 | q1w2e3r4 |
⚠️ 注意:示例口令仅用于文档演示,生产环境务必使用强口令;注册页密码最低长度为 6 字符。
注册成功后跳回登录页,用该账号登录,首次登录会引导进入「创建商店」页面(路径 /stores/create),说明管理面与账号体系均正常。
7.2 数据库侧复核账号
su - postgres -c "psql btcpayservermainnet -c 'SELECT \"Email\" FROM \"AspNetUsers\";'"
实测回显:
Email
-------------------
admin@example.com
(1 row)
7.3 自动化集成时的表单字段约定
若需要用脚本(而非浏览器)完成注册/登录验证,注意 2.4.5 的表单字段命名:
- 注册页
/register:字段为Email、Password、ConfirmPassword加__RequestVerificationToken(不带Input.前缀); - 登录页
/login:字段为Email、Password、RememberMe,且必须携带按钮字段Method=Password(页面上还有Method=Passkey、Method=LoginCode两个提交按钮,缺Method字段登录会失败)。
注册/登录的完整 API 化操作见《BTCPay Server 2.4.5 API 使用详解》。
八、服务日常运维(systemd)
三个服务的管理命令一览(均以 root 执行):
# 状态查看
systemctl status bitcoind nbxplorer btcpayserver --no-pager
# 启停与重启
systemctl stop btcpayserver nbxplorer
systemctl start bitcoind nbxplorer btcpayserver
systemctl restart btcpayserver
# 实时日志
journalctl -u btcpayserver -f
journalctl -u nbxplorer --since "10 min ago"
💡 说明:重启顺序遵循依赖链——先停上层(btcpayserver → nbxplorer → bitcoind),启动顺序相反。unit 文件里已写
After=依赖,systemctl start btcpayserver会自动按序拉起依赖服务。
开机自启确认(三个服务均应显示 enabled):
systemctl is-enabled bitcoind nbxplorer btcpayserver
实测回显:
enabled
enabled
enabled
九、升级、降级与多版本管理
9.1 版本切换的标准流程
三个 .NET 组件(NBXplorer、BTCPay Server)的版本切换遵循同一套流程:切换源码标签 → 重新 publish → 重启服务。以 NBXplorer 为例:
cd /usr/local/src/NBXplorer
git fetch --tags
git tag -l "v2.6.1*" | sort -V | tail -4
实测回显:
v2.6.16
v2.6.17
v2.6.18
v2.6.19
BTCPay Server 主程序同理,可用 git tag -l "v2.4*" 查看可用版本。升级前建议先看目标版本 Release Notes 是否包含 Breaking changes(v2.4.5 的 SSRF 私网默认阻断等变更清单见《BTCPay Server 2.4.5 介绍与选型指南》第四章)。
9.2 降级实测(2.6.19 → 2.6.18)
cd /usr/local/src/NBXplorer
git checkout v2.6.18
dotnet publish NBXplorer/NBXplorer.csproj -c Release -o /opt/nbxplorer
systemctl restart nbxplorer
journalctl -u nbxplorer --no-pager -n 20 | grep "NBXplorer version" | tail -1
实测回显:
NBXplorer -> /opt/nbxplorer/
Oct 22 18:24:57 btcpay245 dotnet[8065]: info: Configuration: NBXplorer version 2.6.18
9.3 升级实测(2.6.18 → 2.6.19)与重启后瞬态
cd /usr/local/src/NBXplorer
git checkout v2.6.19
dotnet publish NBXplorer/NBXplorer.csproj -c Release -o /opt/nbxplorer
systemctl restart nbxplorer
journalctl -u nbxplorer --no-pager -n 20 | grep "NBXplorer version" | tail -1
实测回显:
NBXplorer -> /opt/nbxplorer/
Oct 22 18:25:16 btcpay245 dotnet[8201]: info: Configuration: NBXplorer version 2.6.19
⚠️ 注意(升级/重启后的同步瞬态):重启 NBXplorer 后立即查询 BTCPay 健康接口,会短暂返回未同步状态,这是索引器重启后重新完成索引就绪的正常过程:
$ curl -s http://127.0.0.1:23000/api/v1/health {"synchronized":false}等待 NBXplorer 日志出现
Node state changed: NBXplorerSynching => Ready后(实测约 2 秒)自动恢复:info: NBXplorer.Events: BTC: Node state changed: NBXplorerSynching => Ready $ curl -s http://127.0.0.1:23000/api/v1/health {"synchronized":true}
9.4 多版本并存(按版本号独立目录)
用 publish 的输出目录参数把不同版本发布到独立目录,可随时切换回滚。实测:把 NBXplorer 2.6.18 发布到独立目录并直接验证版本(--version 参数会打印版本号后退出,不影响运行中的服务):
cd /usr/local/src/NBXplorer
git checkout v2.6.18
dotnet publish NBXplorer/NBXplorer.csproj -c Release -o /opt/nbxplorer-2.6.18
/usr/share/dotnet/dotnet /opt/nbxplorer-2.6.18/NBXplorer.dll --version | head -1
git checkout v2.6.19
实测回显:
NBXplorer -> /opt/nbxplorer-2.6.18/
info: Configuration: NBXplorer version 2.6.18
需要切换到该版本时,把 nbxplorer.service 的 ExecStart 指向 /opt/nbxplorer-2.6.18/NBXplorer.dll,daemon-reload 后重启即可。BTCPay Server 主程序同理。
十、常见问题(排障实录汇总)
10.1 bitcoind 服务一直显示 activating
现象:systemctl is-active bitcoind 长期停在 activating,RPC 实际可响应,300 秒后 systemd 判定服务失败。
定位:官方 tarball 的 bitcoind 不支持 sd_notify 就绪通知,Type=notify 永远等不到 READY。
解决:unit 改为 Type=simple(见 4.5),daemon-reload 后重启。
10.2 NBXplorer 报 Unrecognized option '--btcconf=...'
现象:按老教程传 --btcconf=/etc/bitcoin/bitcoin.conf 启动失败。
定位:2.6.19 已移除该参数。
解决:用 --btcrpcuser/--btcrpcpassword(或 --btcrpccookiefile/--btcrpcauth)显式指定 BTC RPC 凭据(见 5.3)。
10.3 NBXplorer API 返回 404 或 401
现象一:GET /v1/crypto/btc/status 返回 404。
定位:2.6.19 路由改为 v1/cryptos/{cryptoCode}/status(复数 cryptos)。
现象二:新路径返回 401。
定位:REST API 默认启用 cookie 认证,凭据在数据目录 <datadir>/<网络>/.cookie,HTTP Basic 用户名固定 __cookie__。
解决:curl -u "$(cat /var/lib/nbxplorer/RegTest/.cookie) ..."(见 5.5)。BTCPay Server 通过 --btcexplorercookiefile 自动带该凭据。
10.4 BTCPay Server 启动即 ABRT:Access to the path '/home/btcpay' is denied
现象:服务反复重启,日志 System.UnauthorizedAccessException: Access to the path '/home/btcpay' is denied,进程 status=6/ABRT。
定位:useradd -r 未创建 home 目录,应用启动要写运行用户 $HOME。
解决:mkdir -p /home/btcpay && chown btcpay:btcpay /home/btcpay(见 6.4)。
10.5 服务正常但页面 500:ArgumentNullException (Parameter 'path1')
现象:健康检查通过,但注册/登录页面 500;日志指向 BTCPayServer.Services.LanguageService..ctor 的 Path.Combine 收到 null。
定位:systemd 单元缺 WorkingDirectory,工作目录落在 /,WebRootPath(/wwwroot)解析为 null。
解决:unit 加 WorkingDirectory=/opt/btcpayserver(见 6.3、6.4)。
10.6 NBXplorer 日志提示 RPC wallet 功能被禁用
现象:journalctl -u nbxplorer 出现 RPC wallet features are disabled because neither 'BTC.rpc.defaultwallet' nor 'NBXPLORER_BTC_RPC_DEFAULTWALLET' is configured.。
影响:服务可用,但 BTCPay Server 通过 NBXplorer 生成热钱包的能力受影响。
解决:NBXplorer 配置加 --btcrpcdefaultwallet=<钱包名>(指向 bitcoind 中已 createwallet 的钱包),重启后日志出现 BTC: RPC Wallet loaded(见 5.6、5.7)。
10.7 首次启动日志出现 __EFMigrationsHistory 查询失败
现象:fail: ... Failed executing DbCommand ... SELECT "MigrationId", "ProductVersion" FROM "__EFMigrationsHistory"。
定位:EF Core 首次迁移建表前的正常探测异常,非故障。
判断:以 /api/v1/health 返回 {"synchronized":true} 与 Now listening on 日志为准(见 6.5)。
10.8 Bitcoin Core 31 发送交易报 Fallbackfee is disabled
现象:bitcoin-cli ... sendtoaddress ... 报 Fee estimation failed. Fallbackfee is disabled(regtest 等无手续费市场数据的链必现)。
定位:Core 31 默认禁用兜底费率,且老参数 settxfee 已移除(实测调用返回 Method not found)。
解决:转账时显式指定费率,JSON-RPC 中用 fee_rate(单位 sat/vB,最小 1,实测 0.00002/0.0001 均被拒);conf_target 与 fee_rate 不能同时传,estimate_mode 与 fee_rate 也不能同时传。
10.9 端口速查表
| 网络端 | NBXplorer API | BTC RPC | BTC P2P | 说明 |
|---|---|---|---|---|
| mainnet | 24444 | 8332 | 8333 | 生产默认 |
| regtest | 24446 | 18443 | 18444 | 本文验证环境 |
--btcexplorerurl 与 --network 必须配套,混用不同网络的端口会出现 NBXplorer 连接异常。
十一、卸载
按部署资源的逆序删除。以下命令按本文创建的资源路径编写,执行前请再次核对路径:
# 1. 停止并禁用服务
systemctl disable --now btcpayserver nbxplorer bitcoind
# 2. 删除服务单元与配置
rm -f /etc/systemd/system/{btcpayserver,nbxplorer,bitcoind}.service
systemctl daemon-reload
# 3. 删除程序与数据目录
rm -rf /opt/btcpayserver /opt/nbxplorer /opt/bitcoin
rm -rf /var/lib/btcpay /var/lib/nbxplorer /var/lib/bitcoind /etc/bitcoin
rm -rf /usr/local/src/btcpayserver /usr/local/src/NBXplorer
rm -f /usr/local/bin/{bitcoind,bitcoin-cli,bitcoin-wallet,bitcoin-tx,dotnet}
# 4. 删除数据库(psql 中执行)
# DROP DATABASE btcpayservermainnet; DROP DATABASE nbxplorermainnet; DROP USER btcpay;
# 5. 删除系统用户
userdel bitcoin btcpay
十二、参考链接
- BTCPay Server 主仓库:https://github.com/btcpayserver/btcpayserver (v2.4.5 标签)
- NBXplorer 仓库:https://github.com/NicolasDorier/NBXplorer (v2.6.19 标签)
- Bitcoin Core 下载页:https://bitcoincore.org/bin/bitcoin-core-31.1/
- .NET 官方安装脚本:https://dot.net/v1/dotnet-install.sh
- BTCPay Server 官方文档站:https://docs.btcpayserver.org
- Greenfield API 文档:https://docs.btcpayserver.org/API/Greenfield/v1/
- 配置参数逐项说明:《BTCPay Server 2.4.5 配置参数详解》
- Docker Compose 部署形态:《BTCPay Server 2.4.5 Docker Compose 部署指南》
- 组件背景与选型:《BTCPay Server 2.4.5 介绍与选型指南》
- API 集成实操:《BTCPay Server 2.4.5 API 使用详解》