Docker Auto-Provisioning Deep Dive: Zero-Config AI Wallet Deployment

Docker Auto-Provisioning Deep Dive: Zero-Config AI Wallet Deployment

Docker auto-provisioning for AI wallets sounds like it should require a weekend of configuration — but WAIaaS ships with a zero-config path that gets you from docker run to a fully operational, self-hosted AI wallet daemon in under a minute. If you've ever asked yourself whether you'd trust a third-party service with your AI agent's private keys, this post is for you. We're going to walk through exactly how WAIaaS's auto-provision system works, why self-hosting matters for AI agent wallets specifically, and how to go from nothing to a running wallet daemon with one command.

Why Self-Hosting an AI Wallet Actually Matters

There's a philosophical argument for self-hosting almost anything — privacy, control, no vendor lock-in. But with AI agent wallets, the stakes are higher than with, say, a self-hosted RSS reader.

An AI agent with a wallet has the ability to sign and broadcast real transactions. It can move funds, interact with DeFi protocols, pay for API calls via x402, trade on perpetual markets, and bridge assets across chains. That's not a read-only integration — it's an agent with real financial authority. When that agent lives inside a hosted service, you're trusting that service with:

Self-hosting doesn't just satisfy a philosophical preference. It means your keys never leave your infrastructure, your policy engine runs on hardware you control, and your agent's transaction history is yours. Think of it like running your own email server — except this one actually holds money, so the sovereignty argument isn't just ideological.

WAIaaS is open-source and designed from the ground up to run on your own hardware. The Docker image at ghcr.io/minhoyoo-iotrust/waiaas:latest is the canonical distribution, and the auto-provisioning system means you don't need to configure anything to get started.

What Auto-Provisioning Actually Does

When you pass WAIAAS_AUTO_PROVISION=true to the container, the Docker entrypoint generates a master password for you on first start and writes it to a recovery key file. This means you can spin up a fully secured daemon without ever typing a password manually — the system creates one, stores it somewhere safe, and you retrieve it after the fact.

Here's the full one-liner:

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 auto-generated master password
docker exec waiaas cat /data/recovery.key

A few things worth noting about that single command:

The port binding is 127.0.0.1:3100:3100 — localhost only, by default. The daemon doesn't expose itself to the network unless you deliberately change this. That's a sane default for a service that controls wallets.

The data volume is named, not a bind mount to a random path. Your keys and transaction history survive docker compose down and come back intact on restart.

The recovery key is in /data — the same volume you mounted. If you're running this in production, that volume should be encrypted at rest and backed up. The key itself is just a file, so treat it like one.

The entrypoint also supports Docker Secrets for production deployments, which we'll cover shortly.

The Full Docker Compose Setup

For anything beyond a quick test, docker compose is the right tool. The full docker-compose.yml that ships with WAIaaS looks like this:

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

The healthcheck matters if you're running this behind a reverse proxy or with a process supervisor that needs to know when the daemon is actually ready. It polls /health every 30 seconds and gives the container 10 seconds to warm up before starting checks.

The restart: unless-stopped policy means the daemon comes back after host reboots without you having to do anything. For a homelab or dedicated server, that's the behavior you want.

To get started from the repo:

git clone https://github.com/minhoyoo-iotrust/WAIaaS.git
cd WAIaaS
docker compose up -d

That's it. Three commands.

Hardening for Production: Docker Secrets

Environment variables are fine for development, but for a production self-hosted deployment, you don't want your master password sitting in shell history or visible in docker inspect. WAIaaS ships with a docker-compose.secrets.yml overlay specifically for this use case.

# 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

The secrets overlay injects the password as a Docker Secret rather than an environment variable. The file permission (chmod 600) ensures only root can read it on the host, and Docker Secrets mount it into the container at a path inaccessible from docker inspect output. For homelabbers running Portainer or Dockge, this is worth setting up even if it feels like extra steps — the master password controls wallet creation, session management, and policy configuration, so it's worth protecting.

Key Environment Variables You Should Know

The daemon is configured primarily through environment variables. The ones you're most likely to need:

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 deserve special mention. By default, WAIaaS will use public RPC endpoints, which are fine for experimentation but rate-limited for production. If you're running this seriously — especially if you have an agent executing DeFi actions across 18 supported networks — you'll want to plug in your own RPC URLs from providers like Alchemy, Helius, or your own node. This is another advantage of self-hosting: you control the entire stack, including where your RPC calls go.

From Running Container to Configured Wallet: The CLI Path

Once your container is up, you have two paths to initial configuration: the REST API directly, or the CLI. The CLI is faster for humans.

npm install -g @waiaas/cli
waiaas init                        # Create data directory + config.toml
waiaas start                       # Start daemon (sets master password on first run)
waiaas quickset --mode mainnet     # Create wallets + MCP sessions in one step

If you went the auto-provision route with Docker, you skip init and start and go straight to quickset. The quickset command creates wallets and MCP sessions in one step — it's designed for exactly this use case where you want to go from zero to an AI agent that can actually do things as fast as possible.

The CLI has 20 commands in total. The ones most relevant to initial Docker setup are init, start, quickset, status, stop, and wallet create. The backup create and restore commands are worth knowing about for ongoing maintenance of a self-hosted instance.

Verifying Your Setup with the REST API

Once the daemon is running, the REST API is available at http://127.0.0.1:3100. The interactive API reference lives at /reference and the OpenAPI 3.0 spec is at /doc:

# Download OpenAPI 3.0 spec
curl http://127.0.0.1:3100/doc -o openapi.json

# View interactive API reference
open http://127.0.0.1:3100/reference

There are 39 REST API route modules in total, covering wallets, transactions, policies, DeFi actions, NFTs, sessions, and more. But for a sanity check after initial deployment, the simplest test is creating a wallet and checking its balance.

First, create a wallet using your master password (retrieved from recovery.key if you used auto-provision):

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 an AI agent to use:

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>"}'

And verify the session works by checking balance:

curl http://127.0.0.1:3100/v1/wallet/balance \
  -H "Authorization: Bearer wai_sess_eyJhbGciOiJIUzI1NiJ9..."

If you get a balance response, your self-hosted AI wallet daemon is fully operational. Your keys are on your hardware, your transactions are in your database, and your policy engine is running under your control.

Setting Up Policies Before Letting Your Agent Loose

This is the step self-hosters sometimes skip because they're excited to get their agent running — don't skip it. WAIaaS uses a default-deny policy model, meaning certain transaction types are blocked unless explicitly allowed. Before you hand a session token to an AI agent, set at least a spending limit:

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
    }
  }'

There are 21 policy types available, organized around 4 security tiers: INSTANT (execute immediately), NOTIFY (execute and alert), DELAY (queue and wait before executing), and APPROVAL (require human sign-off). The spending limit policy shown above maps dollar thresholds to these tiers — transactions under $100 go through instantly, transactions between $100-$500 trigger a notification, transactions between $500-$2000 wait 15 minutes before executing (giving you time to cancel), and anything above $2000 requires your explicit approval.

The policy engine runs entirely on your server. There's no external service deciding whether your agent's transaction is legitimate — it's all local, deterministic rules that you wrote.

Common Docker Maintenance Commands

For ongoing management of your self-hosted instance:

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 distinction between down and down -v is important. Without -v, your wallet keys, transaction history, and policies survive the container being removed. With -v, everything is gone. Keep that in mind before running the second variant.

For backups, the CLI has a dedicated command:

waiaas backup create
waiaas backup list
waiaas restore

For a self-hosted setup that's actually managing funds, treat backups the way you'd treat a hardware wallet seed phrase backup — redundant, offline, and tested.

The Two-Image Architecture

WAIaaS actually ships two Docker images: the main waiaas daemon and a push-relay service. The push-relay handles the signing channel notifications — when your agent initiates a transaction that requires human approval, the push-relay is what delivers that approval request to you via push notification. For a minimal self-hosted setup, you can start with just the daemon. The push-relay becomes relevant when you want to approve transactions from your phone rather than having to be at your terminal.

Quick Start Summary

If you want to go from zero to running right now:

  1. Pull and start: docker compose up -d from the cloned repo
  2. Retrieve your password: docker exec waiaas cat /data/recovery.key
  3. Create a wallet: POST to /v1/wallets with your master password
  4. Set a spending policy: POST to /v1/policies before creating any agent sessions
  5. Create a session: POST to /v1/sessions and hand that token to your agent

The whole process takes under five minutes. Everything runs on your hardware, your keys never leave your server, and you have full audit visibility into everything your agent does.

What's Next

Once your daemon is running, the natural next step is connecting it to an AI agent via the MCP integration — WAIaaS provides 45 MCP tools that give Claude and other MCP-compatible agents direct wallet access within the policy guardrails you've set. From there, you can explore the DeFi integrations across 15 supported protocols, or set up the Admin Web UI at /admin for a visual dashboard of your wallets, sessions, and positions.

The full source is at https://github.com/minhoyoo-iotrust/WAIaaS and the project site is at https://waiaas.ai. If you're running this in a homelab or on a VPS and have questions, the GitHub issues and discussions are the right place — this is open-source software maintained in the open.

Your keys, your server, your rules.