1 / 17
🚀
الموديول 11 — النشر في الإنتاج

النشر في الإنتاج

من تجربة في الـ terminal لخدمة بتشتغل 24/7 — systemd، reverse proxy، TLS، لوجات، مراقبة، نسخ احتياطي، ترقية ورجوع
17 شريحة ثنائي اللغة تطبيق عملي
شريحة 2 — أهداف النشر
أهداف النشر: VPS أم Docker أم Serverless
القرار الأول: البوابة عملية دائمة stateful — مش request/response
ℹ️
الحكم العملي
حالة الاستخدام الغالبة للوكيل = «خدمة دائمة تستقبل رسائل».
المعيار VPS (systemd) Docker Serverless
State دائم بين الـ runs ✔ طبيعي ✔ volume ✘ لازم external store
تشغيل cron / scheduler ✔ ✔ ✘ غير مدعوم بشكل موثوق
WebSocket / اتصال طويل ✔ ✔ ✘ محدود
الموارد على Oracle Free tier ✔ 4 OCPU / 24 GB ✘ overhead بسيط ✘ مفيش free tier دائم
أمان العزل OS user منفصل ✔ الأقوى ✔
سرعة الإقلاع أسرع متوسط أبطأ (cold start)
سهولة الـ reproducibility بتتبع حالة الماكينة ✔✔ ✔✔
التكلفة على Oracle Free tier $0 $0 (على نفس الـ VM) $0 (تجريبي)
🖥️
Oracle Ampere A1
Ubuntu 24.04 aarch64 — VM.Standard.A1.Flex
🔒
الإعداد الآمن الافتراضي
خلي البوابة على loopback
⚠️
Out of capacity
السعة في الـ free tier محدودة
شريحة 3 — تجهيز الـ VM وتثبيت الوكيل
تجهيز الـ VM وتثبيت الوكيل
أول سطرين: تحدّث وحط build-essential للـ ARM. وآخر سطر: الـ linger
ℹ️
الخطوة صفر على الـ instance بتاع Oracle Ampere.
bash
# على الـ instance
sudo apt update && sudo apt upgrade -y
sudo apt install -y build-essential

# اسم مضيف واضح + linger (مهم جداً — شرحه تحت)
sudo hostnamectl set-hostname openclaw
sudo passwd ubuntu
sudo loginctl enable-linger ubuntu
🔑
loginctl enable-linger هو أهم سطر في الوحدة دي.
bash
# Hermes
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
hermes --version
hermes setup          # model + provider + API keys
hermes doctor         # لازم يخرج 0

# OpenClaw (اختياري — على نفس الجهاز بـ profile منفصل)
curl -fsSL https://openclaw.ai/install.sh | bash
source ~/.bashrc
openclaw --version
openclaw doctor
شريحة 4 — البوابة كـ systemd user service
تثبيت البوابة كـ systemd user service
الأوامر الموثّقة، واسم الـ unit: hermes-gateway.service أو openclaw-gateway.service
ℹ️
بعد ما تظبط القنوات، بتثبّت البوابة كخدمة.
bash
# Hermes — الـ subcommands الموثّقة
hermes gateway setup     # قنوات + allowlists
hermes gateway install   # systemd (Linux) / launchd (macOS)
hermes gateway start
hermes gateway status
hermes gateway list      # كل الـ profiles وحالة كل gateway (+ PID)

# OpenClaw — من الـ runbook الرسمي
openclaw gateway install
systemctl --user enable --now openclaw-gateway.service
openclaw gateway status

# الاستمرارية بعد logout
sudo loginctl enable-linger $(whoami)
الحاجة القيمة
اسم الـ unit (Hermes، default profile) hermes-gateway.service
اسم الـ unit (Hermes، profile مسمّى) hermes-gateway-.service
اسم الـ unit (OpenClaw) openclaw-gateway.service
سيرفر headless من غير desktop session ظبّط XDG_RUNTIME_DIR لو فشل
⚠️
لو الإصدار عندك مختلف
اتأكد بـ systemctl --user list-units | grep hermes.
شريحة 5 — جسم الـ unit والإعدادات المهمة
جسم الـ unit والإعدادات المهمة
الجسم مُدار كما هو في التوثيق — ولكل سطر فيه سبب
ℹ️
ده جسم الـ systemd user unit المُدار كما هو في التوثيق.
ini
[Unit]
Description=OpenClaw Gateway
After=network-online.target
Wants=network-online.target
StartLimitBurst=10
StartLimitIntervalSec=300

[Service]
ExecStart=/usr/local/bin/openclaw gateway --port 18789
Restart=always
RestartSec=5
RestartPreventExitStatus=78
TimeoutStopSec=330
TimeoutStartSec=30
SuccessExitStatus=0 143
OOMPolicy=continue
KillMode=mixed

[Install]
WantedBy=default.target
السطر الوظيفة
Restart=always إعادة تشغيل عند أي خروج — العمود الفقري للـ auto-restart
RestartSec=5 5 ثواني راحة بين المحاولات
RestartPreventExitStatus=78 أهم سطر أمني
TimeoutStopSec=330 يغطي أقصى drain + هامش تنظيف
SuccessExitStatus=0 143 يعتبر 143 خروجاً نظيفاً
KillMode=mixed SIGTERM للرئيسي، SIGKILL للمتبقي
OOMPolicy=continue النظام ما بيقفش — العملية بس بتتقفل
أقصى 10 محاولات في 5 دقائق، بعدين systemd/unit معلّق" data-en="max 10 attempts in 5 minutes, then the unit is parked">أقصى 10 محاولات في 5 دقائق
شريحة 6 — التعديل على الـ unit والعقود مع الـ supervisor
auto-restart والعقد مع الـ supervisor
exit 78 يمنع إعادة التشغيل، exit 75 بيطلبها — الاتنين عن قصد
⚠️
استخدم systemctl --user edit عشان تعدّل من غير ما تكسر الـ unit.
bash
# تعديل آمن على الـ unit المُدارة
systemctl --user edit openclaw-gateway.service
ℹ️
على أجهزة ARM والـ VM الصغيرة، التوثيق بينصح تضيف السطور دي.
ini
[Service]
Environment=OPENCLAW_NO_RESPAWN=1
Environment=NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache
TimeoutStartSec=90
🚨
عقد Hermes مع الـ supervisor: exit code 75
لو شغّلت البوابة بـ wrapper بيقطع الـ environment، استخدم --external-supervisor.
Two supervision layers
Process-level OpenClaw: loop watchdog Hermes: loop watchdog systemd-level Restart=always + Restart=on-failure / always RestartPreventExitStatus=78 exit 75 (Hermes) gateway_state: degraded -> supervisor restarts exit_reason: loop_liveness_watchdog stack dump kill -USR2 <pid> -> gateway_faulthandler.log (writes all thread stacks, keeps running)
شريحة 7 — فحوصات الصحة الحقيقية
فحوصات الصحة: «العملية شغّالة» مش دليل
البوابة ممكن تبقى process حيّة والمفيش adapter متصل — فالمشكلة الحقيقية end-to-end
ℹ️
الطبقة الأولى: حالة الـ unit نفسها.
bash
# Hermes
systemctl --user is-active hermes-gateway.service   # exit 0 = active
systemctl --user show hermes-gateway.service -p NRestarts   # عدد مرات إعادة التشغيل
systemctl --user reset-failed hermes-gateway   # لو معلّقة في failed state
hermes gateway status
hermes gateway list
hermes doctor                # exit 0 = مفيش مشاكل، exit 1 = في مشكلة

# OpenClaw — فحص أعمق
openclaw gateway status --deep          # system-level service scan
openclaw gateway status --require-rpc       # إثبات read-scope RPC، مش مجرد reachability
openclaw channels status --probe
⚠️
مؤشر تدهور مهم — stale heartbeat.
💡
الـ health check الحقيقية: probe end-to-end
الـ health check الحقيقية: probe end-to-end.
شريحة 8 — سكربت الـ health check
سكربت فحص صحة جاهز للإنتاج
أربع فحوصات: الوحدة، عاصفة الـ restarts، الـ API end-to-end، ومساحة القرص
ℹ️
السكربت بيرجّع exit 0 لو كل حاجة تمام.
bash
#!/usr/bin/env bash
# /usr/local/bin/agent-healthcheck
set -euo pipefail
rc=0

# 1) systemd active
systemctl --user is-active --quiet hermes-gateway.service \
  || { echo "FAIL: unit not active"; rc=1; }

# 2) no restart storm
n=$(systemctl --user show hermes-gateway.service -p NRestarts --value)
if [ "$n" -gt 3 ]; then echo "WARN: $n restarts"; fi

# 3) API server end-to-end (اختياري لو مفعّل)
if [ -n "${API_SERVER_KEY:-}" ]; then
  curl -sf --max-time 20 http://127.0.0.1:8642/v1/chat/completions \
    -H "Authorization: Bearer ***" \
    -H "Content-Type: application/json" \
    -d '{"model":"hermes-agent","messages":[{"role":"user","content":"ping"}]}' \
    >/dev/null || { echo "FAIL: API server unhealthy"; rc=1; }
fi

# 4) disk space
used=$(df --output=pcent / | tail -1 | tr -dc '0-9')
[ "$used" -gt 90 ] && { echo "FAIL: disk ${used}%"; rc=1; }

[ $rc -eq 0 ] && echo "OK"
exit $rc
ℹ️
اربطه بـ cron كل خمس دقايق.
bash
# كل 5 دقايق
*/5 * * * * /usr/local/bin/agent-healthcheck 2>&1 | tee -a ~/healthcheck.log
شريحة 9 — reverse proxy مع TLS
reverse proxy مع TLS
القاعدة الذهبية: الوكيل يظل على 127.0.0.1 — والـ proxy هو الوحيد على :443
🔐
القاعدة الذهبية
البوابة والـ API server يظلوا على loopback.
ℹ️
لو bind على lan أو tailnet، لازم shared secret.
caddyfile
# /etc/caddy/Caddyfile
agent.example.com {
    encode zstd gzip

    # WebSocket / streaming يحتاج headers صريحة
    reverse_proxy 127.0.0.1:8642 {
        flush_interval -1
        header_up Connection {>Connection}
        header_up Upgrade {>Upgrade}
    }

    log {
        output file /var/log/caddy/agent-access.log
        format json
    }
}
ℹ️
Caddy هو الخيار الموصى به — بياخد ويجدّد الشهادة لوحده.
bash
# تثبيت Caddy على Ubuntu 24.04 ARM
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
  | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
  | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install -y caddy

# تحقّق ثم أعد التحميل
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
curl -I https://agent.example.com
شريحة 10 — Nginx، قفل الشبكة، وتدوير اللوجات
Nginx وقفل الشبكة وتدوير اللوجات
البديل اليدوي لـ Caddy — ومهم: قفل الـ VCN على Oracle
ℹ️
لو فضّلت Nginx، خلّي الـ timeout كبير.
nginx
# /etc/nginx/sites-available/agent
server {
    listen 443 ssl http2;
    server_name agent.example.com;

    ssl_certificate     /etc/letsencrypt/live/agent.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/agent.example.com/privkey.pem;

    # مهم: الوقت كبير — نداءات الوكيل ممكن تاخد دقايق
    proxy_read_timeout  600s;
    proxy_buffering     off;          # للـ SSE streaming
    client_max_body_size 100M;

    location / {
        proxy_pass         http://127.0.0.1:8642;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade           $http_upgrade;
        proxy_set_header   Connection        "upgrade";
    }
}
bash
sudo apt install -y nginx certbot python3-certbot-nginx
sudo ln -s /etc/nginx/sites-available/agent /etc/nginx/sites-enabled/
sudo nginx -t
sudo certbot --nginx -d agent.example.com
sudo systemctl reload nginx
⚠️
قفل الـ VCN على Oracle — خطوة مش اختيارية
احذف كل ingress إلا Tailscale UDP 41641.
ini
# تدوير اللوجات — journald لازم persistent على الإنتاج
# /etc/systemd/journald.conf.d/agent.conf
[Journal]
Storage=persistent
SystemMaxUse=2G
MaxRetentionSec=30day
Compress=yes
شريحة 11 — قراءة اللوجات والتدوير
اللوجات: قراءة، تدوير، وسرّية
RotatingFileHandler بتدور لوحدها — والـ journal لازم persistent
ℹ️
Hermes بيخزّن اللوجات في ~/.hermes/logs/.
bash
# hermes logs
hermes logs                       # آخر 50 سطر من agent.log
hermes logs -f                    # real-time
hermes logs gateway -n 100        # آخر 100 سطر من gateway.log
hermes logs --level WARNING --since 1h
hermes logs errors --since 30m -f
hermes logs list                  # كل ملفات اللوج + أحجامها

# journalctl على إنتاج
sudo systemctl restart systemd-journald
journalctl --disk-usage
journalctl -u hermes-gateway.service --since today
journalctl -u 'hermes-gateway*' --since 1h -p err
journalctl -u hermes-gateway.service --since 1h -o json > /tmp/j.json
⚠️
لا تسجّل الأسرار.
bash
# كشف تسريب محتمل لأسرار في اللوجات
journalctl -u hermes-gateway.service -p warning --since 1d \
  | grep -iE 'api[_-]?key|token|password' && echo "🔴 possible secret leak"
شريحة 12 — المراقبة والتنبيه
المراقبة والتنبيه
الأرقام اللي لازم تراقبها — والتنبيه لازم يوصل القناة اللي المستخدم بيشوفها
المقياس الطريقة العتبة
العملية حية systemctl --user is-active ≠ active ⇒ alert
عدد الـ restarts NRestarts > 3 في ساعة ⇒ alert
Gateway state عمر gateway_state.json > 120s ⇒ stale ⇒ restart
القرص df --output=pcent > 90% ⇒ alert
الذاكرة (ARM) free -m swap thrash
القنوات openclaw channels status --probe أي قناة مش probe ⇒ alert
التكلفة hermes insights تجاوز الميزانية
⚠️
راقب الـ filesystem بنفسك على Oracle Free tier.
bash
# تنبيه متعدد القنوات — دايم بلّغ المستخدم على القناة
hermes send --to telegram "[ALERT] gateway down on $(hostname)"
hermes send --to discord:#ops --subject "[ALERT] agent degraded"
curl -d "gateway down on $(hostname)" https://ntfy.sh/your-topic-alerts
💡
REST 200 مش دليل صحة
Hermes بيجمع ready state + حالة الـ socket + عمر الـ heartbeat ACK + صمت الأحداث.
شريحة 13 — الشفاء الذاتي
الاستجابة التلقائية (self-healing)
سكربت بيعمل restart تلقائي، وبيحميك من حلقة لا نهائية بـ exit storm
ℹ️
السكربت بيشتغل من cron كل بضع دقايق.
bash
#!/usr/bin/env bash
# /usr/local/bin/agent-autofix
set -euo pipefail

if ! systemctl --user is-active --quiet hermes-gateway.service; then
  n=$(systemctl --user show hermes-gateway.service -p NRestarts --value)
  if [ "$n" -ge 5 ]; then
    # exit storm — متحاولش تعمل loop لا نهائي
    hermes send --to telegram "🔴 gateway dead ($n restarts) — manual intervention needed"
    exit 1
  fi
  hermes send --to telegram "🟡 gateway down, restarting…"
  systemctl --user restart hermes-gateway.service
  sleep 15
  if systemctl --user is-active --quiet hermes-gateway.service; then
    hermes send --to telegram "🟢 gateway recovered"
  else
    hermes send --to telegram "🔴 restart failed — see journalctl -u hermes-gateway"
  fi
fi
🚫
الإيقاف الطارئ
hermes pause بيوقف الـ cron الجديد و gateway turns — وhermes resume يرجّعه.
bash
hermes pause     # مفيش cron جديد + مفيش kanban dispatch + مفيش gateway turns
hermes resume    # يرجّع
شريحة 14 — النسخ الاحتياطي وتحسين التكلفة
النسخ الاحتياطي وتحسين التكلفة
القاعدة رقم 1: النسخة اللي متنسخش على نفس الجهاز مش نسخة
ℹ️
hermes backup WAL-safe بـ SQLite backup() API.
bash
# Hermes — أداة backup مدمجة
hermes backup                                  # zip كامل → ~/hermes-backup-<ts>.zip
hermes backup -o /var/backups/agent.zip
hermes backup --quick                          # config, state.db, .env, auth, cron
hermes backup --quick --label pre-upgrade
hermes backup --keep 5                         # احتفظ بآخر 5 (default 3، 0 = الكل)
hermes import                                  # استرجع من zip

# OpenClaw — نسخ ما قبل الترحيل بتتعمل تلقائي
openclaw gateway status --deep
openclaw doctor
openclaw secrets reload
ℹ️
OpenClaw بينسخ قاعدة البيانات قبل أي ترحيل.
bash
# النسخة اللي على نفس الجهاز مش نسخة — استخدم الجهاز التاني كـ replica
rsync -avz --delete \
  /var/backups/agent/ \
  ubuntu@hermes-2:/var/backups/agent-replica/

# تشفير قبل ما النسخة تغادر الجهاز
tar czf - /var/backups/agent | gpg --encrypt --recipient ops@example.com > /tmp/agent-enc.tar.gz.gpg

# 3-2-1: 3 نسخ، 2 وسائط مختلفة، 1 نسخة برّه الموقع
find "$DEST" -type f -mtime +30 -delete
💡
تحسين التكلفة على Oracle Free tier
الـ Always Free tier بيدّيك 4 OCPU / 24 GB / 200 GB — يعني السيرفر بتاعك بـ $0.
شريحة 15 — الترقية والرجوع
الترقية والرجوع
Hermes بيعمل snapshot لكل profile + syntax validation + rollback تلقائي لو الكود اتكسر
ℹ️
الترقية بتمشي كده: snapshot ← pull ← validation ← install ← migration.
bash
# Hermes
hermes update              # آخر كود من main + dependencies + config migration
hermes update --check      # preview بدون install
hermes update --backup     # full zip قبل الـ pull
hermes config check        # أي options جديدة ناقصة
hermes config migrate      # أضفها تفاعلياً
hermes update --status     # read-only

# OpenClaw
openclaw update                    # يكتشف النوع + يجيب آخر نسخة + doctor + restart
openclaw update --dry-run
openclaw update --channel extended-stable   # exact pins، fails closed
⚠️
الـ snapshot السريع مش تأمين كود
الـ snapshot السريع = file-loss recovery، مش code-rollback insurance.
bash
# بعد الترقية على السيرفر
sudo loginctl enable-linger $USER
hermes gateway restart --all     # كل الـ profiles
hermes gateway list
hermes doctor                    # لازم exit 0

# Rollback
git -C ~/.hermes/hermes-agent log --oneline -5
git -C ~/.hermes/hermes-agent reset --hard <good-sha>
hermes import /var/backups/agent/hermes-full-<ts>.zip
شريحة 16 — التوسّع لأكتر من VPS والمقارنة
جهازان Oracle Ampere + iMac: العزل والمقارنة
تقسيم الأدوار، العزل، وOpenClaw مقابل Hermes في الإنتاج
Two Ampere boxes + iMac over a Tailscale tailnet
VPS-1 (Oracle Ampere A1) VPS-2 (Oracle Ampere A1) Hermes gateway :18789/:8642 Hermes gateway :18789/:8642 • Telegram • Email • Discord • Slack • rescue bot • production — canonical data • ops + backup replica \ / \__ Tailscale tailnet _/ | iMac — nodes / admin
bash
# العزل عبر الأجهزة — Tailscale
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --ssh --hostname=hermes-1
sudo tailscale up --ssh --hostname=hermes-2

# OpenClaw على Tailscale Serve
openclaw config set gateway.bind loopback
openclaw config set gateway.auth.mode token
openclaw doctor --generate-gateway-token
openclaw config set gateway.tailscale.mode serve
openclaw config set gateway.trustedProxies '["127.0.0.1"]'

# Rescue bot بـ profile ومنفذ منفصلين
openclaw --profile rescue gateway install --port 19789
hermes profile create rescue
⚠️
قاعدة المسافات بين المنافذ
OPENCLAW_STATE_DIR لوحده مش بيعزل خدمة مُدارة.
العنصر OpenClaw Hermes Agent
الـ bind الافتراضي loopback 127.0.0.1
Exit يمنع الـ restart 78 (config error) ✘ مفيش — بل 75 بيطلب restart
أداة backup ✘ مفيش أداة مستقلة ✔ hermes backup
Code auto-rollback ✘ ✔ git reset --hard
المراقبة فحص نظامي عميق stale heartbeat
Liveness دقيق ✘ ✔ knobs
إرسال بدون LLM openclaw message send hermes send
إيقاف طارئ ✘ ✔ hermes pause
التكلفة على Free tier $0 $0
متى تختاره container image، rescue bot backup بأمر واحد
ℹ️
مفيش failover تلقائي — الـ rescue bot مش HA حقيقي.
شريحة 17 — المشروع العملي والاختبار
المشروع العملي والاختبار
انشر وكيل إنتاجي كامل على Oracle Ampere — والاختبار النهائي
🚀
المشروع: نشر وكيل إنتاجي كامل (ساعتين)
انشر وكيل إنتاجي حقيقي على واحد من جهازين Oracle Ampere.
المرحلة الهدف الدليل
1 — تجهيز VM تحديث + build-essential + linger + ufw loginctl show-user ubuntu | grep Linger
2 — التثبيت الوكيل + القنوات hermes doctor exit 0
3 — الخدمات systemd unit + hardening على loopback systemctl --user is-active
4 — TLS reverse proxy بشهادة curl -I https://…
5 — المراقبة health check + alert + autofix /usr/local/bin/agent-healthcheck
6 — النسخ backup يومي + restore test + replica sqlite3 … integrity_check
7 — الصيانة dry-run ترقية + readiness prod-readiness
❓ اختبار — 5 أسئلة
النتيجة: 0/5
Q1: البوابة شغّالة من جوه SSH، بس أول ما أقفل الـ SSH بتموت. الخدمة متثبّتة صح. إيه السبب والحل؟
systemd user service محتاج linger
الـ binary محتاج recompile
sshd بيقتل العمليات
محتاجة tmux
Q2: البوابة في production طلع منها exit code 78 وفضلت ميتة، و systemd مش بيعيد التشغيل. ده bug ولا سلوك مقصود؟
سلوك مقصود — config error
bug في systemd
نفاد الذاكرة (OOM)
StartLimitBurst اتreach
Q3: عملت restart للبوابة بـ wrapper بيقطع الـ environment، وبعدين لقتها واقفة خالص. إيه اللي فاتك؟
محتاج --external-supervisor
لازم Restart=always
daemon-reload
gateway install تاني
Q4: hermes backup في الـ cron رجع exit 1 والـ zip موجود. إيه اللي حصل؟
Backup incomplete — والـ --keep ما اشتغلش
القرص امتلأ
exit 1 = مفيش backup
exit 2 والـ zip ميتالف
Q5: عايز بوت إنقاذ على الجهاز الثاني معزول تماماً. إيه اللي ممكن تعمله واللي لأ؟
profile مسمّى + منفذ فريد
STATE_DIR مختلف
EnvironmentFile مختلف
منفذ تاني على نفس الـ profile