Openclaw · EN · Part 3

Ch 11 Deployment And Operations

11-ch-11-Deployment-and-Operations.md

第11章 Deployment and Operations

"The gap between development and production is where good ideas go to die." This observation holds especially true for AI assistants that must reliably handle twenty messaging channels, maintain state across sessions, and respond within seconds. You've built OpenClaw locally—it works on your machine, passes tests, and handles your Telegram and WhatsApp messages during development. Now you need it to run continuously, survive restarts, and behave predictably when you're not watching over it.

Production deployment isn't just "running it somewhere else." It's about visibility, recoverability, and operational discipline. When the Gateway crashes at 3 AM, you need logs that explain why. When an update introduces a breaking change, you need a rollback path that doesn't require forensic archaeology. When disk space fills up with session history, you need monitoring that alerts you before operations degrade.

OpenClaw supports three primary deployment strategies, each with different trade-offs:

  • npm global install: Simplest for single-machine deployments, gives you direct CLI access, but requires manual process management
  • Docker containers: Isolated runtime, reproducible builds, easier horizontal scaling, but adds container orchestration complexity
  • Building from source: Maximum customization, useful for development and testing, but requires ongoing maintenance

This chapter covers each approach, then dives into monitoring, logging, update management, and Docker-specific operations. We'll focus on what you need to know to keep OpenClaw running reliably in production.

Deployment Strategies

The right deployment strategy depends on your environment, scale requirements, and operational preferences. Let's examine each approach with production considerations.

npm Global Install Deployment

The simplest path to production is installing OpenClaw globally via npm:

# Install the latest published version
npm install -g openclaw@latest

# Or install a specific version for reproducibility
npm install -g [email protected]

This places the openclaw binary in your global npm bin directory (typically ~/Library/pnpm on macOS with pnpm, or /usr/local/bin with npm). The Gateway runs as a background process managed by launchd on macOS or systemd on Linux.

Starting the Gateway:

# Start the gateway in the background
openclaw gateway run --bind lan --port 18789

# Or run in daemon mode with auto-restart
openclaw gateway daemon start

Production considerations for npm deployment:

  1. Version pinning: Always specify explicit versions in production scripts. Using @latest can introduce breaking changes unexpectedly.
  2. Process management: Use openclaw gateway daemon start on macOS/Linux for automatic restart, or configure systemd/supervisord for more control.
  3. Log rotation: Gateway logs grow indefinitely. Configure logrotate or use the --log-file flag with rotation.
  4. User isolation: Run as a non-privileged user. The Gateway doesn't need root access after initial installation.

⚠️ 避坑指南: npm global installs share the same node_modules tree across all global packages. If another global package installs conflicting dependencies, OpenClaw may fail to start. Version pinning and regular testing of updates in a staging environment first helps avoid this.

Docker Container Deployment

Docker provides isolation and reproducibility at the cost of added complexity. OpenClaw's multi-stage Dockerfile produces a minimal runtime image without build tools or source code.

Building the image:

# Default build (bookworm base)
docker build -t openclaw:local .

# Slim variant (smaller image, fewer preinstalled tools)
docker build --build-arg OPENCLAW_VARIANT=slim -t openclaw:local .

# With optional extensions and system packages
docker build \
  --build-arg OPENCLAW_EXTENSIONS="diagnostics-otel" \
  --build-arg OPENCLAW_DOCKER_APT_PACKAGES="python3 wget" \
  -t openclaw:local .

Running with Docker Compose:

The repository provides a production-ready docker-compose.yml:

services:
  openclaw-gateway:
    image: ${OPENCLAW_IMAGE:-openclaw:local}
    environment:
      HOME: /home/node
      TERM: xterm-256color
      OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN:-}
      OPENCLAW_ALLOW_INSECURE_PRIVATE_WS: ${OPENCLAW_ALLOW_INSECURE_PRIVATE_WS:-}
      TZ: ${OPENCLAW_TZ:-UTC}
    volumes:
      - ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw
      - ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace
    ports:
      - "${OPENCLAW_GATEWAY_PORT:-18789}:18789"
      - "${OPENCLAW_BRIDGE_PORT:-18790}:18790"
    init: true
    restart: unless-stopped
    command: ["node", "dist/index.js", "gateway", "--bind", "${OPENCLAW_GATEWAY_BIND:-lan}", "--port", "18789"]
    healthcheck:
      test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:18789/healthz').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
      interval: 30s
      timeout: 5s
      retries: 5
      start_period: 20s

Production considerations for Docker deployment:

  1. Volume permissions: The container runs as the node user (uid 1000). Ensure bind-mounted directories are writable by this UID, or use the setup script's permission-fixing step.
  2. Networking: The default Gateway bind is loopback (127.0.0.1). With Docker bridge networking, this makes the Gateway unreachable from the host. Either use --network host or override OPENCLAW_GATEWAY_BIND=lan.
  3. Resource limits: Set memory and CPU limits in docker-compose to prevent container resource exhaustion from affecting the host.
  4. Image digest pinning: For reproducible deployments, pin images by SHA256 digest rather than tags.
# Example resource limits
services:
  openclaw-gateway:
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 2G
        reservations:
          cpus: '0.5'
          memory: 512M

🤿 深入底层: The Dockerfile uses a multi-stage build pattern. The build stage includes Bun for compilation, the runtime-assets stage prunes dev dependencies, and the final runtime stage copies only production artifacts. This reduces the final image size by ~60% compared to a single-stage build.

Building from Source

Building from source gives you maximum control but requires ongoing maintenance:

# Clone and build
git clone https://github.com/openclaw/openclaw.git
cd openclaw
pnpm install
pnpm build

# Run the built output
node dist/index.js gateway run

Production considerations for source builds:

  1. Reproducibility: Pin exact commit SHAs in your deployment scripts. main branch moves quickly.
  2. Build time: Builds take 3-5 minutes on modern hardware. Factor this into deployment pipelines.
  3. Dependencies: Source builds require Node.js 22+, pnpm, and platform-specific build tools (Xcode for macOS, various compilers for Linux).
  4. Testing: Always run pnpm test after building before deploying. The codebase has 3,500+ tests for a reason.

Deployment Architecture

Here's how the pieces fit together in a production deployment:

Rendering diagram...

This architecture separates concerns: clients connect via WebSocket, the Gateway manages state, and monitoring runs independently. The health check endpoints (/healthz for liveness, /readyz for readiness) allow orchestrators like Docker or Kubernetes to detect and respond to Gateway failures.

☕ 茶水间时间: The health check uses a Node.js one-liner instead of curl because the base Node image doesn't include curl. This design choice keeps the image smaller (~50MB savings) but requires the healthcheck to use fetch() via Node's built-in HTTP client.

Monitoring and Observability

Production systems require visibility. You can't fix what you can't see, and you can't improve what you don't measure. OpenClaw provides several mechanisms for monitoring Gateway health and behavior.

Health Checks

The Gateway exposes built-in health check endpoints:

# Liveness check: is the gateway process running?
curl http://localhost:18789/healthz

# Readiness check: is the gateway accepting requests?
curl http://localhost:18789/readyz

# With authentication
curl -H "X-Gateway-Token: your-token" http://localhost:18789/healthz

These endpoints return HTTP 200 when healthy and HTTP 503 when unhealthy. They're used by Docker's HEALTHCHECK directive and can be integrated with external monitoring systems.

What they check:

  • /healthz: Verifies the Gateway server is responding. Fails if the process is dead or the HTTP server is stuck.
  • /readyz: Verifies the Gateway can accept new WebSocket connections. Fails if at capacity or during shutdown.

Custom health checks:

# Check via CLI (respects configured auth)
openclaw health --token your-gateway-token

# Check from within a container
docker compose exec openclaw-gateway node dist/index.js health --token "$OPENCLAW_GATEWAY_TOKEN"

Metrics Collection

OpenClaw doesn't include a built-in metrics server, but it exposes operational data through several paths:

  1. Gateway status: openclaw gateway status shows running state, uptime, and connection counts
  2. Channel status: openclaw channels status shows per-channel connectivity
  3. Session listing: openclaw sessions list shows active sessions and their states

Example metrics collection script:

#!/bin/bash
# collect-metrics.sh - Gather Gateway metrics for monitoring

GATEWAY_TOKEN="${OPENCLAW_GATEWAY_TOKEN}"
GATEWAY_URL="${OPENCLAW_GATEWAY_URL:-http://localhost:18789}"

# Function to metric-safe output
sanitize_metric_name() {
  echo "$1" | tr '[:upper:]' '[:lower:]' | tr -cs '[:alnum:]' '_'
}

# Collect Gateway status
STATUS=$(openclaw gateway status --token "$GATEWAY_TOKEN" 2>/dev/null)
UPTIME=$(echo "$STATUS" | grep "Uptime" | awk '{print $2}')
CONNECTIONS=$(echo "$STATUS" | grep "Connections" | awk '{print $2}')

echo "openclaw_gateway_uptime_seconds $UPTIME"
echo "openclaw_gateway_connections $CONNECTIONS"

# Collect per-channel status
openclaw channels status --token "$GATEWAY_TOKEN" 2>/dev/null | \
while read -r channel status; do
  CHANNEL_METRIC=$(sanitize_metric_name "$channel")
  STATUS_CODE=0
  [[ "$status" == "connected" ]] && STATUS_CODE=1 || STATUS_CODE=0
  echo "openclaw_channel_up{channel=\"$CHANNEL_METRIC\"} $STATUS_CODE"
done

This script outputs Prometheus-style metrics that can be scraped by monitoring systems.

Log Aggregation

OpenClaw logs to stdout/stderr by default, making it compatible with container log drivers and log aggregation systems:

Docker log driver configuration:

services:
  openclaw-gateway:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

Sending logs to external systems:

# Example: Send to syslog
services:
  openclaw-gateway:
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://192.168.0.42:514"
        tag: "openclaw"

# Example: Send to Fluentd
services:
  openclaw-gateway:
    logging:
      driver: "fluentd"
      options:
        fluentd-address: "localhost:24224"
        tag: "openclaw.gateway"

macOS Unified Logging

On macOS, OpenClaw integrates with the unified logging system for structured, searchable logs:

# View recent OpenClaw logs
log show --predicate 'subsystem == "ai.openclaw"' --last 5m --info

# Stream logs in real-time
log stream --predicate 'subsystem == "ai.openclaw"' --level info

# Filter by category
log show --predicate 'subsystem == "ai.openclaw" AND category == "gateway"' --last 1h

clawlog.sh Tool

The scripts/clawlog.sh utility simplifies macOS log access:

# Show last 50 lines (default)
./scripts/clawlog.sh

# Follow logs in real-time
./scripts/clawlog.sh -f

# Show only errors
./scripts/clawlog.sh -e

# Show specific category
./scripts/clawlog.sh -c ServerManager

# Search for text
./scripts/clawlog.sh -s "failed to connect"

# Export to file
./scripts/clawlog.sh -l 1h -o /tmp/openclaw-logs.txt

The tool handles Apple's privacy redaction by using sudo to access full log details, which Apple otherwise hides for sensitive subsystems.

⚠️ 避坑指南: macOS unified logging has rate limits and may drop messages under high log volume. For production deployments, consider forwarding critical logs to an external aggregation system (syslog, Fluentd, or a SaaS logging service) to ensure nothing is lost.

Update Management

Software updates are a fact of life. OpenClaw provides several update mechanisms depending on your deployment method. The key principle is safe rollback: never deploy an update without a path back to the previous working state.

macOS Sparkle Update System

The macOS app uses Sparkle for automatic updates:

# Check for updates (via the app)
OpenClaw → Check for Updates...

# Manual update via CLI
openclaw update

Sparkle updates:

  1. Download the new version in the background
  2. Verify code signature
  3. Install on next app launch
  4. Keep the old version available for rollback

Rollback procedure:

# Sparkle keeps old versions in ~/Library/Caches/com.openclaw.OpenClaw
ls -la ~/Library/Caches/com.openclaw.OpenClaw/

# To rollback, quit the app and restore the previous version
killall OpenClaw
cp -r ~/Library/Caches/com.openclaw.OpenClaw/OpenClaw-2026.4.3.app /Applications/OpenClaw.app
open /Applications/OpenClaw.app

npm Version Updates

For npm installations, updates are manual:

# Check current version
openclaw --version

# Update to latest
npm update -g openclaw@latest

# Or install specific version
npm install -g [email protected]

# Verify update
openclaw --version

Safe update procedure:

#!/bin/bash
# safe-update.sh - Update OpenClaw with rollback path

CURRENT_VERSION=$(openclaw --version)
BACKUP_DIR="$HOME/.openclaw/backup/$(date +%Y%m%d-%H%M%S)"

echo "Current version: $CURRENT_VERSION"

# Create backup of config and state
mkdir -p "$BACKUP_DIR"
cp -r ~/.openclaw/config "$BACKUP_DIR/"
cp -r ~/.openclaw/agents "$BACKUP_DIR/"

# Update
npm update -g openclaw@latest
NEW_VERSION=$(openclaw --version)

echo "Updated to: $NEW_VERSION"

# Test gateway start
if openclaw gateway run --bind loopback --port 18790 --test; then
  echo "Update successful, backup at: $BACKUP_DIR"
  # Cleanup old backups (keep last 5)
  ls -dt ~/.openclaw/backup/*/ | tail -n +6 | xargs rm -rf
else
  echo "Update failed, rolling back..."
  npm install -g "openclaw@$CURRENT_VERSION"
  echo "Rolled back to: $CURRENT_VERSION"
  exit 1
fi

Safe Rollback Procedures

Rollback is your safety net. Design your deployment process with rollback in mind:

Docker rollback:

# Tag images before deployment
docker tag openclaw:2026.4.4 openclaw:production
docker tag openclaw:2026.4.4 openclaw:previous

# Deploy new version
docker build -t openclaw:2026.4.5 .
docker tag openclaw:2026.4.5 openclaw:production

# If issues occur, rollback
docker tag openclaw:previous openclaw:production
docker compose up -d --force-recreate

Source build rollback:

# Always keep the previous working commit
git tag working-$(date +%Y%m%d)
git push origin working-$(date +%Y%m%d)

# Deploy new version
git pull origin main
pnpm install && pnpm build

# If issues occur
git checkout working-20260320
pnpm install && pnpm build

Version Coordination

OpenClaw has multiple versioned components that must stay in sync:

ComponentLocationCoordination Method
CLI/npm packagepackage.jsonversion field
macOS appapps/macos/Sources/Info.plistCFBundleShortVersionString
iOS appapps/ios/Info.plistCFBundleShortVersionString
Android appapps/android/app/build.gradle.ktsversionName
Docsdocs/install/updating.mdPinned version

When releasing, update all locations simultaneously. The project provides a verification script:

# Check version alignment
pnpm version:check

# Bump all versions together
pnpm version:patch  # 2026.4.4 → 2026.4.5
pnpm version:minor  # 2026.4.4 → 2026.5.0
pnpm version:major  # 2026.4.4 → 2027.0.0

🤿 深入底层: Version misalignment causes subtle bugs. For example, if the CLI is at 2026.4.5 but the macOS app is still at 2026.4.4, the app may try to use Gateway protocol features that the older CLI doesn't support, causing connection failures. Always verify version alignment after updates.

Docker and Container Operations

Docker deployment adds a layer of indirection but provides significant operational benefits: isolation, resource controls, and easy rollback. Let's dive deeper into Docker-specific considerations.

Dockerfile Configuration

The multi-stage Dockerfile optimizes for security and size:

# Build stage with Bun for compilation
FROM node:24-bookworm AS build
RUN curl -fsSL https://bun.sh/install | bash
ENV PATH="/root/.bun/bin:${PATH}"
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm build:docker
RUN pnpm ui:build

# Runtime stage without build tools
FROM node:24-bookworm-slim AS runtime
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends \
    procps hostname curl git lsof openssl
COPY --from=build --chown=node:node /app/dist ./dist
COPY --from=build --chown=node:node /app/node_modules ./node_modules
USER node
HEALTHCHECK CMD node -e "fetch('http://127.0.0.1:18789/healthz')..."
CMD ["node", "openclaw.mjs", "gateway", "--allow-unconfigured"]

Key security features:

  1. Non-root user: Runs as node (uid 1000) to prevent container escape via root privileges
  2. Minimal base: Uses bookworm-slim to reduce attack surface
  3. No build tools: Strips Bun, compilers, and dev dependencies from runtime image
  4. SHA256 pinning: Base image digests are pinned for reproducible builds

docker-compose Setup

The provided docker-compose.yml is production-ready but requires configuration:

Environment variables:

# .env file
OPENCLAW_CONFIG_DIR=/data/openclaw/config
OPENCLAW_WORKSPACE_DIR=/data/openclaw/workspace
OPENCLAW_GATEWAY_PORT=18789
OPENCLAW_GATEWAY_BIND=lan
OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32)
OPENCLAW_IMAGE=openclaw:local
OPENCLAW_TZ=America/New_York

Automated setup script:

# The scripts/docker/setup.sh handles:
# - Image building or pulling
# - Directory creation and permissions
# - Config file generation
# - Initial onboarding
# - Gateway startup

./scripts/docker/setup.sh

The setup script is idempotent—safe to run multiple times.

Volume Management

Volumes persist state outside the container lifecycle:

volumes:
  - ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw
  - ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace

Volume considerations:

  1. Permissions: Container runs as uid 1000. Ensure host directories are writable by this UID.
  2. Backup: Use Docker volume backup commands or direct filesystem backups:
    # Backup via tar
    tar -czf openclaw-backup-$(date +%Y%m%d).tar.gz /data/openclaw
    
    # Restore
    tar -xzf openclaw-backup-20260320.tar.gz -C /
    
  3. Migration: To migrate volumes between hosts, use docker-volume-copy or similar tools.

Networking

Docker networking affects how clients reach the Gateway:

Bridge networking (default):

ports:
  - "18789:18789"  # HOST:CONTAINER mapping

With bridge networking, clients connect via host-ip:18789. The Gateway must bind to 0.0.0.0 (lan mode) for this to work.

Host networking:

services:
  openclaw-gateway:
    network_mode: "host"

With host networking, the container shares the host's network stack. Clients connect via localhost:18789. This bypasses Docker's network overhead but reduces isolation.

Tailscale integration:

For remote access, run Tailscale on the host and use the host's Tailscale IP:

# Get Tailscale IP
tailscale ip -4

# Connect clients via TAILSCALE_IP:18789

Container-Specific Considerations

Sandbox support:

The Gateway can spawn sandboxed containers for agent execution. This requires Docker-in-Docker:

# Build with Docker CLI
docker build --build-arg OPENCLAW_INSTALL_DOCKER_CLI=1 -t openclaw:local .

# Mount Docker socket
docker run -v /var/run/docker.sock:/var/run/docker.sock openclaw:local

The setup script (scripts/docker/setup.sh) handles this automatically when OPENCLAW_SANDBOX=1 is set.

Resource limits:

services:
  openclaw-gateway:
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 2G
        reservations:
          cpus: '0.5'
          memory: 512M

Set limits based on your workload. Message-heavy workloads need more CPU; agents with large contexts need more memory.

Log rotation:

services:
  openclaw-gateway:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

Configure rotation to prevent log files from consuming disk space.

☕ 茶水间时间: The Gateway's health check uses fetch() instead of curl because the Node base image doesn't include curl to stay small. The one-liner node -e "fetch(...)" works everywhere Node runs, avoiding the 50MB curl dependency. This is a micro-optimization that matters at scale but can confuse newcomers who expect standard Unix tools.

Production deployment requires security considerations...

You now have the tools to deploy OpenClaw using npm, Docker, or source builds. You can monitor health, collect metrics, aggregate logs, and handle updates safely. But production deployment also requires security: authentication, encryption, access control, and secrets management. A well-deployed system that's insecure is worse than no deployment at all.