Self-Updating Crypto Infrastructure: Watchtower + GHCR for AI Agent Wallets
Self-hosted wallet infrastructure for AI agents sounds like a weekend project that ends in tears — until you realize one Docker command is genuinely all it takes to get started. But getting it running is only half the battle. The harder question is: how do you keep it updated without babysitting a server? That's where Watchtower and GitHub Container Registry (GHCR) come in, and it's a combination worth understanding if you care about running your own infrastructure.
Why Self-Hosting Your AI Agent's Wallet Actually Matters
Would you trust a third party with your AI agent's private keys?
That's not a rhetorical scare tactic — it's a genuine architectural question that comes up the moment you start building AI agents that need to move money. When you hand wallet custody to a hosted service, you're also handing over your transaction history, your rate limits, your uptime dependency, and in the worst case, your keys themselves.
The self-hosted philosophy here is familiar to anyone who runs their own email server, Nextcloud instance, or Home Assistant setup: you trade some operational overhead for complete sovereignty. Your keys live on your hardware. Your transaction data doesn't leave your network. You set the rules.
What makes WAIaaS compelling for this crowd specifically is that it isn't just a wallet — it's a full Wallet-as-a-Service daemon that an AI agent can call via REST API or MCP tools. The agent gets a session token. The session token has policies. The policies define what the agent can and cannot do with your funds. All of that runs on your server, behind your firewall, without any third party in the loop.
But let's talk about the part that usually gets skipped in self-hosting guides: keeping the thing updated.
The Update Problem for Self-Hosted Services
Here's how update management usually goes for self-hosted projects:
- You deploy version X.
- Version X+1 comes out with a security fix.
- You find out three weeks later from a forum post.
- You SSH in, pull the new image, restart the service.
- Repeat forever.
For a homelab running Jellyfin, this is mildly annoying. For infrastructure that AI agents use to sign and broadcast transactions, stale software is a genuine risk. Security patches, bug fixes, and new protocol support all matter here.
WAIaaS publishes its Docker image to GHCR at ghcr.io/minhoyoo-iotrust/waiaas:latest. The :latest tag is the conventional signal that you want the most current stable build. Watchtower is the conventional tool for polling that tag and rolling updates automatically.
Together, they solve the update problem without requiring you to log into your server.
What WAIaaS Actually Runs
Before getting into the update mechanics, it helps to understand what you're deploying.
WAIaaS is a 15-package monorepo that ships as two Docker images: the main daemon and a push-relay service. The daemon is the piece most people care about — it's the REST API server that AI agents talk to.
That API has 39 route modules covering wallets, transactions, DeFi actions, NFTs, sessions, policies, and more. It supports 18 networks across EVM and Solana chain types. It has 15 DeFi protocol integrations including Jupiter, Aave v3, Lido, Jito, Hyperliquid, Polymarket, and others.
The transaction pipeline has 7 stages — validate, auth, policy, wait, execute, confirm — and a policy engine with 21 policy types and 4 security tiers (INSTANT, NOTIFY, DELAY, APPROVAL). Default-deny enforcement means if you haven't explicitly whitelisted a token or contract, the transaction gets blocked.
For AI agent integration, there are 45 MCP tools covering wallet operations, transfers, DeFi positions, NFTs, and x402 payments. The CLI has 20 commands for everything from quickstart to backup create to mcp setup.
This is not a toy. Keeping it updated matters.
Getting It Running: One Docker Command
The fastest path to a running instance:
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
The WAIAAS_AUTO_PROVISION=true flag tells the entrypoint to generate a master password on first start and write it to /data/recovery.key. You retrieve it once, store it somewhere safe, and the daemon is ready.
The port binding 127.0.0.1:3100:3100 is intentional — it keeps the API localhost-only by default, so you're not accidentally exposing wallet infrastructure to the internet.
For anything beyond a quick test, Docker Compose gives you a cleaner setup:
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 compose file:
-
restart: unless-stoppedmeans the daemon survives reboots. - The healthcheck polls
/healthevery 30 seconds, so you'll know if something goes wrong. - Data lives in a named volume, so
docker compose downdoesn't wipe your wallets. Onlydocker compose down -vdoes.
Production Secrets: Not Just Environment Variables
If you're running this seriously, hardcoded environment variables in compose files aren't the right approach for sensitive values. WAIaaS ships with a Docker Secrets overlay pattern via docker-compose.secrets.yml.
# 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
Secret files are mounted into the container at runtime rather than baked into environment variables that might show up in docker inspect or process listings. This is the right approach for production deployments, especially on shared hardware.
Adding Watchtower for Automatic Updates
Watchtower is a container that watches your other containers and restarts them when their upstream image is updated. It works by periodically checking the registry for newer digests matching the tag you're tracking.
Adding it to your compose setup is straightforward — here's the concept in a standalone docker run to keep things clear:
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
--interval 86400 \
waiaas-daemon
This tells Watchtower to check once per day (--interval 86400 seconds) and only watch the waiaas-daemon container. If a new image is published to ghcr.io/minhoyoo-iotrust/waiaas:latest, Watchtower pulls it, stops the old container, and starts a new one with the same configuration.
Because the wallet data lives in a named volume (waiaas-data:/data), it persists across container restarts. The new container picks up exactly where the old one left off.
A few practical notes for self-hosters:
Schedule updates during low-traffic windows. If your AI agents are actively trading, a restart in the middle of a transaction pipeline isn't ideal. Watchtower supports cron-style scheduling with --schedule if you want updates to happen at 3am instead of randomly throughout the day.
Consider update notifications. Watchtower can post to Slack, email, or other channels when it performs an update. For infrastructure you care about, knowing when an update happened is useful for debugging if something changes behavior.
Test before enabling auto-update in production. Run a staging instance that auto-updates, verify it works, then roll to production. Named volumes make this easy because staging and production can share nothing except the image.
The CLI Path: More Control, Less Magic
If automatic updates feel like too much magic for your taste, the CLI gives you explicit control:
npm install -g @waiaas/cli
waiaas init
waiaas start
waiaas update
The waiaas update command is one of the 20 CLI commands built into the WAIaaS CLI. It's the manual equivalent of what Watchtower does automatically — pull the latest image, restart the daemon. You run it when you want to, not on a schedule.
This is the right approach if you're running WAIaaS on hardware where unattended restarts could cause problems, or if you want to read changelogs before updating.
Setting Up Your First Wallet and Agent Session
Once the daemon is running, the quickstart flow is three more commands:
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
quickset creates wallets and sessions, then prints the MCP configuration JSON you need to paste into Claude Desktop (or whatever AI agent framework you're using). If you want to skip copy-pasting:
waiaas mcp setup --all # Auto-register all wallets with Claude Desktop
After that, your AI agent has a session token, and you control what it can do via policies. For example, setting 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
}
}'
This creates a four-tier policy: under $100 executes immediately, $100-500 sends you a notification, $500-2000 queues for 15 minutes (cancellable), and over $2000 requires your explicit approval. The agent can't override these — they're enforced server-side in the transaction pipeline before any signing happens.
The Self-Hosting Philosophy in Practice
Running your own wallet infrastructure is the crypto equivalent of running your own email server — the comparison gets made a lot because it's accurate. Both give you control over sensitive data. Both require you to think about uptime, updates, and backups. Both are more practical than they used to be.
The backup story matters here too. The CLI includes backup create, backup list, backup inspect, and restore commands. Your wallet data, session configuration, and policies are all in the named volume. Back it up. The waiaas backup create command exists precisely so you don't have to figure out the right tar incantation to grab the right files.
For the privacy-conscious: all of this runs on your hardware, on your network. The transaction data that flows through your WAIaaS instance — which agents are doing what, when, to which addresses — stays local. If you're building agents that handle sensitive financial operations, that's not a minor consideration.
The three-layer security model (session auth → time delay and approval → monitoring and kill switch) works because all three layers run locally. WalletConnect integration lets you approve transactions from your phone. The kill switch is yours to pull, not a hosted service's.
Quick Start Summary
-
Deploy:
docker compose up -dfrom the cloned repo, ordocker runwith the image from GHCR -
Auto-provision: Set
WAIAAS_AUTO_PROVISION=true, retrieve the master password from/data/recovery.key -
Add Watchtower: Point it at
waiaas-daemonwith a daily check interval -
Create wallets and sessions:
waiaas quickset --mode mainnet - Set policies: Define spending limits and whitelists via the REST API or Admin UI before handing session tokens to agents
The OpenAPI spec and interactive docs are available at http://127.0.0.1:3100/doc and http://127.0.0.1:3100/reference once you're running.
What's Next
The infrastructure side of self-hosting WAIaaS is genuinely approachable — the harder and more interesting questions are around policy design (which of the 21 policy types you need, and how tight to set the tiers) and agent integration (MCP vs. SDK vs. direct REST). Both are worth spending time on before your agents start moving real funds. The GitHub repository has the full source and documentation, and waiaas.ai covers the broader architecture. Start with WAIAAS_AUTO_PROVISION=true on a testnet wallet, run a few transactions through the pipeline, watch the logs — you'll get a feel for how the pieces fit together before anything is at stake.
Top comments (0)