Hosting
Fly.io
هدف: اجرای OpenClaw Gateway روی یک ماشین Fly.io با فضای ذخیرهسازی پایدار، HTTPS خودکار، و دسترسی Discord/کانال.
آنچه نیاز دارید
- نصب بودن flyctl CLI
- حساب Fly.io (سطح رایگان هم کار میکند)
- احراز هویت مدل: کلید API برای ارائهدهنده مدل انتخابی شما
- اعتبارنامههای کانال: توکن بات Discord، توکن Telegram، و غیره.
مسیر سریع برای مبتدیان
- مخزن را clone کنید →
fly.tomlرا سفارشی کنید - برنامه + volume بسازید → secrets را تنظیم کنید
- با
fly deployمستقر کنید - برای ساخت پیکربندی SSH بزنید یا از رابط کاربری کنترل استفاده کنید
ساخت برنامه Fly
# 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
نکته: منطقهای نزدیک به خودتان انتخاب کنید. گزینههای رایج: lhr (لندن)، iad (ویرجینیا)، sjc (سنخوزه).
پیکربندی fly.toml
فایل fly.toml را مطابق نام برنامه و نیازهای خودتان ویرایش کنید.
نکته امنیتی: پیکربندی پیشفرض یک URL عمومی را در دسترس قرار میدهد. برای استقرار سختگیرانهتر بدون IP عمومی، استقرار خصوصی را ببینید یا از 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"
تنظیمات کلیدی:
| تنظیم | دلیل |
|---|---|
--bind lan |
به 0.0.0.0 متصل میشود تا proxy مربوط به Fly بتواند به Gateway دسترسی پیدا کند |
--allow-unconfigured |
بدون فایل پیکربندی شروع میشود (بعدا یکی میسازید) |
internal_port = 3000 |
باید برای health checkهای Fly با --port 3000 (یا OPENCLAW_GATEWAY_PORT) مطابقت داشته باشد |
memory = "2048mb" |
512 مگابایت خیلی کم است؛ 2 گیگابایت توصیه میشود |
OPENCLAW_STATE_DIR = "/data" |
وضعیت را روی volume پایدار نگه میدارد |
تنظیم 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=sk-ant-...
# Optional: Other providers
fly secrets set OPENAI_API_KEY=sk-...
fly secrets set GOOGLE_API_KEY=...
# Channel tokens
fly secrets set DISCORD_BOT_TOKEN=MTQ...
یادداشتها:
- اتصالهای غیر loopback (
--bind lan) به یک مسیر احراز هویت معتبر برای Gateway نیاز دارند. این نمونه Fly.io ازOPENCLAW_GATEWAY_TOKENاستفاده میکند، اماgateway.auth.passwordیا یک استقرارtrusted-proxyغیر loopback که درست پیکربندی شده باشد نیز این نیاز را برآورده میکند. - با این توکنها مانند گذرواژه رفتار کنید.
- برای همه کلیدهای API و توکنها، env vars را به فایل پیکربندی ترجیح دهید. این کار secrets را بیرون از
openclaw.jsonنگه میدارد؛ جایی که ممکن است بهاشتباه افشا یا log شوند.
استقرار
fly deploy
اولین استقرار image مربوط به Docker را میسازد (حدود 2 تا 3 دقیقه). استقرارهای بعدی سریعتر هستند.
پس از استقرار، بررسی کنید:
fly status
fly 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 /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
یادداشت: با OPENCLAW_STATE_DIR=/data، مسیر پیکربندی /data/openclaw.json است.
یادداشت: https://my-openclaw.fly.dev را با origin واقعی برنامه Fly خودتان جایگزین کنید. راهاندازی Gateway، originهای محلی رابط کاربری کنترل را از مقادیر runtime یعنی --bind و --port seed میکند تا اولین boot بتواند پیش از وجود پیکربندی ادامه پیدا کند، اما دسترسی مرورگر از طریق Fly همچنان نیاز دارد origin دقیق HTTPS در gateway.controlUi.allowedOrigins فهرست شده باشد.
یادداشت: توکن Discord میتواند از هرکدام از این دو جا بیاید:
- متغیر محیطی:
DISCORD_BOT_TOKEN(برای secrets توصیه میشود) - فایل پیکربندی:
channels.discord.token
اگر از env var استفاده میکنید، نیازی نیست توکن را به پیکربندی اضافه کنید. Gateway بهصورت خودکار DISCORD_BOT_TOKEN را میخواند.
برای اعمال، restart کنید:
exit
fly machine restart <machine-id>
دسترسی به Gateway
رابط کاربری کنترل
در مرورگر باز کنید:
fly open
یا به https://my-openclaw.fly.dev/ بروید
با shared secret پیکربندیشده احراز هویت کنید. این راهنما از توکن Gateway از OPENCLAW_GATEWAY_TOKEN استفاده میکند؛ اگر به احراز هویت با گذرواژه تغییر دادهاید، بهجای آن از همان گذرواژه استفاده کنید.
Logها
fly logs # Live logs
fly logs --no-tail # Recent logs
کنسول SSH
fly ssh console
عیبیابی
«برنامه روی نشانی مورد انتظار listen نمیکند»
Gateway بهجای 0.0.0.0 به 127.0.0.1 متصل میشود.
رفع: --bind lan را به فرمان process خود در fly.toml اضافه کنید.
شکست health checkها / connection refused
Fly نمیتواند روی پورت پیکربندیشده به Gateway دسترسی پیدا کند.
رفع: مطمئن شوید internal_port با پورت Gateway مطابقت دارد (--port 3000 یا OPENCLAW_GATEWAY_PORT=3000 را تنظیم کنید).
OOM / مشکلات حافظه
Container مدام restart میشود یا kill میشود. نشانهها: SIGABRT، v8::internal::Runtime_AllocateInYoungGeneration، یا restartهای بیصدا.
رفع: حافظه را در fly.toml افزایش دهید:
[[vm]]
memory = "2048mb"
یا یک ماشین موجود را بهروزرسانی کنید:
fly machine update <machine-id> --vm-memory 2048 -y
یادداشت: 512 مگابایت خیلی کم است. 1 گیگابایت ممکن است کار کند اما زیر بار یا با logging مفصل میتواند OOM شود. 2 گیگابایت توصیه میشود.
مشکلات lock در Gateway
Gateway با خطاهای «already running» از شروع شدن خودداری میکند.
این زمانی رخ میدهد که container restart میشود اما فایل PID lock روی volume باقی میماند.
رفع: فایل lock را حذف کنید:
fly ssh console --command "rm -f /data/gateway.*.lock"
fly machine restart <machine-id>
فایل lock در /data/gateway.*.lock است (نه در یک زیرپوشه).
پیکربندی خوانده نمیشود
--allow-unconfigured فقط guard راهاندازی را دور میزند. این گزینه /data/openclaw.json را نمیسازد یا repair نمیکند، پس مطمئن شوید پیکربندی واقعی شما وجود دارد و زمانی که یک شروع عادی Gateway محلی میخواهید، شامل gateway.mode="local" است.
بررسی کنید پیکربندی وجود دارد:
fly ssh console --command "cat /data/openclaw.json"
نوشتن پیکربندی از طریق SSH
فرمان fly ssh console -C از shell redirection پشتیبانی نمیکند. برای نوشتن فایل پیکربندی:
# 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
یادداشت: اگر فایل از قبل وجود داشته باشد، fly sftp ممکن است fail شود. ابتدا حذف کنید:
fly ssh console --command "rm /data/openclaw.json"
وضعیت پایدار نمیماند
اگر پس از restart، auth profileها، وضعیت کانال/ارائهدهنده، یا sessionها را از دست میدهید، state dir در حال نوشتن روی filesystem مربوط به container است.
رفع: مطمئن شوید OPENCLAW_STATE_DIR=/data در fly.toml تنظیم شده است و دوباره مستقر کنید.
بهروزرسانیها
# Pull latest changes
git pull
# Redeploy
fly deploy
# Check health
fly status
fly logs
بهروزرسانی فرمان ماشین
اگر لازم است فرمان startup را بدون redeploy کامل تغییر دهید:
# 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
یادداشت: پس از fly deploy، ممکن است فرمان ماشین به آنچه در fly.toml است reset شود. اگر تغییرات دستی دادهاید، پس از deploy دوباره آنها را اعمال کنید.
استقرار خصوصی (سختگیرانه)
بهصورت پیشفرض، Fly، IPهای عمومی اختصاص میدهد و Gateway شما را در https://your-app.fly.dev در دسترس قرار میدهد. این راحت است، اما یعنی استقرار شما توسط اسکنرهای اینترنتی (Shodan، Censys، و غیره) قابل کشف است.
برای یک استقرار سختگیرانهتر با بدون هیچ مواجهه عمومی، از قالب خصوصی استفاده کنید.
چه زمانی از استقرار خصوصی استفاده کنید
- فقط تماسها/پیامهای خروجی برقرار میکنید (بدون webhookهای ورودی)
- برای هر callback مربوط به Webhook از تونلهای ngrok یا Tailscale استفاده میکنید
- بهجای مرورگر، از طریق SSH، proxy، یا WireGuard به Gateway دسترسی دارید
- میخواهید استقرار از اسکنرهای اینترنتی پنهان باشد
راهاندازی
بهجای پیکربندی استاندارد، از deploy/fly.private.toml استفاده کنید:
# Deploy with private config
fly deploy -c deploy/fly.private.toml
یا یک استقرار موجود را تبدیل کنید:
# 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
پس از این، fly ips list باید فقط یک IP از نوع private نشان دهد:
VERSION IP TYPE REGION
v6 fdaa:x:x:x:x::x private global
دسترسی به استقرار خصوصی
از آنجا که URL عمومی وجود ندارد، از یکی از این روشها استفاده کنید:
گزینه 1: proxy محلی (سادهترین)
# Forward local port 3000 to the app
fly proxy 3000:3000 -a my-openclaw
# Then open http://localhost:3000 in browser
گزینه 2: 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
گزینه 3: فقط SSH
fly ssh console -a my-openclaw
Webhookها با استقرار خصوصی
اگر به 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 را روی نام میزبان عمومی تونل تنظیم کنید تا headerهای میزبانِ ارسالشده پذیرفته شوند.
مزایای امنیتی
| جنبه | عمومی | خصوصی |
|---|---|---|
| اسکنرهای اینترنت | قابل کشف | پنهان |
| حملههای مستقیم | ممکن | مسدود |
| دسترسی UI کنترل | مرورگر | پروکسی/VPN |
| تحویل Webhook | مستقیم | از طریق تونل |
یادداشتها
- Fly.io از معماری x86 استفاده میکند (نه ARM)
- Dockerfile با هر دو معماری سازگار است
- برای راهاندازی اولیه WhatsApp/Telegram، از
fly ssh consoleاستفاده کنید - دادههای پایدار روی volume در
/dataقرار دارند - Signal به Java + signal-cli نیاز دارد؛ از یک image سفارشی استفاده کنید و حافظه را روی 2GB+ نگه دارید.
هزینه
با پیکربندی پیشنهادی (shared-cpu-2x، 2GB RAM):
- حدود $10-15 در ماه، بسته به میزان استفاده
- سطح رایگان شامل مقداری سهمیه است
برای جزئیات، قیمتگذاری Fly.io را ببینید.
گامهای بعدی
- کانالهای پیامرسانی را راهاندازی کنید: کانالها
- Gateway را پیکربندی کنید: پیکربندی Gateway
- OpenClaw را بهروز نگه دارید: بهروزرسانی