Docker 一键部署加密支付网关:从零开始完整教程

Docker 一键部署加密支付网关:从零开始完整教程

在电商或 SaaS 项目中集成加密货币支付,很多人第一反应是接入 BitPay 或 Coinbase Commerce。但对于有一定技术能力的团队来说,自托管(Self-Hosted)方案在成本、安全性和品牌体验上都有显著优势。

本文将从零开始,手把手教你用 Docker 部署一个生产级的自托管加密支付网关,并集成到你的应用中。

环境准备

硬件要求

配置项 最低要求 推荐配置
CPU 1 核 2 核
内存 1GB 4GB
磁盘 20GB 50GB (SSD)
网络 公网 IP 公网 IP + 域名

大部分云厂商的入门级 VPS(如阿里云轻量、腾讯云轻量、AWS Lightsail 等)都能满足需求。

软件要求

  • 操作系统:Ubuntu 22.04 / Debian 12 / CentOS 8+(本文以 Ubuntu 22.04 为例)
  • Docker:20.10+
  • Docker Compose:v2+

安装 Docker

bash 复制代码
# 更新包索引
sudo apt update

# 安装依赖
sudo apt install -y ca-certificates curl gnupg lsb-release

# 添加 Docker 官方 GPG 密钥
sudo mkdir -m 0755 -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# 添加 Docker 仓库
echo \
  "deb [arch=$(dpkg --print-architecture) \
  signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 安装 Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# 验证安装
sudo docker --version
sudo docker compose version

第一步:生成主种子(Master Seed)

种子短语是支付网关的根密钥,所有收款地址都由它派生。这一步必须在离线环境中完成

方式一:使用离线工具生成

下载 iancoleman.io/bip39 的离线版本,在不联网的机器上生成 12 或 24 个单词的 BIP-39 种子:

复制代码
abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about

安全警告 :上面的种子是 BIP-39 测试向量,仅用于测试。生产环境绝不可使用。必须在离线、无网络的机器上生成真实种子。

方式二:使用命令行生成(离线)

bash 复制代码
# 使用 openssl 生成 128 位随机数(12 词助记词)
openssl rand -hex 16
# 输出示例: 7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f

# 然后使用 BIP-39 工具将熵转换为助记词(需要离线运行)

记录下生成的 12 或 24 个单词,将其安全保存(纸质备份 + 加密存储)。

第二步:创建项目目录

bash 复制代码
mkdir -p ~/payment-gateway
cd ~/payment-gateway

第三步:配置环境变量

创建 .env 文件:

bash 复制代码
cat > .env << 'EOF'
# 数据库
DB_ROOT_PASSWORD=your_secure_root_password_here
DB_PASSWORD=your_secure_db_password_here

# Redis
REDIS_PASSWORD=your_secure_redis_password_here

# 支付网关
XPAY_MASTER_SEED="your twelve word seed phrase generated offline"
XPAY_WEBHOOK_SECRET=whsec_your_webhook_secret_here
XPAY_API_KEY=xpay_your_api_key_here
XPAY_CHAINS=tron,eth,bsc,polygon

# 链配置(可选,默认使用公共 RPC)
# XPAY_TRON_NETWORK=mainnet
# XPAY_ETH_RPC_URL=https://eth.drpc.org
# XPAY_BSC_RPC_URL=https://bsc.drpc.org
# XPAY_POLYGON_RPC_URL=https://polygon.drpc.org
EOF

注意 :生产环境请将以上密码全部替换为强随机字符串。可以使用 openssl rand -base64 32 生成。

第四步:编写 Docker Compose 文件

创建 docker-compose.yml

yaml 复制代码
version: '3.8'

services:
  mysql:
    image: mysql:8.0
    container_name: gateway-mysql
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      MYSQL_DATABASE: xpay_gateway
      MYSQL_USER: xpay
      MYSQL_PASSWORD: ${DB_PASSWORD}
    volumes:
      - mysql_data:/var/lib/mysql
    networks:
      - gateway-net
    restart: always
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: gateway-redis
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data
    networks:
      - gateway-net
    restart: always
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5

  gateway:
    image: ghcr.io/xpaylabs/gateway:latest
    container_name: xpay-gateway
    ports:
      - "8080:8080"
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/xpay_gateway?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
      SPRING_DATASOURCE_USERNAME: xpay
      SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD}
      SPRING_DATASOURCE_DRIVER_CLASS_NAME: com.mysql.cj.jdbc.Driver
      SPRING_REDIS_HOST: redis
      SPRING_REDIS_PORT: 6379
      SPRING_REDIS_PASSWORD: ${REDIS_PASSWORD}
      XPAY_MASTER_SEED: ${XPAY_MASTER_SEED}
      XPAY_WEBHOOK_SECRET: ${XPAY_WEBHOOK_SECRET}
      XPAY_API_KEY: ${XPAY_API_KEY}
      XPAY_CHAINS: ${XPAY_CHAINS}
      # 可选:自定义区块链 RPC
      # XPAY_TRON_GRID_URL: https://api.trongrid.io
      # XPAY_ETH_RPC_URL: https://eth.drpc.org
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - gateway-net
    restart: always
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

volumes:
  mysql_data:
  redis_data:

networks:
  gateway-net:
    driver: bridge

第五步:启动网关

bash 复制代码
# 启动所有服务
sudo docker compose up -d

# 查看启动日志
sudo docker compose logs -f gateway

# 等待约 30-60 秒,看到类似以下日志表示启动成功:
# [INFO] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http)
# [INFO] [main] c.xpay.gateway.GatewayApplication : Started GatewayApplication in 25.4 seconds

第六步:验证网关运行状态

bash 复制代码
# 测试网关 API 是否正常响应
curl -X GET http://localhost:8080/api/v1/health

# 预期返回:
# {"status":"UP","timestamp":"2025-01-15T10:30:00Z"}

创建一张测试发票验证功能:

bash 复制代码
curl -X POST http://localhost:8080/api/v1/invoices \
  -H "Content-Type: application/json" \
  -H "X-API-Key: xpay_your_api_key_here" \
  -d '{
    "amount": "10.00",
    "currency": "USD",
    "chain": "tron",
    "settlementAsset": "USDT",
    "description": "测试订单 #001",
    "metadata": {"orderId": "001"}
  }'

成功后会返回类似:

json 复制代码
{
  "id": "inv_a1b2c3d4",
  "amount": "10.00",
  "currency": "USD",
  "chain": "tron",
  "settlementAsset": "USDT",
  "depositAddress": "TXYZ1234...",
  "status": "pending",
  "checkoutUrl": "http://localhost:8080/checkout/inv_a1b2c3d4",
  "createdAt": "2025-01-15T10:31:00Z",
  "expiresAt": "2025-01-15T11:01:00Z"
}

第七步:配置 Nginx 反向代理(生产环境)

生产环境不应直接暴露网关端口。使用 Nginx 反向代理 + SSL 证书:

nginx 复制代码
# /etc/nginx/sites-available/payments.example.com
server {
    listen 443 ssl;
    server_name payments.example.com;

    ssl_certificate /etc/letsencrypt/live/payments.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/payments.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

# HTTP 重定向到 HTTPS
server {
    listen 80;
    server_name payments.example.com;
    return 301 https://$server_name$request_uri;
}

申请 SSL 证书:

bash 复制代码
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d payments.example.com

第八步:集成到你的后端应用

Node.js/TypeScript 集成

bash 复制代码
npm install @xpaylabs/node-sdk
typescript 复制代码
import { XPayClient } from '@xpaylabs/node-sdk';

const client = new XPayClient({
  apiKey: process.env.XPAY_API_KEY,
  gatewayUrl: 'https://payments.example.com'
});

// 创建支付订单
app.post('/api/create-payment', async (req, res) => {
  const { orderId, amount } = req.body;

  const invoice = await client.createInvoice({
    amount: amount.toString(),
    currency: 'USD',
    chain: 'tron',
    settlementAsset: 'USDT',
    description: `订单 #${orderId}`,
    metadata: { orderId },
    successUrl: `https://myshop.com/order/success/${orderId}`,
    cancelUrl: `https://myshop.com/order/${orderId}`
  });

  res.json({
    invoiceId: invoice.id,
    checkoutUrl: invoice.checkoutUrl
  });
});

// Webhook 处理支付确认
app.post('/api/webhooks/xpay',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    const sig = req.headers['x-webhook-signature'];
    const expected = crypto
      .createHmac('sha256', process.env.XPAY_WEBHOOK_SECRET)
      .update(req.body)
      .digest('hex');

    if (sig !== expected) {
      return res.status(401).send('Invalid signature');
    }

    const event = JSON.parse(req.body);
    if (event.type === 'invoice.confirmed') {
      const { orderId } = event.data.metadata;
      // 释放订单、发送商品、更新数据库
      console.log(`订单 ${orderId} 支付确认`);
    }

    res.status(200).send('OK');
  }
);

Java/Spring Boot 集成

xml 复制代码
<dependency>
    <groupId>io.xpay</groupId>
    <artifactId>xpay-java-sdk</artifactId>
    <version>0.1.0</version>
</dependency>
java 复制代码
@Configuration
public class XPayConfig {
    @Bean
    public XPayClient xPayClient(@Value("${xpay.api-key}") String apiKey,
                                  @Value("${xpay.gateway-url}") String gatewayUrl) {
        return new XPayClient(apiKey, gatewayUrl);
    }
}

@Service
public class PaymentService {
    @Autowired
    private XPayClient xPayClient;

    public Invoice createPayment(String orderId, BigDecimal amount) {
        CreateInvoiceRequest request = new CreateInvoiceRequest();
        request.setAmount(amount.toString());
        request.setCurrency("USD");
        request.setChain("tron");
        request.setSettlementAsset("USDT");
        request.setDescription("订单 #" + orderId);
        request.setSuccessUrl("https://myshop.com/order/success/" + orderId);

        return xPayClient.createInvoice(request);
    }
}

@RestController
public class WebhookController {
    @PostMapping("/api/webhooks/xpay")
    public ResponseEntity<String> handleWebhook(
            @RequestBody String payload,
            @RequestHeader("x-webhook-signature") String signature) {

        String expected = HmacUtils.hmacSha256Hex(
            webhookSecret, payload);

        if (!expected.equals(signature)) {
            return ResponseEntity.status(401).body("Invalid signature");
        }

        // 处理事件...
        return ResponseEntity.ok("OK");
    }
}

第九步:配置 Nginx 白标结账页面

网关自带白标结账页面。只需配置前端域名,客户看到的就是你的品牌:

yaml 复制代码
# docker-compose.yml 中添加前端环境变量
services:
  gateway:
    environment:
      XPAY_BRAND_NAME: "你的品牌名称"
      XPAY_BRAND_LOGO_URL: "https://example.com/logo.png"
      XPAY_SUPPORT_EMAIL: "support@example.com"
      XPAY_PRIMARY_COLOR: "#2563eb"

运维与监控

查看日志

bash 复制代码
# 实时日志
sudo docker compose logs -f --tail=100

# 查看特定服务的日志
sudo docker compose logs -f gateway
sudo docker compose logs -f mysql

备份数据库

bash 复制代码
# 创建备份脚本 backup.sh
#!/bin/bash
BACKUP_DIR="/backups/gateway"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR

# 备份 MySQL
sudo docker compose exec -T mysql \
  mysqldump -u root -p${DB_ROOT_PASSWORD} xpay_gateway \
  > $BACKUP_DIR/gateway_$TIMESTAMP.sql

# 压缩备份
gzip $BACKUP_DIR/gateway_$TIMESTAMP.sql

# 保留最近 30 天备份,删除更早的
find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete

添加到 crontab 实现自动备份:

bash 复制代码
0 3 * * * /root/payment-gateway/backup.sh

更新网关

bash 复制代码
cd ~/payment-gateway

# 拉取最新镜像
sudo docker compose pull gateway

# 重新创建容器
sudo docker compose up -d --no-deps gateway

常见问题

1. 网关启动后立即退出

检查配置文件和数据库连接:

bash 复制代码
# 查看完整错误日志
sudo docker compose logs gateway

# 常见原因:数据库连接失败、种子短语格式错误
# 确认 MySQL 服务健康:
sudo docker compose ps

2. 无法创建发票

bash 复制代码
# 检查 API 密钥是否正确
curl -X POST http://localhost:8080/api/v1/invoices \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your_key_here" \
  -d '{"amount":"10","currency":"USD","chain":"tron","settlementAsset":"USDT"}'

# 如果返回 401,检查 .env 中的 XPAY_API_KEY 配置

3. 交易检测不到

bash 复制代码
# 检查是否配置了正确的链
curl -X GET http://localhost:8080/api/v1/chains

# 确认使用的网络(主网/测试网)
# 测试网使用 TRON Shasta 网络:XPAY_TRON_NETWORK=shasta

4. Webhook 收不到回调

bash 复制代码
# 确认 Webhook URL 可公网访问
# 确认 Webhook Secret 前后端一致
# 查看 Webhook 投递日志:
curl -X GET http://localhost:8080/api/v1/webhooks/logs?limit=10 \
  -H "X-API-Key: your_key_here"

成本估算

部署完成后,运行成本如下:

项目 月成本
VPS(2核4G) ¥50-100
域名 ¥5-10
SSL 证书(Let's Encrypt) 免费
区块链 RPC 费用 $0-15
总计 约 ¥50-150/月

对比第三方网关(月流水 10 万美元情况下):

方案 月费用 年费用
BitPay 1,030-1,300 12,360-15,600
Coinbase Commerce $1,000 $12,000
自托管 ¥50-150 (~$7-21) ¥600-1,800 (~$84-252)

总结

本文从零开始完成了 Docker 部署加密支付网关的全流程:

  1. 环境准备:服务器、Docker 安装
  2. 密钥生成:离线 BIP-39 种子短语
  3. 配置部署:Docker Compose 一键启动
  4. 集成验证:API 创建发票 + Webhook 回调
  5. 生产加固:Nginx 反向代理、SSL、备份

整个部署过程大约需要 30 分钟,之后的维护主要是偶尔更新镜像和检查备份。对于月流水 1 万美元以上的商家,一年节省的费用足以覆盖数十倍的部署投入。

如果你正在寻找替代 BitPay 或 Coinbase Commerce 的自托管方案,这个部署流程是一个很好的起点。对于需要 TRON USDT 原生支持、多链架构和白标体验的团队,基于 Docker 的自托管网关是目前性价比最高的选择。

相关推荐
涛声依旧-底层原理研究所2 小时前
Docker+K8s:云原生应用基石
docker·kubernetes
杨云龙UP2 小时前
Oracle CDB巡检脚本使用SOP:从HTML原始报告到Word正式交付_2026-05-29
运维·服务器·数据库·oracle·架构·html·巡检
難釋懷2 小时前
Nginx自签名-OpenSSL
运维·chrome·nginx
2301_803538952 小时前
CentOS版本差异详解和系统信息查看方法
linux·运维·centos
灰灰老师2 小时前
Docker部署Tomcat9
java·linux·docker·tomcat
IT策士2 小时前
第14篇 Docker Compose 开发环境最佳实践:热重载与调试
运维·docker·容器
运维老郭2 小时前
【Kubernetes 性能排查】线上服务突然变慢?SRE 的 4 层排查法
运维·云原生·kubernetes
正在走向自律2 小时前
架构进阶:从 Docker 环境变量到 Nacos 统一配置中心实战
docker·容器·架构
comedate2 小时前
[WSL2] 解决 WSL2 中 Docker 部署的 SearXNG 重启后,localhost 不能用的问题
docker·wsl2·searxng