Self-Hosted Crypto Wallet Reliability: Docker Healthcheck and Auto-Recovery
Running a self-hosted crypto wallet for your AI agents means you own the infrastructure — and that ownership comes with a responsibility most tutorials skip entirely: what happens when your Docker container quietly dies at 2am while your agent is mid-trade? This post walks through how WAIaaS handles uptime, healthchecks, and recovery so your self-hosted setup is actually reliable, not just theoretically in control.
Why Self-Hosting Matters (and Why Reliability Is the Hard Part)
The case for self-hosting your AI agent's wallet infrastructure is straightforward: your private keys never leave your server, there are no third-party rate limits throttling your agent's transactions, and no hosted service can freeze your account, change their API, or shut down without warning. It's the crypto equivalent of running your own email server — except WAIaaS makes the operational side considerably more practical than Postfix ever was.
But sovereignty comes with a catch. When you depend on a hosted wallet service, uptime is someone else's problem. When you self-host, a crashed container means your AI agent is sitting with zero transaction capability until you notice. For agents running DeFi strategies, monitoring incoming deposits, or responding to x402 payment requests, that downtime window is a real cost. This is why the operational details — healthchecks, auto-restart, secret management, and recovery keys — matter as much as the initial setup.
What WAIaaS Ships With Out of the Box
WAIaaS is distributed as a Docker image (ghcr.io/waiaas/waiaas:latest) with two Docker images in total: the main daemon and a push-relay for notification delivery. The default port binding is 127.0.0.1:3100:3100, which keeps the API local by default — a sensible starting position for a service holding wallet credentials.
The official Docker Compose configuration ships with a healthcheck already wired in:
services:
daemon:
image: ghcr.io/waiaas/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
Three things in this compose file are doing a lot of work that's easy to overlook.
restart: unless-stopped means Docker will automatically restart the container after a crash, an OOM kill, or a host reboot — without any additional process manager. You don't need systemd wrappers or a separate watchdog. As long as Docker is running, WAIaaS comes back.
The healthcheck polls http://localhost:3100/health every 30 seconds. After 3 consecutive failures the container is marked unhealthy. This doesn't restart the container on its own (that's what restart: unless-stopped handles), but it makes the health state visible to Docker tooling, orchestrators, and your own monitoring scripts. If you're running Portainer, Watchtower, or a simple cron that checks docker ps, the unhealthy status surfaces immediately rather than leaving you with a process that's technically running but silently broken.
Named volumes (waiaas-data) mean your wallet data, session tokens, and configuration survive a docker compose down and come back intact on docker compose up -d. This is the difference between "self-hosted with persistence" and "self-hosted with amnesia." Destroying the container does not destroy your wallets.
Getting Started: From Zero to Running in One Command
If you haven't set WAIaaS up yet, the fastest path is:
git clone https://github.com/waiaas/WAIaaS.git
cd WAIaaS
docker compose up -d
That's the complete deployment. The daemon starts, the healthcheck activates, and the API is available at http://127.0.0.1:3100.
For a fully hands-off first run — useful for automated provisioning or headless servers — the entrypoint supports auto-provision mode:
docker run -d \
--name waiaas \
-p 127.0.0.1:3100:3100 \
-v waiaas-data:/data \
-e WAIAAS_AUTO_PROVISION=true \
ghcr.io/waiaas/waiaas:latest
# Retrieve 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 start and write it to /data/recovery.key. You don't interact with a password prompt — the container just starts. Retrieve the key once, store it somewhere safe offline, and then harden it later with waiaas set-master when you're ready.
The auto-provision pattern is genuinely useful for homelab setups where you're deploying via Ansible, a git push hook, or any automation that can't handle interactive prompts.
Secrets Management for Production
The compose file approach above stores your master password in an environment variable or .env file, which is fine for local development. For a production self-hosted setup — a VPS, a dedicated homelab machine, anything that might be accessed by others — WAIaaS ships with a secrets overlay specifically for Docker Secrets:
# 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 docker-compose.secrets.yml overlay configures Docker Secrets, which mount credential files into the container via an in-memory tmpfs rather than environment variables. This means the master password doesn't appear in docker inspect output, isn't logged, and isn't visible in process environment dumps. For a service holding private keys, that's a meaningful security improvement over a plain .env file.
The entrypoint script handles reading from Docker Secrets automatically — you don't need to change application code.
Key Environment Variables Worth Knowing
When you're tuning your self-hosted deployment, these are the variables that matter most:
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 attention. By default WAIaaS will use public RPC nodes, which are fine for getting started but come with rate limits and reliability concerns for production agent workloads. Pointing to your own RPC node (or a paid endpoint you control) is the self-hosting philosophy applied all the way down: your keys, your RPC, your rules.
WAIAAS_DAEMON_HOSTNAME=0.0.0.0 combined with a firewall rule or reverse proxy is the standard pattern for exposing the API beyond localhost — for example, if your AI agent is running on a different machine than the WAIaaS daemon.
Verifying Your Setup Is Actually Healthy
After deployment, confirm the container is running and healthy:
docker compose logs -f # Follow logs in real time
Then test the API directly:
curl http://127.0.0.1:3100/health
A healthy daemon responds immediately. If you want to go further and verify the full stack — authentication, wallet creation, balance checks — the OpenAPI spec is available at http://127.0.0.1:3100/doc and the interactive Scalar API reference UI is at http://127.0.0.1:3100/reference. The reference UI lets you make live API calls against your running instance, which is the fastest way to sanity-check a fresh deployment without writing any code.
# 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
Creating Your First Wallet After Recovery
One thing worth testing before you need it: verify that your setup actually survives a container restart with data intact. Stop the container, bring it back up, and confirm your wallets are still there.
docker compose down # Stop (data preserved in named volume)
docker compose up -d # Restart
Then verify by checking a wallet's balance using the session token you created before the restart:
curl http://127.0.0.1:3100/v1/wallet/balance \
-H "Authorization: Bearer wai_sess_eyJhbGciOiJIUzI1NiJ9..."
If the balance comes back correctly, your persistence layer is working. If you get an authentication error, the session may have expired — create a new one with your master password. The wallet itself and its private keys are safe in the named volume.
For a brand-new setup creating your first wallet:
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"}'
The Three-Auth Model and Why It Matters for Self-Hosters
WAIaaS uses three distinct authentication methods, and understanding the separation is important for operating it reliably:
-
masterAuth (
X-Master-Password) — system administrator level. Creates wallets, manages sessions, configures policies. You use this; your AI agent does not. -
sessionAuth (
Authorization: Bearer wai_sess_...) — what your AI agent holds. Can send transactions, check balances, execute DeFi actions. Scoped and revocable. - ownerAuth (signature-based) — fund owner level for approving transactions that exceed policy thresholds or using the kill switch.
For self-hosters, this separation is the core of the security model. Your agent's session token being compromised doesn't expose your master password or your ability to approve or block transactions. The policy engine — with its 21 policy types and 4 security tiers (INSTANT, NOTIFY, DELAY, APPROVAL) — enforces default-deny: transactions are blocked unless explicitly permitted by policy. Even a fully autonomous agent can't spend beyond the limits you've set.
Monitoring Common Docker Commands
For day-to-day operation:
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 (destructive — deletes wallets)
That last command deserves a warning in bold: docker compose down -v deletes the named volume. This is the one command that actually destroys wallet data. Don't run it unless you mean to wipe everything.
What's Next
WAIaaS is open source and available on GitHub at https://github.com/waiaas/WAIaaS — you can inspect every line of code that handles your keys, which is exactly the kind of transparency self-hosters should expect from infrastructure this sensitive. For documentation, the official site at https://waiaas.ai covers the full feature set including the policy engine, MCP integration for Claude and other AI frameworks, and the TypeScript and Python SDKs. If you're running a serious agent workload, the next step after getting the daemon stable is locking it down with spending limits, token whitelists, and approval thresholds — your agent gets autonomy within the boundaries you define, and nothing outside them.
Top comments (0)