DEV Community

Cover image for Securing Your Self-Hosted Wallet: Docker Secrets and Production Best Practices
Wallet Guy
Wallet Guy

Posted on

Securing Your Self-Hosted Wallet: Docker Secrets and Production Best Practices

Docker secrets and production hardening are critical when self-hosting wallet infrastructure for AI agents. Unlike hosted wallet services that handle security for you, self-hosted solutions put you in complete control — but also complete responsibility — for protecting private keys and managing access credentials.

Why Production Security Matters for Self-Hosted Wallets

When you self-host a wallet service, you're not just running another web application. You're managing cryptographic keys that control real assets, often with automated systems that could drain funds if compromised. The stakes are higher than a typical self-hosted service like Nextcloud or Plex.

Traditional deployment methods like hardcoded passwords in docker-compose.yml files or environment variables visible in process lists create unnecessary attack vectors. Production deployments need proper secrets management, non-root containers, and defense-in-depth security layers.

The Self-Hosted Wallet Security Challenge

WAIaaS addresses production security through multiple layers. The Docker image runs as non-root user (UID 1001), supports Docker Secrets for credential management, includes health checks for monitoring, and provides auto-provisioning for secure initial setup.

Docker Secrets Integration

The production deployment uses Docker Compose secrets overlay to keep sensitive credentials out of configuration files:

# Create secret files with proper permissions
mkdir -p secrets
echo "your-secure-master-password" > secrets/master_password.txt
echo "production-jwt-secret" > secrets/jwt_secret.txt
chmod 600 secrets/*.txt

# Deploy with secrets overlay
docker compose -f docker-compose.yml -f docker-compose.secrets.yml up -d
Enter fullscreen mode Exit fullscreen mode

The secrets overlay file (docker-compose.secrets.yml) mounts credential files into the container without exposing them in environment variables:

services:
  daemon:
    secrets:
      - master_password
      - jwt_secret
    environment:
      - WAIAAS_MASTER_PASSWORD_FILE=/run/secrets/master_password
      - WAIAAS_JWT_SECRET_FILE=/run/secrets/jwt_secret

secrets:
  master_password:
    file: ./secrets/master_password.txt
  jwt_secret:
    file: ./secrets/jwt_secret.txt
Enter fullscreen mode Exit fullscreen mode

Auto-Provisioning for Secure Bootstrapping

For initial deployment, WAIaaS supports auto-provisioning to generate secure credentials without manual password entry:

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
Enter fullscreen mode Exit fullscreen mode

The auto-provision feature generates a cryptographically secure master password and saves it to recovery.key. You can later harden this with a memorable password using the CLI:

# After initial setup, set a custom master password
waiaas set-master
# Then securely delete the recovery key
rm ~/.waiaas/recovery.key
Enter fullscreen mode Exit fullscreen mode

Network Security and Binding

The default Docker Compose configuration binds only to localhost (127.0.0.1:3100:3100), preventing external access. For production deployments with reverse proxy access, this provides an additional security layer:

ports:
  - "127.0.0.1:3100:3100"  # Localhost only
Enter fullscreen mode Exit fullscreen mode

If you need external access, use a reverse proxy like nginx or Traefik with TLS termination rather than exposing the wallet service directly.

Multi-Layer Authentication

WAIaaS implements 3 authentication methods with different security levels:

# masterAuth — system administration (wallet creation, policies)
curl -H "X-Master-Password: $(cat /run/secrets/master_password)" \
  http://localhost:3100/v1/wallets

# sessionAuth — AI agent operations (transactions, balance queries)
curl -H "Authorization: Bearer wai_sess_eyJhbGciOiJIUzI1NiJ9..." \
  http://localhost:3100/v1/wallet/balance

# ownerAuth — fund owner approval (transaction approval, kill switch)
curl -H "X-Owner-Signature: <ed25519-signature>" \
  -H "X-Owner-Message: <signed-message>" \
  http://localhost:3100/v1/transactions/<tx-id>/approve
Enter fullscreen mode Exit fullscreen mode

The session tokens use HS256 JWT signing with configurable TTL, maxRenewals, and absoluteLifetime limits. Master password uses Argon2id hashing. Owner auth requires cryptographic signatures from the wallet's private key.

Health Monitoring and Reliability

The Docker image includes built-in health checks for monitoring and restart policies:

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:3100/health"]
  interval: 30s
  timeout: 5s
  start_period: 10s
  retries: 3
restart: unless-stopped
Enter fullscreen mode Exit fullscreen mode

Combined with watchtower for automatic updates:

services:
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    command: --interval 3600 --cleanup
Enter fullscreen mode Exit fullscreen mode

This ensures your wallet service stays updated with security patches while maintaining uptime.

Policy Engine for Defense-in-Depth

Beyond infrastructure security, WAIaaS implements application-level security through its policy engine with 21 policy types and 4 security tiers (INSTANT, NOTIFY, DELAY, APPROVAL):

# Create spending limits with escalating security
curl -X POST http://localhost:3100/v1/policies \
  -H 'Content-Type: application/json' \
  -H 'X-Master-Password: $(cat /run/secrets/master_password)' \
  -d '{
    "walletId": "<wallet-uuid>",
    "type": "SPENDING_LIMIT",
    "rules": {
      "instant_max_usd": 10,
      "notify_max_usd": 100,
      "delay_max_usd": 1000,
      "delay_seconds": 900,
      "daily_limit_usd": 5000
    }
  }'
Enter fullscreen mode Exit fullscreen mode

The default-deny policy model blocks transactions unless explicitly allowed through ALLOWED_TOKENS and CONTRACT_WHITELIST policies, preventing unauthorized asset transfers even if session tokens are compromised.

Quick Start: Production Docker Deployment

Here's how to deploy WAIaaS securely in production:

1. Clone and Prepare Secrets

git clone https://github.com/minhoyoo-iotrust/WAIaaS.git
cd WAIaaS
mkdir -p secrets
openssl rand -base64 32 > secrets/master_password.txt
openssl rand -base64 32 > secrets/jwt_secret.txt
chmod 600 secrets/*.txt
Enter fullscreen mode Exit fullscreen mode

2. Configure Environment

Create .env file for non-sensitive configuration:

WAIAAS_DAEMON_LOG_LEVEL=info
WAIAAS_RPC_ETHEREUM_MAINNET=https://ethereum.publicnode.com
WAIAAS_RPC_SOLANA_MAINNET=https://api.mainnet-beta.solana.com
Enter fullscreen mode Exit fullscreen mode

3. Deploy with Secrets

docker compose -f docker-compose.yml -f docker-compose.secrets.yml up -d
Enter fullscreen mode Exit fullscreen mode

4. Verify Health

curl http://localhost:3100/health
# Should return: {"status": "ok"}
Enter fullscreen mode Exit fullscreen mode

5. Create Wallets and Policies

# Create a trading wallet
curl -X POST http://localhost:3100/v1/wallets \
  -H "Content-Type: application/json" \
  -H "X-Master-Password: $(cat secrets/master_password.txt)" \
  -d '{"name": "production-trading", "chain": "ethereum", "environment": "mainnet"}'

# Set up spending limits
curl -X POST http://localhost:3100/v1/policies \
  -H "Content-Type: application/json" \
  -H "X-Master-Password: $(cat secrets/master_password.txt)" \
  -d '{
    "walletId": "<wallet-uuid>",
    "type": "SPENDING_LIMIT",
    "rules": {"instant_max_usd": 50, "daily_limit_usd": 1000}
  }'
Enter fullscreen mode Exit fullscreen mode

The combination of Docker Secrets, non-root execution, localhost binding, health monitoring, and policy enforcement creates multiple security layers that protect your self-hosted wallet infrastructure from common attack vectors while maintaining the control and privacy benefits of running your own wallet service.

For AI agents that need programmatic access, the session authentication system provides secure, time-limited access tokens that can execute transactions within policy boundaries without exposing the master credentials or private keys.

Ready to deploy your own secure wallet infrastructure? Check out the WAIaaS GitHub repository for complete deployment examples, or visit waiaas.ai for additional documentation and community resources.

What's Next

Once you have your production deployment running, explore the policy configuration options to fine-tune security for your specific use case. The 21 policy types provide granular control over everything from spending limits to DeFi protocol access, letting you balance automation with security based on your risk tolerance.

Top comments (0)