Deployment Guide
Deployment Guide
This guide covers two deployment methods for WAIaaS: npm global install (recommended for development and single-host setups) and Docker Compose (recommended for production).
Prerequisites
| Requirement | npm Install | Docker |
|---|---|---|
| Node.js 22 LTS | Required | - |
| Docker Engine 24+ | - | Required |
| Docker Compose v2 | - | Required |
| 2 GB RAM minimum | Required | Required |
Option A: npm Global Install
1. Install the CLI
npm install -g @waiaas/cli
2. Initialize
Auto-provision (recommended for AI agents -- no human interaction):
waiaas init --auto-provision
This creates the data directory at ~/.waiaas/ with:
config.toml-- default configuration with auto-generated master password hashrecovery.key-- plaintext master password for autonomous accesskeystore/-- encrypted key storage (sodium-native guarded memory)data/waiaas.db-- SQLite database
Manual (human-guided password setup):
waiaas init
You will be prompted to set a master password. This password protects all wallet private keys via Argon2id key derivation. Store it securely -- it cannot be recovered.
3. Start the Daemon
waiaas start
The daemon starts at http://127.0.0.1:3100 by default. If initialized manually, you will be prompted for the master password. If auto-provisioned, no prompt is needed.
4. Verify
waiaas status
Or:
curl http://127.0.0.1:3100/health
Expected response:
{
"status": "ok",
"version": "1.8.0",
"schemaVersion": 16,
"uptime": 42,
"timestamp": 1771300000
}
5. Stop
waiaas stop
6. Update
# Recommended: built-in update command (7-step process with backup)
waiaas update
# Alternative: manual npm update
npm install -g @waiaas/cli@latest
The waiaas update command checks for new versions, creates a backup, downloads the update, runs database migrations, and restarts the daemon.
Data Directory Structure
~/.waiaas/
config.toml # Configuration file
data/
waiaas.db # SQLite database
waiaas.db-wal # WAL journal
keystore/
*.enc # Encrypted private keys
tokens/ # MCP session token files
backups/ # Automatic backup archives
Option B: Docker Compose
1. Create Project Directory
mkdir waiaas && cd waiaas
2. Create docker-compose.yml
services:
daemon:
image: ghcr.io/minho-yoo/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
3. Configure Environment
Create a .env file with your settings:
With auto-provision (no password hash needed):
# Auto-provision: generates master password on first start
WAIAAS_AUTO_PROVISION=true
# Optional: RPC endpoints (or configure later via Admin Settings)
WAIAAS_RPC_SOLANA_MAINNET=https://api.mainnet-beta.solana.com
WAIAAS_RPC_SOLANA_DEVNET=https://api.devnet.solana.com
# WAIAAS_RPC_EVM_ETHEREUM_MAINNET=https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY
# Optional: Daemon settings
WAIAAS_DAEMON_PORT=3100
WAIAAS_DAEMON_LOG_LEVEL=info
With pre-set password hash:
# Required: Master password hash (Argon2id)
# Generate with: npx @waiaas/cli hash-password
WAIAAS_SECURITY_MASTER_PASSWORD_HASH=$argon2id$v=19$m=65536,t=3,p=4$...
# Optional: RPC endpoints (or configure later via Admin Settings)
WAIAAS_RPC_SOLANA_MAINNET=https://api.mainnet-beta.solana.com
WAIAAS_RPC_SOLANA_DEVNET=https://api.devnet.solana.com
# WAIAAS_RPC_EVM_ETHEREUM_MAINNET=https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY
# Optional: Daemon settings
WAIAAS_DAEMON_PORT=3100
WAIAAS_DAEMON_LOG_LEVEL=info
# Optional: Notifications (or configure later via Admin Settings)
WAIAAS_NOTIFICATIONS_ENABLED=true
WAIAAS_NOTIFICATIONS_TELEGRAM_BOT_TOKEN=123456:ABC-DEF...
WAIAAS_NOTIFICATIONS_TELEGRAM_CHAT_ID=987654321
4. Using Docker Secrets (Recommended for Production)
For sensitive values, use Docker secrets instead of environment variables. Create secret files:
mkdir -p secrets
echo "your_master_password" > secrets/master_password.txt
chmod 600 secrets/master_password.txt
# Optional: Telegram bot token
echo "your_bot_token" > secrets/telegram_bot_token.txt
chmod 600 secrets/telegram_bot_token.txt
Create docker-compose.secrets.yml:
services:
daemon:
secrets:
- waiaas_master_password
- waiaas_telegram_bot_token
environment:
- WAIAAS_MASTER_PASSWORD_FILE=/run/secrets/waiaas_master_password
- WAIAAS_TELEGRAM_BOT_TOKEN_FILE=/run/secrets/waiaas_telegram_bot_token
secrets:
waiaas_master_password:
file: ./secrets/master_password.txt
waiaas_telegram_bot_token:
file: ./secrets/telegram_bot_token.txt
Start with secrets:
docker compose -f docker-compose.yml -f docker-compose.secrets.yml up -d
5. Start
docker compose up -d
6. View Logs
docker compose logs -f waiaas
7. Update
docker compose pull
docker compose up -d
Database migrations run automatically on startup. The Docker image supports Watchtower auto-update via the com.centurylinklabs.watchtower.enable=true label.
Docker Auto-Provision
For fully autonomous Docker deployments (no pre-set password), add WAIAAS_AUTO_PROVISION=true to your environment:
services:
daemon:
image: ghcr.io/minho-yoo/waiaas:latest
environment:
- WAIAAS_AUTO_PROVISION=true
- WAIAAS_DATA_DIR=/data
- WAIAAS_DAEMON_HOSTNAME=0.0.0.0
volumes:
- waiaas-data:/data
ports:
- "127.0.0.1:3100:3100"
On first start (when /data/config.toml does not exist), the entrypoint automatically runs waiaas init --auto-provision. The generated master password is saved to /data/recovery.key.
Retrieve the recovery key after first start:
docker compose exec daemon cat /data/recovery.key
After retrieving, harden the password with waiaas set-master and delete the recovery key.
Docker Image Details
- Base image:
node:22-slim - Runs as: non-root user
waiaas(UID 1001) - Data volume:
/data(database, keystore, config) - Exposed port: 3100
- Health check:
curl -f http://localhost:3100/healthevery 30s
Configuration
config.toml
The configuration file is located at ~/.waiaas/config.toml (npm install) or mounted into the container at /data/config.toml (Docker). All sections are flat (no nesting allowed).
[daemon]
port = 3100 # Listening port
hostname = "127.0.0.1" # Bind address (keep localhost for security)
log_level = "info" # trace | debug | info | warn | error
admin_ui = true # Enable Admin Web UI
admin_timeout = 900 # Admin session timeout (seconds)
[rpc]
solana_mainnet = "https://api.mainnet-beta.solana.com"
solana_devnet = "https://api.devnet.solana.com"
# ethereum_mainnet = "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY"
# ethereum_sepolia = "https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY"
[security]
session_ttl = 86400 # Session lifetime (seconds, default 24h)
max_sessions_per_wallet = 5 # Max sessions per wallet
policy_defaults_delay_seconds = 300 # DELAY tier wait time (seconds)
policy_defaults_approval_timeout = 3600 # APPROVAL tier timeout (seconds)
[keystore]
argon2_memory = 65536 # Argon2id memory (KB)
argon2_time = 3 # Argon2id iterations
argon2_parallelism = 4 # Argon2id parallelism
[database]
path = "data/waiaas.db" # SQLite file path (relative to data dir)
[walletconnect]
project_id = "" # Reown Cloud project ID (optional)
[notifications]
enabled = false
telegram_bot_token = ""
telegram_chat_id = ""
discord_webhook_url = ""
ntfy_topic = ""
ntfy_server = "https://ntfy.sh"
Environment Variable Override
Any config value can be overridden with environment variables using the pattern WAIAAS_{SECTION}_{KEY}:
WAIAAS_DAEMON_PORT=4000
WAIAAS_DAEMON_LOG_LEVEL=debug
WAIAAS_RPC_SOLANA_MAINNET="https://my-rpc.example.com"
WAIAAS_SECURITY_SESSION_TTL=43200
Admin Settings (Preferred for Runtime Configuration)
Prefer Admin Settings over config.toml. Most settings can be changed at runtime through the Admin Settings API, Admin UI, or CLI commands without restarting the daemon:
# View all current settings
curl http://127.0.0.1:3100/v1/admin/settings \
-H "X-Master-Password: <password>"
# Update settings (hot-reload, no restart needed)
curl -X PUT http://127.0.0.1:3100/v1/admin/settings \
-H "X-Master-Password: <password>" \
-H "Content-Type: application/json" \
-d '{"settings":[{"key": "display.currency", "value": "KRW"}]}'
Admin Settings covers: notifications, RPC endpoints, security parameters, display currency, monitoring, autostop, signing SDK, WalletConnect, oracle, and daemon log level.
Only infrastructure settings (port, hostname, database path, master_password_hash) require a daemon restart and remain config.toml-only. For everything else, use Admin Settings, CLI commands, or the Admin UI.
Post-Installation
1. Harden Master Password (Auto-Provision Only)
If you used --auto-provision or WAIAAS_AUTO_PROVISION=true, change the auto-generated password to a strong human-chosen password:
waiaas set-master
Or via REST API:
curl -s -X PUT http://127.0.0.1:3100/v1/admin/master-password \
-H "Content-Type: application/json" \
-H "X-Master-Password: $(cat ~/.waiaas/recovery.key)" \
-d '{"newPassword": "<your-strong-password>"}'
After changing, delete the recovery key:
rm ~/.waiaas/recovery.key
2. Access Admin UI
Open your browser and navigate to:
http://127.0.0.1:3100/admin
Log in with your master password to access the dashboard, wallet management, session management, policy configuration, and notification settings.
3. Create Your First Wallet
curl -X POST http://127.0.0.1:3100/v1/wallets \
-H "Content-Type: application/json" \
-H "X-Master-Password: <your-master-password>" \
-d '{
"name": "my-wallet",
"chain": "solana",
"environment": "mainnet"
}'
Response:
{
"id": "01234567-89ab-cdef-0123-456789abcdef",
"name": "my-wallet",
"chain": "solana",
"network": "mainnet",
"environment": "mainnet",
"publicKey": "ABC123...",
"status": "ACTIVE",
"ownerState": "NONE"
}
4. Create a Session Token
curl -X POST http://127.0.0.1:3100/v1/sessions \
-H "Content-Type: application/json" \
-H "X-Master-Password: <your-master-password>" \
-d '{"walletId": "<wallet-id-from-above>"}'
The response includes a token field (wai_sess_...) that AI agents use to authenticate.
5. Set Up MCP (for AI Agents)
# Automatic: registers MCP server with Claude Desktop
waiaas mcp setup
# For a specific wallet
waiaas mcp setup --wallet <wallet-id>
# For all wallets
waiaas mcp setup --all
This automatically creates session tokens and configures Claude Desktop's MCP server settings.
6. Install Skill Files (Optional)
Skill files teach AI agents how to interact with the WAIaaS API. They are plain Markdown files that can be included in the AI agent's context.
# List available skills
npx @waiaas/skills list
# Add a specific skill to your project
npx @waiaas/skills add wallet
# Add all skills
npx @waiaas/skills add all
This copies .skill.md files to your current directory. Include them in your AI agent's prompt or context window for API-aware conversations.
Notifications Setup
WAIaaS supports four notification channels: Telegram, Discord, ntfy, and Slack. Notifications fire on 8 event types including transaction execution, approval requests, and kill switch activation.
| Channel | Config Key | Setup |
|---|---|---|
| Telegram | telegram_bot_token + telegram_chat_id |
Create bot via @BotFather |
| Discord | discord_webhook_url |
Server Settings > Integrations > Webhooks |
| ntfy | ntfy_topic + ntfy_server |
Choose topic, subscribe via app |
| Slack | slack_webhook_url |
Create incoming webhook |
Via Admin Settings (Recommended)
Use the Admin Settings API for runtime configuration without editing config.toml:
# Configure Telegram notifications via Admin Settings
curl -s -X PUT http://127.0.0.1:3100/v1/admin/settings \
-H "Content-Type: application/json" \
-H "X-Master-Password: <password>" \
-d '{"settings":[
{"key":"notifications.telegram_bot_token","value":"<bot-token>"},
{"key":"notifications.telegram_chat_id","value":"<chat-id>"},
{"key":"notifications.enabled","value":"true"}
]}'
Or use the CLI:
waiaas notification setup --bot-token <TOKEN> --chat-id <ID> --test
Via Admin UI
Open http://127.0.0.1:3100/admin, navigate to Notifications, and configure channels through the visual interface.
Test Notifications
curl -X POST http://127.0.0.1:3100/v1/admin/notifications/test \
-H "X-Master-Password: <your-master-password>" \
-H "Content-Type: application/json" \
-d '{"channel": "telegram"}'
Security Checklist
Before running in production, verify these security settings:
- Bind to localhost only --
hostname = "127.0.0.1"(default). Never expose the daemon to the public internet. - Strong master password -- Use a password with high entropy. The master password protects all wallet private keys.
- Set up 2+ notification channels -- Ensure you receive alerts even if one channel fails. Set
min_channels = 2. - Configure spending policies -- Set SPENDING_LIMIT policies with appropriate tier thresholds for your use case.
- Register an Owner -- Set an owner address on each wallet to enable APPROVAL tier and Kill Switch recovery.
- Enable TLS via reverse proxy -- If accessed remotely, place behind nginx/Caddy with TLS. WAIaaS itself does not serve HTTPS.
- Restrict file permissions --
chmod 600on config.toml, keystore files, and Docker secret files. - Regular backups -- Use
waiaas backupor configure automatic backups. - Keep updated -- Enable Watchtower (Docker) or periodically run
waiaas update(npm).
Troubleshooting
Port Already in Use
Error: listen EADDRINUSE :::3100
Another process is using port 3100. Either stop it or change the port:
WAIAAS_DAEMON_PORT=3200 waiaas start
Permission Denied (Keystore)
Error: EACCES: permission denied, open '~/.waiaas/keystore/...'
Fix file ownership:
sudo chown -R $(whoami) ~/.waiaas/
chmod -R 700 ~/.waiaas/keystore/
Database Migration
Database migrations run automatically on daemon startup. If you see migration errors:
- Check the daemon logs for the specific migration version that failed.
- Ensure you are running the latest version of WAIaaS.
- Restore from backup if necessary:
waiaas restore --backup <path>.
The daemon tracks schema versions in the schema_version table. Current schema version: 16.
Docker: Container Exits Immediately
Check logs for the error:
docker compose logs waiaas
Common causes:
- Missing master password: use
WAIAAS_AUTO_PROVISION=truefor auto-provision, or setWAIAAS_MASTER_PASSWORD/ use Docker secrets. - Volume permission issues: the container runs as UID 1001. Ensure the data volume is accessible.
Admin UI Not Loading
- Verify
admin_ui = truein config.toml (default). - Check that you are accessing
http://127.0.0.1:3100/admin(not/admin/). - Clear browser cache if you recently upgraded.
RPC Connection Errors
Error: Failed to connect to Solana RPC
- Verify your RPC URL is correct and accessible.
- For mainnet, consider using a dedicated RPC provider (Alchemy, QuickNode, Helius) instead of the public endpoint.
- Test connectivity via Admin API:
POST /v1/admin/settings/test-rpc.
Related
- Architecture - System architecture overview
- Agent Self-Setup Guide - Automated daemon provisioning for agents
- Running WAIaaS Inside an Agent Docker Container - Docker sidecar deployment pattern