Self-Hosting
Run your own x402 facilitator with x402-rs
If you prefer full control over your infrastructure, you can run your own x402 facilitator using x402-rs.
Consider Self-Hosting If:
- Custom logic - You need specialized behavior during x402 workflows
- Regulatory compliance - Data residency requirements or audit trails that must stay on your infrastructure
- Absolute control - You want complete ownership of the payment verification and settlement process
- Blockchain proximity - You’re already running nodes or have deep integration with the target chain
- Ops-ready - You’re comfortable managing gas bumps, stuck transactions, nonce coordination, and private key management yourself
Use FareSide Hosted If:
- Avoid settlement complexity - We handle gas bumps, stuck transactions, nonce management, private key management and other operational headaches for you
- Getting started - Focus on building your product, not payment infrastructure
- Managed reliability - Want uptime guarantees and automatic failover
- Advanced features - Need payment splits, webhooks, or cross-chain support (coming soon)
Prerequisites
- Docker (recommended) or Rust toolchain (1.80+)
- Access to RPC endpoints for your target networks
- Private key for the facilitator wallet (for gas)
- Server with reliable uptime
Quick Start with Docker
Prebuilt Docker images are available from:
- GitHub Container Registry:
ghcr.io/x402-rs/x402-facilitator
1. Create Configuration File
Create a config.json file. Note the use of CAIP-2 identifiers for chain keys.
{
"port": 8080,
"host": "0.0.0.0",
"chains": {
"eip155:84532": {
"eip1559": true,
"signers": ["$EVM_PRIVATE_KEY"],
"rpc": [{
"http": "https://sepolia.base.org",
"rate_limit": 100
}]
},
"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": {
"signers": ["$SOLANA_PRIVATE_KEY"],
"rpc": "https://api.devnet.solana.com"
},
"aptos:2": {
"rpc": "https://fullnode.testnet.aptoslabs.com/v1",
"sponsor_gas": true,
"signer": "$APTOS_PRIVATE_KEY"
}
},
"schemes": [{
"id": "v1-eip155-exact",
"chains": "eip155:*"
}, {
"id": "v2-eip155-exact",
"chains": "eip155:*"
}, {
"id": "v2-eip155-upto",
"chains": "eip155:*"
}, {
"id": "v2-solana-exact",
"chains": "solana:*"
}, {
"id": "v2-aptos-exact",
"chains": "aptos:*"
}]
}
2. Create Environment File
Create a .env file with your secrets:
CONFIG=config.json
EVM_PRIVATE_KEY=0x...
SOLANA_PRIVATE_KEY=base58key...
APTOS_PRIVATE_KEY=0x...
RUST_LOG=info
3. Run the Container
docker run --env-file .env -v $(pwd)/config.json:/app/config.json -p 8080:8080 ghcr.io/x402-rs/x402-facilitator
4. Verify It’s Running
curl http://localhost:8080/health
Configuration Reference
The facilitator is configured via config.json.
Chains Configuration
Keys are CAIP-2 chain identifiers.
EVM (eip155):
"eip155:8453": {
"eip1559": true,
"flashblocks": false,
"signers": ["$PRIVATE_KEY"],
"rpc": [{ "http": "https://mainnet.base.org" }]
}
eip1559— use EIP-1559 transaction format (defaults totrue; set it tofalseif a chain does not support it)flashblocks— whentrue, uselatestblock for gas estimation (check if your chain is flashblocks-enabled)signers— array of private keys (hex with0xprefix), supports$ENV_VARsyntaxrpc— array of RPC endpoint objects withhttporhttpsURL and optionalrate_limit
Solana (solana):
"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": {
"signer": "$PRIVATE_KEY",
"rpc": "https://api.mainnet-beta.solana.com",
"pubsub": "wss://api.mainnet-beta.solana.com"
}
signer— Ed25519 private key (base58-encoded), supports$ENV_VARsyntaxrpc— HTTP RPC endpoint URLpubsub— WebSocket endpoint for transaction confirmations (optional but recommended)
Aptos (aptos):
"aptos:1": {
"rpc": "https://fullnode.mainnet.aptoslabs.com/v1",
"sponsor_gas": true,
"signer": "$PRIVATE_KEY"
}
rpc— Aptos fullnode REST API URLsponsor_gas— whentrue, the facilitator pays gas fees for client transactions (recommended)signer— Ed25519 private key (hex with0xprefix), supports$ENV_VARsyntax
Schemes Configuration
Defines which payment schemes are enabled for which chains.
"schemes": [
{
"id": "v2-eip155-exact",
"chains": "eip155:*"
},
{
"id": "v2-eip155-upto",
"chains": "eip155:*"
},
{
"id": "v2-solana-exact",
"chains": "solana:*"
},
{
"id": "v2-aptos-exact",
"chains": "aptos:*"
}
]
Supported chains field formats:
- Specific:
eip155:84532matches only Base Sepolia - Pattern:
eip155:{1,5,84532}matches specific chains - Wildcard:
eip155:*matches all EVM chains,solana:*matches all Solana chains
Building from Source
If you prefer to build locally:
# Clone the repository
git clone https://github.com/x402-rs/x402-rs.git
cd x402-rs
# Build and run the facilitator package
cargo run --release --package x402-facilitator --features full
Or build your own Docker image:
docker build -t x402-facilitator .
docker run --env-file .env -v $(pwd)/config.json:/app/config.json -p 8080:8080 x402-facilitator
Docker Compose
For production deployments:
version: '3.8'
services:
facilitator:
image: ghcr.io/x402-rs/x402-facilitator
ports:
- "8080:8080"
volumes:
- ./config.json:/app/config.json
env_file:
- .env
restart: unless-stopped
Connecting Your Services
Point your middleware to your self-hosted facilitator:
TypeScript
import { HTTPFacilitatorClient } from "@x402/core/server";
const facilitatorClient = new HTTPFacilitatorClient({
url: "http://your-facilitator:8080"
});
Rust (x402-axum)
use x402_axum::X402Middleware;
// Point to your self-hosted facilitator
let x402 = X402Middleware::try_from("http://your-facilitator:8080/").unwrap();
Production Considerations
High Availability
For production, run multiple facilitator instances behind a load balancer:
Example docker-compose.prod.yml:
version: '3.8'
services:
facilitator-1:
image: ghcr.io/x402-rs/x402-facilitator
volumes:
- ./config.json:/app/config.json
env_file: .env.instance1 # Unique private key
facilitator-2:
image: ghcr.io/x402-rs/x402-facilitator
volumes:
- ./config.json:/app/config.json
env_file: .env.instance2 # Different private key
nginx:
image: nginx
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
Sharing a private key across multiple facilitator instances will cause nonce collisions and transaction failures. Each instance needs a unique EVM_PRIVATE_KEY, SOLANA_PRIVATE_KEY, and APTOS_PRIVATE_KEY, and each wallet must be funded with gas tokens.
Each facilitator instance needs its own funded wallet:
- Generate separate keys for each instance
- Fund each wallet with gas tokens on all supported networks
- Monitor gas balances across all wallets
- Consider using a key management service for rotation
RPC providers often have rate limits. For high-availability deployments:
- Carefully distribute RPC endpoints across instances to spread the load
- Use different RPC providers for different instances
# .env.instance1
EVM_PRIVATE_KEY=0xKey1...
RPC_URL_BASE=https://base-mainnet.g.alchemy.com/v2/KEY_1
# .env.instance2
EVM_PRIVATE_KEY=0xKey2...
RPC_URL_BASE=https://base.llamarpc.com
Security
- Minimize wallet balances - Don’t keep large amounts of gas funds in facilitator wallets. Top up regularly as they deplete rather than pre-funding with large amounts
- Never expose private keys in logs or error messages
- Use HTTPS in production (terminate at load balancer)
- Firewall the facilitator to only accept traffic from your services
- Rotate keys periodically
Logs
Enable detailed logging via environment variable:
RUST_LOG=debug
Observability
The facilitator emits OpenTelemetry-compatible traces and metrics. To enable:
# For Honeycomb / Jaeger / etc
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
OTEL_SERVICE_NAME=x402-facilitator
Comparison: Self-Hosted vs FareSide
| Aspect | Self-Hosted | FareSide |
|---|---|---|
| Setup time | Hours | Minutes |
| Settlement ops | Gas bumps, nonces, stuck txs - all yours | Handled for you |
| Private key management | Generate, secure, rotate, fund multiple wallets | Not your problem |
| RPC management | Rate limits, failover, multiple providers | Managed |
| High availability | Complex (unique keys per instance, RPC planning) | Built-in |
| Cost model | Fixed (servers + gas + ops time) | Per transaction |
| Uptime | Your responsibility | 99.9% SLA |
| Payment routing | DIY | Included |
| Support | Community | Direct |
Migration
From FareSide to Self-Hosted
- Set up your facilitator
- Test with a staging environment
- Update middleware configuration
- Monitor for issues
From Self-Hosted to FareSide
- Join the waitlist
- Get your API key
- Update middleware to use FareSide URL
- Decommission your facilitator
Resources
- x402-rs Repository: github.com/x402-rs/x402-rs
- Issues & Support: GitHub Issues
- FareSide Support: t.me/faresidehq