الدرس 08 — تحليل معمّق لنظام الإعداد: الطريقة الصحيحة لحفظ مفاتيح API
الهدف: فهم منظومة الإعداد الثلاثية الطبقات في OpenClaw، وإتقان الأوضاع الثلاثة لـ Secret Provider، لجعل مفاتيحك آمنة ومرنة.
ما ستتعلمه
- بنية ملفات إعداد OpenClaw وترتيب القراءة
- الأساليب الثلاثة لكتابة مفتاح API: نص مباشر / مرجع متغير بيئة / أمر خارجي
- التصميم الأمني لنظام Secret Provider
- كيفية التكامل مع أدوات إدارة المفاتيح مثل 1Password وVault
أولاً: أين تُخزَّن ملفات الإعداد؟
يُخزَّن إعداد OpenClaw في ~/.openclaw/openclaw.json (أو .yaml)، ويُقرأ تلقائياً عند تشغيل البوابة.
# عرض الإعداد الحالي
openclaw config show
# تعيين حقل محدد عبر سطر الأوامر
openclaw config set gateway.mode localالبنية الإجمالية:
{
"gateway": { ... }, // وضع تشغيل البوابة
"agents": { ... }, // السلوك الافتراضي لوكلاء الذكاء الاصطناعي
"models": { ... }, // قائمة مزودي النماذج
"channels": { ... }, // قنوات الرسائل (Telegram، Discord، إلخ)
"env": { ... }, // متغيرات البيئة المحقونة في وقت التشغيل
"secrets": { ... }, // إعداد Secret Provider (متقدم)
"hooks": { ... } // خطافات دورة الحياة
}ثانياً: الأساليب الثلاثة لكتابة مفتاح API
الأسلوب A: كتابة النص مباشرةً (للتجربة السريعة)
الأبسط، لكنه غير موصى به في بيئات الإنتاج أو الاستخدام المشترك لأن المفتاح يُحفظ بصيغة نص واضح.
{
"models": {
"providers": {
"openai": {
"apiKey": "sk-proj-xxxxxxxxxxxxxxxx"
}
}
}
}الأسلوب B: مرجع متغير البيئة (الموصى به يومياً)
استخدم محدد ${VAR_NAME} لمرجعة متغير بيئة النظام، دون حفظ المفتاح الحقيقي في ملف الإعداد.
الخطوة الأولى: تصدير المتغيرات في الـ shell أو كتابتها في ~/.profile:
export OPENAI_API_KEY="sk-proj-xxxxxxxxxxxxxxxx"
export MINIMAX_API_KEY="eyJhbGci..."الخطوة الثانية: استخدام المحدد في ملف الإعداد:
{
"models": {
"providers": {
"openai": {
"apiKey": "${OPENAI_API_KEY}"
},
"minimax": {
"apiKey": "${MINIMAX_API_KEY}"
}
}
}
}يمكن أيضاً كتابة هذا بصيغة أكثر صراحة:
{
"apiKey": { "source": "env", "provider": "default", "id": "OPENAI_API_KEY" }
}آلية العمل: عند بدء تشغيل البوابة، يبحث OpenClaw عن نمط ${VAR_NAME} ويقرأ القيمة المقابلة من process.env، ويُحلّها في الذاكرة فقط دون كتابة أي شيء على القرص.
الأسلوب C: Secret Provider (للفرق / نشر الخوادم)
هذا هو الأسلوب الأكثر أماناً ومرونةً، مناسب لـ:
- الخوادم التي لا تريد تعيين متغيرات بيئة فيها
- البوابات المشتركة مع إدارة مركزية للمفاتيح
- التكامل مع 1Password CLI وHashiCorp Vault وغيرها
لـ Secret Provider ثلاثة مصادر:
source: "file" — القراءة من ملف
مناسب لتخزين المفاتيح في ملف بصلاحيات صارمة (يتحقق OpenClaw من صلاحيات الملف، ولا يسمح بالكتابة الجماعية):
{
"secrets": {
"providers": {
"my-keys": {
"source": "file",
"path": "~/.openclaw/secrets.json",
"mode": "json"
}
}
},
"models": {
"providers": {
"openai": {
"apiKey": { "source": "file", "provider": "my-keys", "id": "/openai/apiKey" }
}
}
}
}ملف ~/.openclaw/secrets.json المقابل:
{
"openai": { "apiKey": "sk-proj-xxxxxxxx" },
"minimax": { "apiKey": "eyJhbGci..." }
}متطلب أمني: يجب أن يكون الملف مملوكاً للمستخدم الحالي، وصلاحياته لا تتجاوز
600(chmod 600 ~/.openclaw/secrets.json).
source: "exec" — استدعاء برنامج خارجي
مناسب للتكامل مع 1Password CLI وVault وخزانة مفاتيح النظام:
{
"secrets": {
"providers": {
"op-vault": {
"source": "exec",
"command": "/usr/local/bin/op-resolver",
"timeoutMs": 5000
}
}
},
"models": {
"providers": {
"openai": {
"apiKey": { "source": "exec", "provider": "op-vault", "id": "openai/api-key" }
}
}
}
}يستقبل البرنامج الخارجي الطلبات عبر stdin ويُعيد النتائج عبر stdout وفق البروتوكول التالي:
# stdin يستلم (JSON):
{ "protocolVersion": 1, "provider": "op-vault", "ids": ["openai/api-key"] }
# stdout يُعيد (JSON):
{ "protocolVersion": 1, "values": { "openai/api-key": "sk-proj-xxx" } }
ثالثاً: مثال التكامل مع 1Password
إذا كنت تحفظ مفاتيح API في 1Password، يمكنك كتابة سكريبت resolver بسيط:
#!/usr/bin/env bash
# ~/.openclaw/op-resolver.sh
# الصلاحيات: chmod 700 ~/.openclaw/op-resolver.sh
set -euo pipefail
INPUT=$(cat)
ID=$(echo "$INPUT" | jq -r '.ids[0]')
# القراءة من 1Password
VALUE=$(op read "op://Private/$ID" 2>/dev/null)
echo "{\"protocolVersion\":1,\"values\":{\"$ID\":\"$VALUE\"}}"ثم الإعداد:
{
"secrets": {
"providers": {
"1password": {
"source": "exec",
"command": "/Users/اسم_مستخدمك/.openclaw/op-resolver.sh",
"timeoutMs": 8000
}
}
}
}ملاحظة: يجب أن يكون
commandمساراً مطلقاً، ولا يجوز للمستخدمين الآخرين الكتابة فيه.
رابعاً: كتلة env في الإعداد
بجانب Secret Provider، توفر كتلة env طريقة مبسطة — إعلان متغيرات البيئة مباشرةً في ملف الإعداد:
{
"env": {
"vars": {
"HTTP_PROXY": "http://127.0.0.1:7890",
"OPENAI_BASE_URL": "https://api.openai.com"
}
}
}القواعد:
- تُحقن فقط قيم
env.varsمن ملف الإعداد، ولا تُكتب فوق متغيرات النظام الموجودة بنفس الاسم - أسماء المتغيرات الخطرة مثل
PATHوLD_PRELOADتُحجب تلقائياً ولا يمكن حقنها بهذه الطريقة
خامساً: إخفاء الحقول الحساسة تلقائياً
يستخدم OpenClaw سجل Zod sensitive لتمييز جميع حقول المفاتيح. عند كشف معلومات الإعداد للوحة التحكم أو السجلات، تُستبدل هذه الحقول تلقائياً بـ [REDACTED]:
# ما تراه في السجلات أو استجابات API:
{ "apiKey": "[REDACTED]" }
# القيمة الحقيقية لا تظهر في السجلات
سادساً: مثال إعداد كامل (نماذج متعددة + مفاتيح آمنة)
{
"gateway": { "mode": "local" },
"secrets": {
"providers": {
"env-keys": { "source": "env" }
},
"defaults": { "env": "env-keys" }
},
"agents": {
"defaults": {
"model": { "primary": "openai/gpt-4o" }
}
},
"models": {
"mode": "merge",
"providers": {
"openai": {
"apiKey": "${OPENAI_API_KEY}",
"models": [
{ "id": "gpt-4o", "name": "GPT-4o" }
]
},
"minimax": {
"baseUrl": "https://api.minimax.io/anthropic",
"apiKey": "${MINIMAX_API_KEY}",
"api": "anthropic-messages",
"models": [
{
"id": "MiniMax-M2.1",
"name": "MiniMax M2.1",
"contextWindow": 200000,
"maxTokens": 8192
}
]
}
}
},
"channels": {
"telegram": {
"token": "${TELEGRAM_BOT_TOKEN}"
}
}
}متغيرات البيئة المقابلة (تُكتب في ~/.profile أو .env):
export OPENAI_API_KEY="sk-proj-..."
export MINIMAX_API_KEY="eyJhbGci..."
export TELEGRAM_BOT_TOKEN="8543054163:AAH..."سابعاً: الأسئلة الشائعة
لماذا لم تُطبَّق التغييرات في الإعداد؟
تحتاج البوابة لإعادة التشغيل لإعادة قراءة الإعداد (باستثناء مهارات SKILL.md):
openclaw gateway restartكيف أتحقق من قراءة المفتاح بشكل صحيح؟
openclaw models list
# رؤية نماذج المزود المقابل تعني نجاح تحليل apiKeyإذا كانت قائمة النماذج فارغة، شغّل openclaw config show للتحقق من تحليل الإعداد، وتأكد من تصدير متغير البيئة المقابل لـ ${VAR_NAME}.
كيف أصلح خطأ صلاحيات مصدر الملف؟
chmod 600 ~/.openclaw/secrets.json
# تأكد أن الملف مملوك للمستخدم الحالي
ls -la ~/.openclaw/secrets.jsonيشترط OpenClaw أن تكون صلاحيات ملف المفاتيح 600 كحد أقصى، وأن يكون مملوكاً للمستخدم الحالي (لا يصح أن يكون مملوكاً للـ root مع قابلية القراءة للمستخدم).
كيف أتعامل مع انتهاء مهلة سكريبت exec source؟
زِد قيمة timeoutMs (الحد الأقصى 120000ms). السبب الأكثر شيوعاً هو أن الأمر الخارجي يحتاج حالة تسجيل دخول، مثل 1Password CLI الذي يحتاج op signin أولاً. يُنصح بإضافة منطق إعادة تسجيل الدخول تلقائياً في السكريبت، أو تخزين رمز الجلسة في ملف.
ما الفرق بين ملف .env وكتلة env في openclaw.json؟
ملف .env هو متغيرات بيئة على مستوى النظام تؤثر على جميع العمليات؛ كتلة env.vars في openclaw.json تؤثر فقط على عملية بوابة OpenClaw ولا تؤثر على البرامج الأخرى. كلاهما يدعم استخدام ${VAR_NAME} في حقول مثل apiKey. يُنصح باستخدام .env للبيانات الحساسة، وenv.vars للإعدادات الغير حساسة الخاصة بـ OpenClaw (مثل عنوان الوكيل).
هل يمكن وجود عدة ملفات إعداد في آنٍ واحد؟
يدعم OpenClaw دمج الإعداد ("mode": "merge")، لكن مسار ملف الإعداد الرئيسي ثابت عند ~/.openclaw/openclaw.json. يمكنك استيراد أجزاء إعداد أخرى عبر حقل import في openclaw.json لتحقيق إدارة معيارية للإعداد.