Hosting
Fly.io
هدف: اجرای OpenClaw Gateway روی یک ماشین Fly.io با ذخیرهسازی پایدار، HTTPS خودکار، و دسترسی Discord/کانال.
آنچه نیاز دارید
- نصب بودن flyctl CLI
- حساب Fly.io (سطح رایگان هم کافی است)
- احراز هویت مدل: کلید API برای ارائهدهنده مدل انتخابی شما
- اعتبارنامههای کانال: توکن ربات Discord، توکن Telegram، و غیره.
مسیر سریع برای مبتدیان
- مخزن را کلون کنید →
fly.tomlرا سفارشی کنید - برنامه + حجم را بسازید → secretها را تنظیم کنید
- با
fly deployاستقرار دهید - با SSH وارد شوید تا پیکربندی بسازید یا از Control UI استفاده کنید
ساخت برنامه Fly
# Clone the repogit clone https://github.com/openclaw/openclaw.gitcd 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نکته: منطقهای نزدیک به خودتان انتخاب کنید. گزینههای رایج: lhr (لندن)، iad (ویرجینیا)، sjc (سنخوزه).
پیکربندی fly.toml
fly.toml را ویرایش کنید تا با نام برنامه و نیازهای شما هماهنگ شود.
نکته امنیتی: پیکربندی پیشفرض یک URL عمومی را در معرض قرار میدهد. برای استقرار سختگیرانهتر بدون IP عمومی، استقرار خصوصی را ببینید یا از deploy/fly.private.toml استفاده کنید.
app = "my-openclaw" # Your app nameprimary_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"تصویر Docker مربوط به OpenClaw از tini بهعنوان entrypoint خود استفاده میکند. فرمانهای فرایند Fly، CMD در Docker را بدون جایگزین کردن ENTRYPOINT عوض میکنند، بنابراین فرایند همچنان زیر tini اجرا میشود.
تنظیمات کلیدی:
| تنظیم | دلیل |
|---|---|
--bind lan |
به 0.0.0.0 متصل میشود تا پراکسی Fly بتواند به Gateway برسد |
--allow-unconfigured |
بدون فایل پیکربندی شروع میشود (بعدا یکی میسازید) |
internal_port = 3000 |
برای بررسیهای سلامت Fly باید با --port 3000 (یا OPENCLAW_GATEWAY_PORT) مطابقت داشته باشد |
memory = "2048mb" |
512 مگابایت خیلی کم است؛ 2 گیگابایت توصیه میشود |
OPENCLAW_STATE_DIR = "/data" |
وضعیت را روی volume پایدار نگه میدارد |
تنظیم secretها
# Required: Gateway token (for non-loopback binding)fly secrets set OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32) # Model provider API keysfly secrets set ANTHROPIC_API_KEY=example-anthropic-key-not-real # Optional: Other providersfly secrets set OPENAI_API_KEY=example-openai-key-not-realfly secrets set GOOGLE_API_KEY=... # Channel tokensfly secrets set DISCORD_BOT_TOKEN=example-discord-bot-tokenیادداشتها:
- اتصالهای غیر loopback (
--bind lan) به یک مسیر معتبر احراز هویت Gateway نیاز دارند. این نمونه Fly.io ازOPENCLAW_GATEWAY_TOKENاستفاده میکند، اماgateway.auth.passwordیا یک استقرارtrusted-proxyغیر loopback که درست پیکربندی شده باشد نیز این نیاز را برآورده میکند. - با این توکنها مثل گذرواژه رفتار کنید.
- برای همه کلیدهای API و توکنها، env varها را به فایل پیکربندی ترجیح دهید. این کار secretها را از
openclaw.jsonدور نگه میدارد، جایی که ممکن است تصادفی افشا یا ثبت شوند.
استقرار
fly deployنخستین استقرار تصویر Docker را میسازد (حدود 2 تا 3 دقیقه). استقرارهای بعدی سریعتر هستند.
پس از استقرار، بررسی کنید:
fly statusfly logsباید ببینید:
[gateway] listening on ws://0.0.0.0:3000 (PID xxx)[discord] logged in to discord as xxxساخت فایل پیکربندی
با SSH وارد ماشین شوید تا یک پیکربندی مناسب بسازید:
fly ssh consoleدایرکتوری و فایل پیکربندی را بسازید:
mkdir -p /datacat > /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یادداشت: با OPENCLAW_STATE_DIR=/data، مسیر پیکربندی /data/openclaw.json است.
یادداشت: https://my-openclaw.fly.dev را با origin واقعی برنامه Fly خود جایگزین کنید. راهاندازی Gateway، originهای محلی Control UI را از مقادیر زمان اجرا --bind و --port مقداردهی اولیه میکند تا نخستین بوت بتواند پیش از وجود پیکربندی ادامه پیدا کند، اما دسترسی مرورگر از طریق Fly همچنان نیاز دارد origin دقیق HTTPS در gateway.controlUi.allowedOrigins فهرست شده باشد.
یادداشت: توکن Discord میتواند از یکی از این دو منبع بیاید:
- متغیر محیطی:
DISCORD_BOT_TOKEN(برای secretها توصیه میشود) - فایل پیکربندی:
channels.discord.token
اگر از env var استفاده میکنید، نیازی نیست توکن را به پیکربندی اضافه کنید. Gateway بهطور خودکار DISCORD_BOT_TOKEN را میخواند.
برای اعمال، راهاندازی مجدد کنید:
exitfly machine restart <machine-id>دسترسی به Gateway
Control UI
در مرورگر باز کنید:
fly openیا به https://my-openclaw.fly.dev/ بروید
با secret مشترک پیکربندیشده احراز هویت کنید. این راهنما از توکن Gateway از OPENCLAW_GATEWAY_TOKEN استفاده میکند؛ اگر به احراز هویت با گذرواژه تغییر دادهاید، همان گذرواژه را استفاده کنید.
لاگها
fly logs # Live logsfly logs --no-tail # Recent logsکنسول SSH
fly ssh consoleعیبیابی
«برنامه روی آدرس مورد انتظار در حال گوش دادن نیست»
Gateway بهجای 0.0.0.0 به 127.0.0.1 متصل شده است.
راهحل: --bind lan را به فرمان فرایند خود در fly.toml اضافه کنید.
بررسیهای سلامت ناموفق هستند / اتصال رد شد
Fly نمیتواند روی پورت پیکربندیشده به Gateway برسد.
راهحل: مطمئن شوید internal_port با پورت Gateway مطابقت دارد (--port 3000 یا OPENCLAW_GATEWAY_PORT=3000 را تنظیم کنید).
OOM / مشکلات حافظه
کانتینر مدام راهاندازی مجدد میشود یا کشته میشود. نشانهها: SIGABRT، v8::internal::Runtime_AllocateInYoungGeneration، یا راهاندازیهای مجدد بیصدا.
راهحل: حافظه را در fly.toml افزایش دهید:
[[vm]] memory = "2048mb"یا یک ماشین موجود را بهروزرسانی کنید:
fly machine update <machine-id> --vm-memory 2048 -yیادداشت: 512 مگابایت خیلی کم است. 1 گیگابایت ممکن است کار کند، اما زیر بار یا با لاگگیری مفصل ممکن است دچار OOM شود. 2 گیگابایت توصیه میشود.
مشکلات قفل Gateway
Gateway با خطاهای «already running» از شروع شدن خودداری میکند.
این زمانی رخ میدهد که کانتینر راهاندازی مجدد میشود اما فایل قفل PID روی volume باقی میماند.
راهحل: فایل قفل را حذف کنید:
fly ssh console --command "rm -f /data/gateway.*.lock"fly machine restart <machine-id>فایل قفل در /data/gateway.*.lock قرار دارد (نه در یک زیردایرکتوری).
پیکربندی خوانده نمیشود
--allow-unconfigured فقط guard راهاندازی را دور میزند. این گزینه /data/openclaw.json را نمیسازد یا تعمیر نمیکند، بنابراین مطمئن شوید پیکربندی واقعی شما وجود دارد و وقتی یک شروع معمولی Gateway محلی میخواهید، شامل gateway.mode="local" است.
وجود پیکربندی را بررسی کنید:
fly ssh console --command "cat /data/openclaw.json"نوشتن پیکربندی از طریق SSH
فرمان fly ssh console -C از redirection شل پشتیبانی نمیکند. برای نوشتن یک فایل پیکربندی:
# Use echo + tee (pipe from local to remote)echo '{"your":"config"}' | fly ssh console -C "tee /data/openclaw.json" # Or use sftpfly sftp shell> put /local/path/config.json /data/openclaw.jsonیادداشت: اگر فایل از قبل وجود داشته باشد، fly sftp ممکن است شکست بخورد. ابتدا حذف کنید:
fly ssh console --command "rm /data/openclaw.json"وضعیت پایدار نمیماند
اگر پس از راهاندازی مجدد، پروفایلهای احراز هویت، وضعیت کانال/ارائهدهنده، یا sessionها را از دست میدهید، دایرکتوری وضعیت روی فایلسیستم کانتینر نوشته میشود.
راهحل: مطمئن شوید OPENCLAW_STATE_DIR=/data در fly.toml تنظیم شده است و دوباره استقرار دهید.
بهروزرسانیها
# Pull latest changesgit pull # Redeployfly deploy # Check healthfly statusfly logsبهروزرسانی فرمان ماشین
اگر لازم است فرمان راهاندازی را بدون استقرار کامل تغییر دهید:
# Get machine IDfly machines list # Update commandfly machine update <machine-id> --command "node dist/index.js gateway --port 3000 --bind lan" -y # Or with memory increasefly machine update <machine-id> --vm-memory 2048 --command "node dist/index.js gateway --port 3000 --bind lan" -yیادداشت: پس از fly deploy، فرمان ماشین ممکن است به چیزی که در fly.toml است بازنشانی شود. اگر تغییرات دستی انجام دادهاید، پس از استقرار دوباره آنها را اعمال کنید.
استقرار خصوصی (سختگیرانه)
بهطور پیشفرض، Fly IPهای عمومی اختصاص میدهد و Gateway شما را در https://your-app.fly.dev در دسترس قرار میدهد. این راحت است، اما یعنی استقرار شما توسط اسکنرهای اینترنتی (Shodan، Censys، و غیره) قابل کشف است.
برای یک استقرار سختگیرانهتر با بدون در معرضگذاری عمومی، از الگوی خصوصی استفاده کنید.
چه زمانی از استقرار خصوصی استفاده کنید
- فقط تماسها/پیامهای خروجی انجام میدهید (بدون Webhook ورودی)
- از تونلهای ngrok یا Tailscale برای هر callback مربوط به Webhook استفاده میکنید
- بهجای مرورگر از طریق SSH، پراکسی، یا WireGuard به Gateway دسترسی دارید
- میخواهید استقرار از اسکنرهای اینترنتی پنهان باشد
راهاندازی
بهجای پیکربندی استاندارد، از deploy/fly.private.toml استفاده کنید:
# Deploy with private configfly deploy -c deploy/fly.private.tomlیا یک استقرار موجود را تبدیل کنید:
# List current IPsfly ips list -a my-openclaw # Release public IPsfly ips release <public-ipv4> -a my-openclawfly 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 IPv6fly ips allocate-v6 --private -a my-openclawپس از این، fly ips list باید فقط یک IP از نوع private نشان دهد:
VERSION IP TYPE REGIONv6 fdaa:x:x:x:x::x private globalدسترسی به استقرار خصوصی
از آنجا که URL عمومی وجود ندارد، از یکی از این روشها استفاده کنید:
گزینه 1: پراکسی محلی (سادهترین)
# Forward local port 3000 to the appfly proxy 3000:3000 -a my-openclaw # Then open http://localhost:3000 in browserگزینه ۲: VPN WireGuard
# 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گزینه ۳: فقط SSH
fly ssh console -a my-openclawWebhookها با استقرار خصوصی
اگر به callbackهای Webhook (Twilio، Telnyx و غیره) بدون در معرض عموم قرار گرفتن نیاز دارید:
- تونل ngrok - ngrok را داخل کانتینر یا بهصورت sidecar اجرا کنید
- Tailscale Funnel - مسیرهای مشخصی را از طریق Tailscale در دسترس قرار دهید
- فقط خروجی - برخی ارائهدهندگان (Twilio) برای تماسهای خروجی بدون Webhook بهخوبی کار میکنند
نمونه پیکربندی تماس صوتی با ngrok:
{ plugins: { entries: { "voice-call": { enabled: true, config: { provider: "twilio", tunnel: { provider: "ngrok" }, webhookSecurity: { allowedHosts: ["example.ngrok.app"], }, }, }, }, },}تونل ngrok داخل کانتینر اجرا میشود و بدون افشای خود برنامه Fly، یک URL عمومی برای Webhook فراهم میکند. webhookSecurity.allowedHosts را روی hostname عمومی تونل تنظیم کنید تا headerهای host فورواردشده پذیرفته شوند.
مزایای امنیتی
| جنبه | عمومی | خصوصی |
|---|---|---|
| اسکنرهای اینترنت | قابل کشف | پنهان |
| حمله مستقیم | ممکن | مسدود |
| دسترسی UI کنترل | مرورگر | Proxy/VPN |
| تحویل Webhook | مستقیم | از طریق تونل |
نکات
- Fly.io از معماری x86 استفاده میکند (نه ARM)
- Dockerfile با هر دو معماری سازگار است
- برای راهاندازی WhatsApp/Telegram، از
fly ssh consoleاستفاده کنید - دادههای پایدار روی volume در
/dataقرار دارند - Signal به Java + signal-cli نیاز دارد؛ از یک image سفارشی استفاده کنید و حافظه را روی 2GB+ نگه دارید.
هزینه
با پیکربندی پیشنهادی (shared-cpu-2x، ۲ گیگابایت RAM):
- حدود ۱۰ تا ۱۵ دلار در ماه، بسته به میزان استفاده
- tier رایگان شامل مقداری سهمیه است
برای جزئیات، قیمتگذاری Fly.io را ببینید.
مراحل بعدی
- کانالهای پیامرسانی را راهاندازی کنید: کانالها
- Gateway را پیکربندی کنید: پیکربندی Gateway
- OpenClaw را بهروز نگه دارید: بهروزرسانی