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 Environment File
Create a .env file with your configuration:
# Server
HOST=0.0.0.0
PORT=8080
# Signer configuration
SIGNER_TYPE=private-key
EVM_PRIVATE_KEY=0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef
SOLANA_PRIVATE_KEY=6ASf5EcmmEHTgDJ4X4ZT5vT6iHVJBXPg5AN5YoTCpGWt
# RPC endpoints (only networks you configure will be supported)
RPC_URL_BASE_SEPOLIA=https://sepolia.base.org
RPC_URL_BASE=https://mainnet.base.org
RPC_URL_SOLANA=https://api.mainnet-beta.solana.com
# Logging
RUST_LOG=info
2. Run the Container
docker run --env-file .env -p 8080:8080 ghcr.io/x402-rs/x402-facilitator
3. Verify It’s Running
curl http://localhost:8080/health
Configuration Reference
The facilitator is configured entirely through environment variables:
| Variable | Required | Description |
|---|---|---|
HOST | No | HTTP host to bind to (default: 0.0.0.0) |
PORT | No | HTTP server port (default: 8080) |
SIGNER_TYPE | Yes | Type of signer, only private-key supported |
EVM_PRIVATE_KEY | Yes* | Private key in hex for EVM networks |
SOLANA_PRIVATE_KEY | Yes* | Private key for Solana networks |
RUST_LOG | No | Logging level (info, debug, trace) |
*At least one private key is required depending on which networks you support.
RPC Endpoints
The networks you support are determined by which RPC URLs you provide:
| Network | Environment Variable |
|---|---|
| Base Sepolia (testnet) | RPC_URL_BASE_SEPOLIA |
| Base Mainnet | RPC_URL_BASE |
| Solana Mainnet | RPC_URL_SOLANA |
| Solana Devnet | RPC_URL_SOLANA_DEVNET |
| Polygon Mainnet | RPC_URL_POLYGON |
| Polygon Amoy (testnet) | RPC_URL_POLYGON_AMOY |
| Avalanche Mainnet | RPC_URL_AVALANCHE |
| Avalanche Fuji (testnet) | RPC_URL_AVALANCHE_FUJI |
| Sei Mainnet | RPC_URL_SEI |
| Sei Testnet | RPC_URL_SEI_TESTNET |
If an RPC URL for a network is missing, that network will not be available.
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
cargo build --release
cargo run --release
Or build your own Docker image:
docker build -t x402-rs .
docker run --env-file .env -p 8080:8080 x402-rs
Docker Compose
For production deployments:
version: '3.8'
services:
facilitator:
image: ghcr.io/x402-rs/x402-facilitator
ports:
- "8080:8080"
env_file:
- .env
restart: unless-stopped
Connecting Your Services
Point your middleware to your self-hosted facilitator:
TypeScript (x402-hono)
import { Hono } from "hono";
import { serve } from "@hono/node-server";
import { paymentMiddleware } from "x402-hono";
const app = new Hono();
// Configure the payment middleware with your self-hosted facilitator
app.use(paymentMiddleware(
"0xYourAddress", // your receiving wallet address
{ // Route configurations for protected endpoints
"/weather": {
price: "$0.001",
network: "base-sepolia",
config: {
description: "Access to weather data",
}
}
},
{
url: "http://your-facilitator:8080/", // Your self-hosted facilitator
}
));
// Implement your route
app.get("/weather", (c) => {
return c.json({
report: {
weather: "sunny",
temperature: 70,
}
});
});
serve({
fetch: app.fetch,
port: 3000
});
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:
# docker-compose.prod.yml
version: '3.8'
services:
facilitator-1:
image: ghcr.io/x402-rs/x402-facilitator
env_file: .env.instance1 # Unique private key
facilitator-2:
image: ghcr.io/x402-rs/x402-facilitator
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 and SOLANA_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
RPC_URL_BASE=https://base-mainnet.g.alchemy.com/v2/KEY_1
# .env.instance2
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
OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io:443
OTEL_EXPORTER_OTLP_HEADERS=x-honeycomb-team=your_api_key,x-honeycomb-dataset=x402-rs
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
The service automatically detects and initializes exporters if OTEL_EXPORTER_OTLP_* variables are provided.
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