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、主程序),含完整实测回显与九类排障实录。

BTCPay ServerBTCPay Server加密货币支付系统自动化部署2026/10/23

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。

组件实测版本安装来源说明
PostgreSQL14.24(Ubuntu 源 14.24-0ubuntu0.22.04.1)apt 官方源Ubuntu 22.04 默认源版本,实测可用
.NET SDK/运行时10.0.402官方 dotnet-install.shBTCPay Server v2.4.5 目标框架为 net10.0
Bitcoin Corev31.1.0bitcoincore.org 官方二进制与官方部署栈锁定的 31.1 版本一致
NBXplorer2.6.19GitHub v2.6.19 标签BTCPay 官方配套链上索引器
BTCPay Server2.4.5GitHub 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 网络):

端口归属用途
23000BTCPay ServerWeb 管理面 + Greenfield API(对外)
24446NBXplorerREST API(BTCPay Server 内部对接)
18443Bitcoin CoreRPC(NBXplorer 对接)
18444Bitcoin CoreP2P(NBXplorer 订阅新区块)
5432PostgreSQL两套数据库

⚠️ 注意: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

配置要点:

参数值说明
--networkregtest链网络;生产改为 mainnet
--postgresbtcpayservermainnet业务库(与 NBXplorer 的 nbxplorermainnet 分库)
--btcexplorerurlhttp://127.0.0.1:24446NBXplorer regtest API;主网为 24444
--btcexplorercookiefile/var/lib/nbxplorer/RegTest/.cookieNBXplorer cookie 凭据;缺省时会找运行用户 $HOME/.nbxplorer/<网络>/.cookie
--port / --bind23000 / 0.0.0.0Web 面端口与监听地址

启动日志中可以看到两条关键确认(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 APIBTC RPCBTC P2P说明
mainnet2444483328333生产默认
regtest244461844318444本文验证环境

--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

十二、参考链接