Production Docker Architecture: Running WAIaaS Daemon + Push-Relay for Enterprise AI Wallets
Would you trust a third party with your AI agent's private keys? If you're building autonomous agents that move real money, that question deserves a serious answer — and for many developers, the answer is no. Self-hosting your wallet infrastructure means your keys live on your server, your policies run in your container, and no external service can rate-limit, suspend, or snoop on your agent's transactions.
Why Self-Hosting Your AI Wallet Infrastructure Matters
The case for self-hosted infrastructure in the AI wallet space isn't just philosophical — it's practical. When your agent executes DeFi trades, pays for API calls via x402, or moves funds across chains, every transaction passes through whatever infrastructure sits between the agent and the blockchain. If that infrastructure is a hosted service, you've introduced a custody and availability dependency you can't control.
Running WAIaaS on your own server flips that equation. You control the master password, the signing keys, the policy engine, and the notification channel. There are no API rate limits imposed by a third party, no Terms of Service that could cut off your agent mid-operation, and no vendor with visibility into your wallet activity. It's the crypto equivalent of running your own email server — except the tooling has matured to the point where it's actually practical.
WAIaaS is an open-source, self-hosted Wallet-as-a-Service built for AI agents. Its 15-package monorepo ships everything you need to run production wallet infrastructure: the main daemon, a push-relay service for mobile notifications, a CLI, MCP integration, and a policy engine. Let's walk through what a production Docker deployment looks like.
The Two-Service Architecture
One detail worth understanding before you deploy: WAIaaS ships two Docker images, not one.
-
waiaasdaemon — the core wallet service. This handles the REST API (39 route modules), the 7-stage transaction pipeline, the policy engine, session auth, and DeFi integrations. -
push-relay— a companion service that handles mobile push notifications for transaction approvals. When your agent submits a transaction that hits the APPROVAL tier, the push-relay is what sends the alert to your phone.
Both images live in the same repository. The daemon is the required service; push-relay is what you add when you want human-in-the-loop approval via mobile notifications rather than requiring you to be at a terminal.
This separation is deliberate. The push-relay has no access to private keys — it only receives notification events and forwards them. You can run the daemon without it, or run the push-relay on a different host entirely if your security model requires it.
Understanding the Security Model Before You Deploy
WAIaaS implements a 3-layer security architecture:
- Session auth → policy evaluation — every agent transaction passes through the policy engine before execution
- Time delay + approval — the DELAY and APPROVAL tiers hold transactions until conditions are met
- Monitoring + kill switch — incoming transaction monitoring and owner-controlled recovery
Three auth methods govern who can do what:
- masterAuth (Argon2id) — system administrator operations: creating wallets, managing sessions, setting policies
- sessionAuth (JWT HS256) — what your AI agent uses for day-to-day operations: sending tokens, querying balances, executing DeFi actions
- ownerAuth (SIWS/SIWE) — the fund owner: approving held transactions, using the kill switch
The policy engine enforces a default-deny model. Until you explicitly configure ALLOWED_TOKENS or CONTRACT_WHITELIST, transactions are blocked. This is the right default for production — you opt into what your agent can do, not out of what it can't.
Deploying with Docker Compose
The fastest path to a running daemon is docker compose up:
git clone https://github.com/minhoyoo-iotrust/WAIaaS.git
cd WAIaaS
docker compose up -d
That's genuinely it for a first run. The image is ghcr.io/minhoyoo-iotrust/waiaas:latest and the default port binding is 127.0.0.1:3100:3100 — localhost-only by design. Your daemon is not exposed to the internet out of the box.
For a more controlled first start — useful if you want to script the setup or run headless — use the auto-provision flag:
docker run -d \
--name waiaas \
-p 127.0.0.1:3100:3100 \
-v waiaas-data:/data \
-e WAIAAS_AUTO_PROVISION=true \
ghcr.io/minhoyoo-iotrust/waiaas:latest
# Retrieve the auto-generated master password
docker exec waiaas cat /data/recovery.key
WAIAAS_AUTO_PROVISION=true tells the entrypoint to generate a random master password on first boot and write it to /data/recovery.key. This is useful for automated deployments where you don't want to manually set a password before the first start. You can harden it later with waiaas set-master once the daemon is running.
Here's the full Compose configuration the project ships with:
services:
daemon:
image: ghcr.io/minhoyoo-iotrust/waiaas:latest
container_name: waiaas-daemon
ports:
- "127.0.0.1:3100:3100"
volumes:
- waiaas-data:/data
environment:
- WAIAAS_DATA_DIR=/data
- WAIAAS_DAEMON_HOSTNAME=0.0.0.0
env_file:
- path: .env
required: false
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3100/health"]
interval: 30s
timeout: 5s
start_period: 10s
retries: 3
volumes:
waiaas-data:
driver: local
A few things worth noting in this config:
-
Named volume (
waiaas-data) — your wallet data persists across container restarts and updates.docker compose downwithout-vleaves your data intact. - Healthcheck — Docker will restart the container if the health endpoint stops responding. Good for unattended production runs.
-
restart: unless-stopped— the daemon comes back after host reboots. -
127.0.0.1:3100— only localhost can reach it. If you need external access, put a reverse proxy (nginx, Caddy) in front and handle TLS there. Don't expose port 3100 directly to the internet.
Production Secrets Management
The docker-compose.secrets.yml overlay is how you handle credentials in production without putting them in environment variables or .env files that end up in logs.
# Create secret files
mkdir -p secrets
echo "your-secure-password" > secrets/master_password.txt
chmod 600 secrets/master_password.txt
# Deploy with secrets overlay
docker compose -f docker-compose.yml -f docker-compose.secrets.yml up -d
Docker Secrets integration is supported directly in the entrypoint. The secret files are mounted into the container at runtime and read by the entrypoint script — they never appear in docker inspect output or process environment listings.
For self-hosters who care about operational security, this is the right way to run it. Your master password lives in a file with 600 permissions, not in a shell history or a .env file sitting next to your docker-compose.yml.
Key Environment Variables
The daemon is configured primarily through environment variables. The important ones for a production deployment:
WAIAAS_AUTO_PROVISION=true # Auto-generate master password on first start
WAIAAS_DAEMON_PORT=3100 # Listening port
WAIAAS_DAEMON_HOSTNAME=0.0.0.0 # Bind address
WAIAAS_DAEMON_LOG_LEVEL=info # Log level (trace/debug/info/warn/error)
WAIAAS_DATA_DIR=/data # Data directory
WAIAAS_RPC_SOLANA_MAINNET=<url> # Solana mainnet RPC endpoint
WAIAAS_RPC_EVM_ETHEREUM_MAINNET=<url> # Ethereum mainnet RPC endpoint
The RPC endpoint variables matter for production. The daemon needs RPC access for 2 chain types across 18 networks. If you're running a self-hosted Solana or Ethereum node, this is where you point the daemon at it — keeping your infrastructure fully sovereign, not just your keys.
Setting Up Wallets and Policies
Once the daemon is running, the CLI handles the initial setup. Install it globally:
npm install -g @waiaas/cli
The CLI ships 20 commands. For initial setup, the relevant flow is:
waiaas init # Create data directory + config.toml
waiaas start # Start daemon
waiaas quickset --mode mainnet # Create wallets + MCP sessions in one step
quickset is the fast path. It creates wallets across the chains you configure and generates MCP sessions — the tokens your AI agent will use.
For manual control, create a wallet directly via the API:
curl -X POST http://127.0.0.1:3100/v1/wallets \
-H "Content-Type: application/json" \
-H "X-Master-Password: my-secret-password" \
-d '{"name": "trading-wallet", "chain": "solana", "environment": "mainnet"}'
Then create a session token for your agent:
curl -X POST http://127.0.0.1:3100/v1/sessions \
-H "Content-Type: application/json" \
-H "X-Master-Password: my-secret-password" \
-d '{"walletId": "<wallet-uuid>"}'
That session token is what your agent uses. It has no access to wallet creation or policy management — only to the operations you've allowed through policies.
Configuring the Policy Engine for Production
The default-deny model means you need to configure policies before your agent can do anything useful. Here's a sensible starting point for a trading wallet — a spending limit with four tiers:
curl -X POST http://127.0.0.1:3100/v1/policies \
-H "Content-Type: application/json" \
-H "X-Master-Password: my-secret-password" \
-d '{
"walletId": "<wallet-uuid>",
"type": "SPENDING_LIMIT",
"rules": {
"instant_max_usd": 100,
"notify_max_usd": 500,
"delay_max_usd": 2000,
"delay_seconds": 900,
"daily_limit_usd": 5000
}
}'
This gives you the full 4-tier security model in action:
- ≤$100: executes immediately, no noise
- $100–$500: executes immediately, sends a notification
- $500–$2,000: queued for 15 minutes, then executes (you can cancel during the window)
- >$2,000: held until you explicitly approve via WalletConnect, Telegram, or push notification
The 21 policy types cover everything from token whitelists and contract whitelists to DeFi-specific rules like PERP_MAX_LEVERAGE for perpetual futures positions and LENDING_LTV_LIMIT for lending protocols. For production, you'll want at minimum ALLOWED_TOKENS and CONTRACT_WHITELIST configured — without them, the default-deny model blocks token transfers and contract calls entirely.
Connecting Your Agent via MCP
Once the daemon is running and wallets are configured, connecting Claude or another MCP-compatible AI is a one-command operation:
waiaas mcp setup --all # Auto-register all wallets with Claude Desktop
Or configure it manually in claude_desktop_config.json:
{
"mcpServers": {
"waiaas": {
"command": "npx",
"args": ["-y", "@waiaas/mcp"],
"env": {
"WAIAAS_BASE_URL": "http://127.0.0.1:3100",
"WAIAAS_SESSION_TOKEN": "wai_sess_<your-token>",
"WAIAAS_DATA_DIR": "~/.waiaas"
}
}
}
}
The MCP server exposes 45 tools covering wallet operations, transactions, DeFi actions across 15 integrated protocols, NFT operations, and x402 HTTP payment. Your agent gets a session-scoped, policy-enforced interface to your self-hosted wallet — no third-party relay, no external API calls beyond the blockchain RPCs you've configured.
Useful Docker Operations
docker compose up -d # Start daemon
docker compose logs -f # Follow logs
docker compose down # Stop (data preserved in named volume)
docker compose down -v # Stop + delete data volume
The named volume approach means updates are safe. Pull a new image, bring the stack down without -v, and bring it back up — your wallet data is untouched. The daemon's healthcheck will tell Docker when it's ready.
For debugging, the OpenAPI spec and interactive docs are available while the daemon is running:
# Download OpenAPI 3.0 spec
curl http://127.0.0.1:3100/doc -o openapi.json
# View interactive API reference in browser
open http://127.0.0.1:3100/reference
The interactive reference at /reference (built with Scalar) makes it straightforward to explore the 39 API routes without reading raw JSON.
Quick Start Summary
If you want to go from zero to a running, policy-protected AI wallet in the shortest path:
-
Clone and start:
git clone https://github.com/minhoyoo-iotrust/WAIaaS.git && cd WAIaaS && docker compose up -d -
Install the CLI:
npm install -g @waiaas/cli -
Create wallets and sessions:
waiaas quickset --mode mainnet -
Connect to Claude:
waiaas mcp setup --all -
Set spending policies via the REST API or Admin UI at
/adminbefore letting your agent operate on mainnet
The entire stack runs on your hardware. The push-relay handles mobile approvals. The policy engine enforces your rules. The keys never leave your server.
What's Next
The WAIaaS repository has detailed documentation on advanced policy configurations, the 15 integrated DeFi protocols, and the full SDK for building agents programmatically. If you're building something beyond a single-agent setup — multiple agents, multiple wallets, different policy profiles per agent — the multi-wallet MCP configuration and the TypeScript/Python SDKs are the natural next step.
The code is open source, the deployment is yours, and the keys stay where they belong.
→ GitHub: https://github.com/minhoyoo-iotrust/WAIaaS
→ Official site: https://waiaas.ai
Top comments (0)