Chuyển đến nội dung chính
Mục tiêu: OpenClaw Gateway chạy trên một máy Fly.io với lưu trữ bền vững, HTTPS tự động và quyền truy cập Discord/kênh.

Bạn cần chuẩn bị

  • Đã cài đặt flyctl CLI
  • Tài khoản Fly.io (gói miễn phí dùng được)
  • Xác thực mô hình: khóa API cho nhà cung cấp mô hình bạn chọn
  • Thông tin xác thực kênh: token bot Discord, token Telegram, v.v.

Lộ trình nhanh cho người mới

  1. Clone repo → tùy chỉnh fly.toml
  2. Tạo app + volume → đặt secret
  3. Triển khai bằng fly deploy
  4. SSH vào để tạo cấu hình hoặc dùng Giao diện điều khiển
1

Create the Fly app

# Clone the repo
git clone https://github.com/openclaw/openclaw.git
cd openclaw

# Create a new Fly app (pick your own name)
fly apps create my-openclaw

# Create a persistent volume (1GB is usually enough)
fly volumes create openclaw_data --size 1 --region iad
Mẹo: Chọn một khu vực gần bạn. Các tùy chọn phổ biến: lhr (London), iad (Virginia), sjc (San Jose).
2

Configure fly.toml

Chỉnh sửa fly.toml để khớp với tên app và yêu cầu của bạn.Ghi chú bảo mật: Cấu hình mặc định để lộ một URL công khai. Để triển khai được gia cố mà không có IP công khai, xem Triển khai riêng tư hoặc dùng deploy/fly.private.toml.
app = "my-openclaw"  # Your app name
primary_region = "iad"

[build]
  dockerfile = "Dockerfile"

[env]
  NODE_ENV = "production"
  OPENCLAW_PREFER_PNPM = "1"
  OPENCLAW_STATE_DIR = "/data"
  NODE_OPTIONS = "--max-old-space-size=1536"

[processes]
  app = "node dist/index.js gateway --allow-unconfigured --port 3000 --bind lan"

[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = false
  auto_start_machines = true
  min_machines_running = 1
  processes = ["app"]

[[vm]]
  size = "shared-cpu-2x"
  memory = "2048mb"

[mounts]
  source = "openclaw_data"
  destination = "/data"
Image Docker của OpenClaw dùng tini làm entrypoint. Lệnh quy trình của Fly thay thế Docker CMD mà không thay thế ENTRYPOINT, nên quy trình vẫn chạy dưới tini.Thiết lập chính:
Thiết lậpLý do
--bind lanBind vào 0.0.0.0 để proxy của Fly có thể truy cập Gateway
--allow-unconfiguredKhởi động khi chưa có tệp cấu hình (bạn sẽ tạo sau)
internal_port = 3000Phải khớp với --port 3000 (hoặc OPENCLAW_GATEWAY_PORT) cho health check của Fly
memory = "2048mb"512MB quá nhỏ; khuyến nghị 2GB
OPENCLAW_STATE_DIR = "/data"Lưu bền vững trạng thái trên volume
3

Set secrets

# Required: Gateway token (for non-loopback binding)
fly secrets set OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32)

# Model provider API keys
fly secrets set ANTHROPIC_API_KEY=example-anthropic-key-not-real

# Optional: Other providers
fly secrets set OPENAI_API_KEY=example-openai-key-not-real
fly secrets set GOOGLE_API_KEY=...

# Channel tokens
fly secrets set DISCORD_BOT_TOKEN=example-discord-bot-token
Ghi chú:
  • Các bind không phải loopback (--bind lan) yêu cầu một đường dẫn xác thực Gateway hợp lệ. Ví dụ Fly.io này dùng OPENCLAW_GATEWAY_TOKEN, nhưng gateway.auth.password hoặc một triển khai trusted-proxy không phải loopback được cấu hình đúng cũng đáp ứng yêu cầu.
  • Xem các token này như mật khẩu.
  • Ưu tiên biến môi trường thay vì tệp cấu hình cho mọi khóa API và token. Điều này giữ secret khỏi openclaw.json, nơi chúng có thể vô tình bị lộ hoặc ghi log.
4

Deploy

fly deploy
Lần triển khai đầu tiên sẽ build image Docker (~2-3 phút). Các lần triển khai sau nhanh hơn.Sau khi triển khai, xác minh:
fly status
fly logs
Bạn sẽ thấy:
[gateway] listening on ws://0.0.0.0:3000 (PID xxx)
[discord] logged in to discord as xxx
5

Create config file

SSH vào máy để tạo cấu hình phù hợp:
fly ssh console
Tạo thư mục và tệp cấu hình:
mkdir -p /data
cat > /data/openclaw.json << 'EOF'
{
  "agents": {
    "defaults": {
      "model": {
        "primary": "anthropic/claude-opus-4-6",
        "fallbacks": ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4"]
      },
      "maxConcurrent": 4
    },
    "list": [
      {
        "id": "main",
        "default": true
      }
    ]
  },
  "auth": {
    "profiles": {
      "anthropic:default": { "mode": "token", "provider": "anthropic" },
      "openai:default": { "mode": "token", "provider": "openai" }
    }
  },
  "bindings": [
    {
      "agentId": "main",
      "match": { "channel": "discord" }
    }
  ],
  "channels": {
    "discord": {
      "enabled": true,
      "groupPolicy": "allowlist",
      "guilds": {
        "YOUR_GUILD_ID": {
          "channels": { "general": { "allow": true } },
          "requireMention": false
        }
      }
    }
  },
  "gateway": {
    "mode": "local",
    "bind": "auto",
    "controlUi": {
      "allowedOrigins": [
        "https://my-openclaw.fly.dev",
        "http://localhost:3000",
        "http://127.0.0.1:3000"
      ]
    }
  },
  "meta": {}
}
EOF
Ghi chú: Với OPENCLAW_STATE_DIR=/data, đường dẫn cấu hình là /data/openclaw.json.Ghi chú: Thay https://my-openclaw.fly.dev bằng origin Fly app thật của bạn. Khi Gateway khởi động, nó seed các origin Giao diện điều khiển cục bộ từ các giá trị runtime --bind--port để lần khởi động đầu tiên có thể tiếp tục trước khi cấu hình tồn tại, nhưng truy cập trình duyệt qua Fly vẫn cần origin HTTPS chính xác được liệt kê trong gateway.controlUi.allowedOrigins.Ghi chú: Token Discord có thể đến từ một trong hai nguồn:
  • Biến môi trường: DISCORD_BOT_TOKEN (khuyến nghị cho secret)
  • Tệp cấu hình: channels.discord.token
Nếu dùng biến môi trường, không cần thêm token vào cấu hình. Gateway tự động đọc DISCORD_BOT_TOKEN.Khởi động lại để áp dụng:
exit
fly machine restart <machine-id>
6

Access the Gateway

Giao diện điều khiển

Mở trong trình duyệt:
fly open
Hoặc truy cập https://my-openclaw.fly.dev/Xác thực bằng secret dùng chung đã cấu hình. Hướng dẫn này dùng token Gateway từ OPENCLAW_GATEWAY_TOKEN; nếu bạn đã chuyển sang xác thực bằng mật khẩu, hãy dùng mật khẩu đó thay thế.

Log

fly logs              # Live logs
fly logs --no-tail    # Recent logs

Bảng điều khiển SSH

fly ssh console

Khắc phục sự cố

”App is not listening on expected address”

Gateway đang bind vào 127.0.0.1 thay vì 0.0.0.0. Cách khắc phục: Thêm --bind lan vào lệnh quy trình trong fly.toml.

Health check thất bại / bị từ chối kết nối

Fly không thể truy cập Gateway trên cổng đã cấu hình. Cách khắc phục: Đảm bảo internal_port khớp với cổng Gateway (đặt --port 3000 hoặc OPENCLAW_GATEWAY_PORT=3000).

OOM / Sự cố bộ nhớ

Container liên tục khởi động lại hoặc bị kill. Dấu hiệu: SIGABRT, v8::internal::Runtime_AllocateInYoungGeneration, hoặc khởi động lại im lặng. Cách khắc phục: Tăng bộ nhớ trong fly.toml:
[[vm]]
  memory = "2048mb"
Hoặc cập nhật một máy hiện có:
fly machine update <machine-id> --vm-memory 2048 -y
Ghi chú: 512MB quá nhỏ. 1GB có thể hoạt động nhưng có thể OOM khi tải cao hoặc khi ghi log chi tiết. Khuyến nghị 2GB.

Sự cố khóa Gateway

Gateway từ chối khởi động với lỗi “already running”. Điều này xảy ra khi container khởi động lại nhưng tệp khóa PID vẫn còn trên volume. Cách khắc phục: Xóa tệp khóa:
fly ssh console --command "rm -f /data/gateway.*.lock"
fly machine restart <machine-id>
Tệp khóa nằm tại /data/gateway.*.lock (không nằm trong thư mục con).

Không đọc được cấu hình

--allow-unconfigured chỉ bỏ qua guard khởi động. Nó không tạo hoặc sửa /data/openclaw.json, nên hãy đảm bảo cấu hình thật của bạn tồn tại và bao gồm gateway.mode="local" khi bạn muốn khởi động Gateway cục bộ bình thường. Xác minh cấu hình tồn tại:
fly ssh console --command "cat /data/openclaw.json"

Ghi cấu hình qua SSH

Lệnh fly ssh console -C không hỗ trợ chuyển hướng shell. Để ghi tệp cấu hình:
# Use echo + tee (pipe from local to remote)
echo '{"your":"config"}' | fly ssh console -C "tee /data/openclaw.json"

# Or use sftp
fly sftp shell
> put /local/path/config.json /data/openclaw.json
Ghi chú: fly sftp có thể thất bại nếu tệp đã tồn tại. Hãy xóa trước:
fly ssh console --command "rm /data/openclaw.json"

Trạng thái không được lưu bền vững

Nếu bạn mất hồ sơ xác thực, trạng thái kênh/nhà cung cấp, hoặc phiên sau khi khởi động lại, thư mục trạng thái đang ghi vào hệ thống tệp của container. Cách khắc phục: Đảm bảo OPENCLAW_STATE_DIR=/data được đặt trong fly.toml và triển khai lại.

Cập nhật

# Pull latest changes
git pull

# Redeploy
fly deploy

# Check health
fly status
fly logs

Cập nhật lệnh máy

Nếu bạn cần thay đổi lệnh khởi động mà không triển khai lại toàn bộ:
# Get machine ID
fly machines list

# Update command
fly machine update <machine-id> --command "node dist/index.js gateway --port 3000 --bind lan" -y

# Or with memory increase
fly machine update <machine-id> --vm-memory 2048 --command "node dist/index.js gateway --port 3000 --bind lan" -y
Ghi chú: Sau fly deploy, lệnh máy có thể được đặt lại theo nội dung trong fly.toml. Nếu bạn đã thay đổi thủ công, hãy áp dụng lại sau khi deploy.

Triển khai riêng tư (được gia cố)

Theo mặc định, Fly cấp phát IP công khai, khiến Gateway của bạn có thể truy cập tại https://your-app.fly.dev. Điều này tiện lợi nhưng đồng nghĩa triển khai của bạn có thể bị các trình quét internet phát hiện (Shodan, Censys, v.v.). Để triển khai được gia cố mà không lộ công khai, hãy dùng template riêng tư.

Khi nào dùng triển khai riêng tư

  • Bạn chỉ thực hiện cuộc gọi/tin nhắn đi ra (không có Webhook đi vào)
  • Bạn dùng tunnel ngrok hoặc Tailscale cho mọi callback Webhook
  • Bạn truy cập Gateway qua SSH, proxy, hoặc WireGuard thay vì trình duyệt
  • Bạn muốn triển khai ẩn khỏi các trình quét internet

Thiết lập

Dùng deploy/fly.private.toml thay vì cấu hình tiêu chuẩn:
# Deploy with private config
fly deploy -c deploy/fly.private.toml
Hoặc chuyển đổi một triển khai hiện có:
# List current IPs
fly ips list -a my-openclaw

# Release public IPs
fly ips release <public-ipv4> -a my-openclaw
fly ips release <public-ipv6> -a my-openclaw

# Switch to private config so future deploys don't re-allocate public IPs
# (remove [http_service] or deploy with the private template)
fly deploy -c deploy/fly.private.toml

# Allocate private-only IPv6
fly ips allocate-v6 --private -a my-openclaw
Sau đó, fly ips list chỉ nên hiển thị IP loại private:
VERSION  IP                   TYPE             REGION
v6       fdaa:x:x:x:x::x      private          global

Truy cập triển khai riêng tư

Vì không có URL công khai, hãy dùng một trong các phương pháp sau: Tùy chọn 1: Proxy cục bộ (đơn giản nhất)
# Forward local port 3000 to the app
fly proxy 3000:3000 -a my-openclaw

# Then open http://localhost:3000 in browser
Tùy chọn 2: WireGuard VPN
# Create WireGuard config (one-time)
fly wireguard create

# Import to WireGuard client, then access via internal IPv6
# Example: http://[fdaa:x:x:x:x::x]:3000
Tùy chọn 3: Chỉ SSH
fly ssh console -a my-openclaw

Webhook với triển khai riêng tư

Nếu bạn cần callback Webhook (Twilio, Telnyx, v.v.) mà không phơi bày công khai:
  1. Đường hầm ngrok - Chạy ngrok bên trong container hoặc làm sidecar
  2. Tailscale Funnel - Phơi bày các đường dẫn cụ thể qua Tailscale
  3. Chỉ gửi ra ngoài - Một số nhà cung cấp (Twilio) hoạt động tốt cho cuộc gọi đi mà không cần Webhook
Ví dụ cấu hình cuộc gọi thoại với ngrok:
{
  plugins: {
    entries: {
      "voice-call": {
        enabled: true,
        config: {
          provider: "twilio",
          tunnel: { provider: "ngrok" },
          webhookSecurity: {
            allowedHosts: ["example.ngrok.app"],
          },
        },
      },
    },
  },
}
Đường hầm ngrok chạy bên trong container và cung cấp một URL Webhook công khai mà không phơi bày chính ứng dụng Fly. Đặt webhookSecurity.allowedHosts thành tên máy chủ đường hầm công khai để chấp nhận các header máy chủ được chuyển tiếp.

Lợi ích bảo mật

Khía cạnhCông khaiRiêng tư
Trình quét InternetCó thể phát hiệnẨn
Tấn công trực tiếpCó thể xảy raBị chặn
Truy cập Control UITrình duyệtProxy/VPN
Phân phối WebhookTrực tiếpQua đường hầm

Ghi chú

  • Fly.io dùng kiến trúc x86 (không phải ARM)
  • Dockerfile tương thích với cả hai kiến trúc
  • Để onboarding WhatsApp/Telegram, dùng fly ssh console
  • Dữ liệu bền vững nằm trên volume tại /data
  • Signal yêu cầu Java + signal-cli; dùng image tùy chỉnh và giữ bộ nhớ ở mức 2GB+.

Chi phí

Với cấu hình được khuyến nghị (shared-cpu-2x, RAM 2GB):
  • Khoảng $10-15/tháng tùy mức sử dụng
  • Gói miễn phí bao gồm một phần hạn mức
Xem giá Fly.io để biết chi tiết.

Bước tiếp theo

Liên quan