DEV Community

Cover image for XPayLabs Deployment Guide: Run Your Own Multi-Chain Crypto Payment Gateway
Neil Yan
Neil Yan

Posted on

XPayLabs Deployment Guide: Run Your Own Multi-Chain Crypto Payment Gateway

XPayLabs Deployment Guide: Run Your Own Multi-Chain Crypto Payment Gateway

XPayLabs is a production-ready, self-hosted cryptocurrency payment gateway with multi-chain support and multi-tenant architecture. This guide walks through deploying the complete stack — from prerequisites to production go-live.

What You're Deploying

XPayLabs consists of 11 services running in Docker containers:

Service Role Technology
mysql Persistent database MySQL 8.0
redis Cache, queue, nonce store Redis 7 Alpine
sui-node-service SUI blockchain RPC proxy Express (Node.js)
xpay-tron TRON blockchain scanner Spring Boot 3.4 (Java 17)
xpay-sui SUI blockchain scanner Spring Boot 3.4 (Java 17)
xpay-eth EVM scanner (ETH, BSC, Polygon, Avalanche) Spring Boot 3.4 (Java 17)
xpay-user User & collection order API Spring Boot 3.4 (Java 17)
xpay-merchant Merchant backend API Spring Boot 3.4 (Java 17)
merchant-vue Merchant admin dashboard Vue 3 + Element Plus (Nginx)
checkout Payment checkout page Vue 3 + Vite 7 (Nginx)
gateway Reverse proxy (single entry point) Nginx Alpine

All Java services use the same base image (ghcr.io/yan253319066/xpay-java) — different JARs are launched via the command directive.

Prerequisites

  • Docker 24+ and Docker Compose v2+
  • A Linux server (4 GB RAM minimum, 8 GB recommended)
  • Domain names for the merchant dashboard and checkout page
  • SSL certificate (Let's Encrypt or commercial)
  • RPC endpoints for each blockchain you intend to support

Step 1: Clone the Deployment Repository

git clone https://github.com/yan253319066/XPayLabs-docker.git
cd XPayLabs-docker
Enter fullscreen mode Exit fullscreen mode

This repository contains everything needed for deployment: docker-compose.yml, nginx configs, SQL init scripts, and the .env template.

Step 2: Configure Environment Variables

cp .env.example .env
Enter fullscreen mode Exit fullscreen mode

Edit .env with your own values. Here's what each section means:

Database & Cache

MYSQL_ROOT_PASSWORD=<strong-random-password>
DB_USERNAME=root
DB_PASSWORD=<same-or-different-password>
REDIS_PASSWORD=<optional-redis-password>
Enter fullscreen mode Exit fullscreen mode

MySQL is initialized automatically on first startup — the ./sql/init.sql script is mounted to the container's init directory. Redis password is optional; leave empty for no auth.

Encryption Keys (Critical)

ENCRYPTION_KEY=<exactly-32-characters>
JWT_SECRET_KEY=<random-string>
SKIP_SIGN_SECRET=<64-char-hex-secret>
Enter fullscreen mode Exit fullscreen mode
  • ENCRYPTION_KEY: AES-256-CBC key, must be exactly 32 characters. Used by sui-node-service and xpay-sui for encrypting SUI private keys at rest.
  • JWT_SECRET_KEY: Used by xpay-merchant for signing JWT tokens for merchant dashboard sessions.
  • SKIP_SIGN_SECRET: HMAC-SHA256 secret used by the SkipSign feature for internal request signing between services.

Public Domains

XPAY_PAY_DOMAIN=https://pay.your-domain.com/checkout
XPAY_API_DOMAIN=https://api.your-domain.com
Enter fullscreen mode Exit fullscreen mode

These are used by the Java services to construct callback URLs and checkout redirects. They must be publicly accessible URLs after you configure DNS.

Blockchain RPC Configuration

EVM chains (ETH, BSC, Polygon, Avalanche):

ETH_NETWORKS=ETH,ETH_SEPOLIA,BSC,BSC_TEST,POLYGON,POLYGON_AMOY,AVAX_C_CHAIN,AVAX_FUJI_TEST
RPC_ETH=https://0xrpc.io/eth,https://rpc.flashbots.net
SCAN_ETH=15
Enter fullscreen mode Exit fullscreen mode
  • ETH_NETWORKS: Comma-separated list of active networks
  • RPC_*: Comma-separated RPC URLs (the scanner tries each in order for fault tolerance)
  • SCAN_*: Polling interval in seconds between block scans

You can use public RPC endpoints for testnets. For mainnet, consider:

  • Commercial RPC providers (Alchemy, Infura, QuickNode) for reliability
  • Running your own node for maximum sovereignty

TRON:

TRON_NETWORKS=TRON,TRON_TEST
NODE_TRON=grpc.trongrid.io:50051
SOLIDITY_TRON=grpc.trongrid.io:50052
APIKEY_TRON=<your-trongrid-api-key>
Enter fullscreen mode Exit fullscreen mode

TRON uses gRPC (not JSON-RPC). The scanner connects to a full node and a solidity node. An API key from trongrid.io is required for production use.

SUI:

SUI does not require direct RPC configuration in .env. The xpay-sui scanner communicates with sui-node-service (an Express-based RPC proxy running in the same Docker network) via http://sui-node-service:3001.

Port Mappings

HOST_PORT_GATEWAY_HTTP=180
HOST_PORT_MYSQL=13306
HOST_PORT_REDIS=16379
HOST_PORT_XPAY_USER=18077
HOST_PORT_XPAY_MERCHANT=18078
HOST_PORT_XPAY_ETH=18076
HOST_PORT_XPAY_TRON=18075
HOST_PORT_XPAY_SUI=18074
HOST_PORT_SUI_NODE=13001
Enter fullscreen mode Exit fullscreen mode

Only port 180 (the Nginx gateway) needs to be exposed to the internet. The other ports are for internal communication and optional direct access.

Step 3: Launch the Stack

docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Docker Compose starts services in dependency order:

  1. mysql and redis start first
  2. Blockchain scanners (xpay-tron, xpay-eth, xpay-sui + sui-node-service) start after MySQL is healthy
  3. xpay-user starts after scanners
  4. xpay-merchant starts after xpay-user
  5. Frontend services (merchant-vue, checkout) start after their backends
  6. gateway (Nginx) starts last

Verify the Deployment

# Check all services are running
docker compose ps

# Check logs for each service
docker compose logs xpay-user
docker compose logs xpay-eth

# Test the API
curl http://localhost:180/api/symbol/supportSymbols
Enter fullscreen mode Exit fullscreen mode

Step 4: Configure DNS and SSL

DNS Records

Point your domains to the server's public IP:

merchant.your-domain.com A <server-ip>
pay.your-domain.com       A <server-ip>
api.your-domain.com       A <server-ip>
Enter fullscreen mode Exit fullscreen mode

The Nginx gateway routes traffic based on path prefixes:

  • /checkout/* → checkout service (payment page)
  • /api/* → xpay-user API
  • /prod-api/* → xpay-merchant API
  • /* → merchant-vue dashboard (default)

SSL with Let's Encrypt

  1. Obtain certificates:
docker run -it --rm -p 80:80 -v "$(pwd)/certs:/etc/letsencrypt" certbot/certbot certonly --standalone -d merchant.your-domain.com -d pay.your-domain.com
Enter fullscreen mode Exit fullscreen mode
  1. Copy the certificates:
cp certs/live/merchant.your-domain.com/fullchain.pem certs/merchant.crt
cp certs/live/merchant.your-domain.com/privkey.pem certs/merchant.key
Enter fullscreen mode Exit fullscreen mode
  1. Enable SSL in docker-compose.yml:
gateway:
  ports:
    - "180:80"
    - "1443:443"   # uncomment this
  volumes:
    - ./nginx/gateway.conf:/etc/nginx/conf.d/default.conf
    # Replace with:
    # - ./nginx/gateway-ssl.conf:/etc/nginx/conf.d/default.conf
    - ./certs:/etc/nginx/certs   # uncomment this
Enter fullscreen mode Exit fullscreen mode
  1. Update HOST_PORT_GATEWAY_HTTPS=1443 in .env

  2. Restart the gateway:

docker compose restart gateway
Enter fullscreen mode Exit fullscreen mode

Step 5: Create the First Merchant

Access the merchant dashboard at http://localhost:180 (or your domain). The registration flow:

  1. Register — Create a merchant account with email and password
  2. API Credentials — After login, navigate to Settings → API Keys to generate an API key and secret
  3. Webhook URL — Configure the callback URL for payment notifications
  4. Deposit Addresses — The system automatically generates deposit addresses per order using HD wallet derivation — no manual setup needed

Using the API

With your API key and secret:

curl -X POST https://api.your-domain.com/v1/collection/create \
  -H "Content-Type: application/json" \
  -d '{
    "sign": "<hmac-signature>",
    "timestamp": 1717000000000,
    "nonce": "<uuid>",
    "data": {
      "amount": "100.00",
      "symbol": "USDT",
      "chain": "tron",
      "orderId": "order_001"
    }
  }'
Enter fullscreen mode Exit fullscreen mode

SDKs handle signing automatically:

  • Node.js: npm install @xpaylabs/node-sdk
  • Java: Maven Central com.xpaylabs:xpay-java-sdk

Architecture Deep Dive

Multi-Tenant Design

XPayLabs is designed as a platform operator model. A single deployment hosts unlimited merchants, each with:

  • Isolated data (scoped by merchant_id)
  • Separate API credentials (HMAC key pairs)
  • Independent webhook configuration
  • Configurable fee schedules (you set the rates)

HD Wallet Key Management

The gateway uses BIP-44 hierarchical deterministic wallet derivation:

m / 44' / coin_type' / 0' / 0 / address_index
Enter fullscreen mode Exit fullscreen mode
  • Master seed is set via XPAY_MASTER_SEED (not exposed in this Docker setup — the HD wallet key is embedded in the scanner services)
  • Database stores only the derivation index, never private keys
  • Recovery: restore the seed phrase and replay blockchain history

Blockchain Scanner Architecture

Each blockchain has an independent scanner service that:

  1. Polls its RPC node at a configurable interval (2-15 seconds)
  2. Fetches Transfer events involving tracked deposit addresses
  3. Matches events to pending collection orders
  4. Updates order status and enqueues webhook delivery
  5. Waits for chain-specific confirmation count before marking as success
Chain Detection Method Block Time Recommended Confirmations
TRON TRON Grid gRPC API ~3s 1-2
Ethereum JSON-RPC eth_getLogs ~12s 12-30
BSC JSON-RPC polling ~3s 15-30
Polygon JSON-RPC polling ~2s 30-100
Avalanche JSON-RPC polling ~2s 10-20
Arbitrum JSON-RPC polling ~1s 10-20
SUI SUI RPC (via sui-node-service) ~2s 5-10

Production Operations

Monitoring

  • Check service health: docker compose ps
  • View logs: docker compose logs -f --tail=100 <service>
  • Log files are persisted in ./logs/ with per-service subdirectories
  • Consider adding Uptime Kuma or a similar monitoring tool to watch the gateway endpoint

Database Backups

# Manual backup
docker exec xpay-mysql mysqldump -u root -p xpaylabs > backup_$(date +%Y%m%d).sql

# Automated backup with crontab
0 3 * * * docker exec xpay-mysql mysqldump -u root -p$MYSQL_ROOT_PASSWORD xpaylabs > /backups/xpaylabs_$(date +\%Y\%m\%d).sql
Enter fullscreen mode Exit fullscreen mode

Updating Services

docker compose pull        # Pull latest images
docker compose up -d       # Restart with new images
Enter fullscreen mode Exit fullscreen mode

The ghcr.io/yan253319066/xpay-java image contains all Java JARs. Update the image tag in docker-compose.yml when a new version is released.

Scaling

The current architecture uses a single-instance deployment. For horizontal scaling:

  • Read replicas: Add MySQL read replicas for query-heavy workloads
  • Multiple scanners: Run additional scanner instances with different RPC providers for redundancy
  • Load balancing: Place multiple gateway instances behind a TCP load balancer

Troubleshooting

"pull access denied" for ghcr.io images

The images are hosted on a public GitHub Container Registry — no authentication required. Common causes:

  • Network/firewall blocking ghcr.io — try configuring a Docker proxy or mirror
  • ghcr.io rate limiting — wait and retry

If pulling consistently fails, build the images from source:

# Build Java services
cd XPayLabs-java
mvn clean install -P prod -DskipTests
docker build -t ghcr.io/yan253319066/xpay-java .

# Build frontend services
cd XPayLabs-checkout
docker build -t ghcr.io/yan253319066/checkout .
cd XPayLabs-merchant-vue
docker build -t ghcr.io/yan253319066/merchant-vue .
Enter fullscreen mode Exit fullscreen mode

Then update docker-compose.yml to use pull_policy: never and build directives, or tag your local images to match the image names.

MySQL connection refused

MySQL takes ~30-60 seconds to initialize on first run (especially the init SQL). Check health:

docker compose logs mysql
docker compose exec mysql mysqladmin ping -h localhost
Enter fullscreen mode Exit fullscreen mode

Scanner not detecting transactions

  1. Check the scanner logs for RPC errors
  2. Verify the RPC endpoint is reachable from the container
  3. Confirm the deposit address derivation path matches the chain
  4. Check that TRON_NETWORKS or ETH_NETWORKS includes the correct network name

Port conflicts

If port 180 is already in use on the host, change HOST_PORT_GATEWAY_HTTP in .env to any available port (e.g., 8080). All internal service ports can also be remapped.

Cost Analysis for Operators

Running XPayLabs as a payment platform operator:

Item Monthly Cost
Server (4 GB RAM, 2 vCPU) ~$20-40
RPC endpoints (mainnet) ~$50-200 (depending on chains)
Domain + SSL ~$1-5
Total ~$70-250/mo

If you charge merchants 0.5% per transaction and process $500,000/month:

Revenue Stream Monthly
Transaction fees (0.5%) $2,500
Server cost -$70-250
Net profit ~$2,250-2,430/mo

Summary

XPayLabs gives you a complete multi-chain crypto payment infrastructure in a single docker compose up command. The key operational responsibilities are:

  1. Secure the master seed — Generate it offline, store it in a hardware wallet or encrypted vault
  2. Monitor service health — Watch scanner logs and gateway uptime
  3. Back up the database — Regular MySQL dumps
  4. Keep RPC endpoints healthy — Use reliable providers with failover

The SDKs (Node.js and Java), checkout UI, and merchant dashboard are open-source under MIT at github.com/yan253319066/XPayLabs. The core gateway engine is source-available under the XPay Enterprise License.

SDKs: npm | Maven Central

Top comments (0)