SSD Nodes Learn
الأدلة Matt Connorبقلم Matt Connor · آخر تحديث في 2026-07-22

شغّل Ollama على VPS: استضف LLM بنفسك

استضف LLM مفتوحًا بواسطة Ollama على VPS: تحجيم صادق لـ CPU، التثبيت، systemd، ولماذا لا تكشف المنفذ 11434 أبدًا، مع Open WebUI خلف TLS.

ما الذي تبنيه

نموذج لغوي واحد مفتوح الأوزان يعمل على خادم تملكه أنت، يُستدعى عبر واجهة برمجية HTTP، وإن أردت عبر صفحة محادثة في متصفحك. Ollama هو الجزء الذي يحمّل النموذج، ويضعه في الذاكرة، ويستجيب للطلبات على http://127.0.0.1:11434. التثبيت أمر واحد فقط. أما كل ما هو صعب هنا فيقع في مكان آخر: اختيار نموذج يستطيع VPS الخاص بك أن يحمله فعلًا في RAM، وعدم نشر خادم استدلال بلا مصادقة على الإنترنت كله بالخطأ.

تحذيران صادقان أولًا. خادم VPS يعمل بمعالج CPU فقط يشغّل النماذج الصغيرة ببطء، والواجهة البرمجية لا تملك أي مصادقة مدمجة على الإطلاق. كلاهما مشروح بالتفصيل أدناه، لأن كليهما الموضع الذي يتأذى فيه الناس.

واقع التحجيم، بأرقام واضحة

بصمة النموذج في الذاكرة تساوي تقريبًا حجم ملفه، زائد نحو غيغابايت واحد من عبء التشغيل، زائد قليلًا آخر لنافذة السياق. النماذج الافتراضية في Ollama مكمَّمة (quantized) على 4 بتات (تحمل التسمية Q4)، وهو ما يكلّف نحو نصف غيغابايت من RAM لكل مليار معلمة (parameter). الحساب إذن بسيط، وهو ما يحسم كل شيء.

نموذج بحجم 3B مثل llama3.2:3b تنزيله نحو 2 GB ويحتاج إلى نحو 4 GB من RAM الحرة ليعمل. نموذج بحجم 7B أو 8B مثل mistral:7b أو llama3.1:8b يشغل نحو 5 GB على القرص ويحتاج إلى نحو 8 GB من RAM، و16 GB ليعمل بارتياح. نموذج بحجم 13B أو 14B يحتاج إلى نحو 16 GB. أي شيء في مدى 30B إلى 70B يحتاج إلى جهاز بذاكرة RAM ضخمة أو، بواقعية، إلى GPU — فعلى VPS يعتمد على CPU فقط، إما أن النموذج لا يتّسع أصلًا أو يجيب ببطء شديد يجعله عديم الفائدة.

والآن السرعة، لأن هذا هو الجزء الذي يقلّل الناس من شأنه. الاستدلال (inference) على CPU مقيّد بعرض النطاق الترددي للذاكرة، لا بسرعة الساعة، وVPS بمعالج vCPU مشترك يملك عرض نطاق متواضعًا. توقّع رقمًا من خانة واحدة إلى عشرات منخفضة من tokens في الثانية: نموذج 7-8B بصيغة Q4 قد يبلغ 4 إلى 10 tokens في الثانية، ونموذج 3B من 10 إلى 25. أما GPU فأسرع بنحو رتبة حجم كاملة. هذه أرقام تقريبية عمدًا — والأصوب هو أن تقيس جهازك أنت، وهو ما تُظهر خطوة التشغيل أدناه كيفية القيام به. ثق بقيمة eval rate الخاصة بك، لا برقم في أي مقال، بما في ذلك هذا المقال.

الخلاصة العملية: النماذج الصغيرة المكمَّمة على CPU مفيدة فعلًا لكتابة المسودات والتلخيص والتصنيف إن كنت تقبل هذه الوتيرة. أما لأي شيء أكبر أو أسرع، فخصص ميزانية لخادم بمعالج GPU.

لموازنة نموذج معين مع جهاز معين، قدّر بصمته في الذاكرة هنا:

ToolLLM VRAM and model-size calculator

ثبّت Ollama

هناك طريقتان نظيفتان. السكربت الرسمي هو الأبسط على VPS نظيف تمامًا:

curl -fsSL https://ollama.com/install.sh | sh

هذا ينشئ مستخدم نظام باسم ollama، ويثبّت الملف التنفيذي في /usr/local/bin/ollama، ويسجّل خدمة systemd باسم ollama.service تبدأ عند الإقلاع وتستمع على 127.0.0.1:11434. تأكد من أنها تعمل:

systemctl status ollama
ollama --version

إن كنت تشغّل Docker فعلًا، فاستخدم الحاوية بدلًا من ذلك:

docker run -d --name ollama \
  -p 127.0.0.1:11434:11434 \
  -v ollama:/root/.ollama \
  --restart always \
  ollama/ollama

لاحظ البادئة 127.0.0.1: في تعيين المنفذ (port mapping). فهي تقصر المنفذ على localhost وحده. أما كتابة -p 11434:11434 بدلًا منها فتنشره على كل الواجهات، وهذا هو الخطأ الذي يحذّر منه قسم الأمان. اختر طريقة تثبيت واحدة؛ ولا تشغّل السكربت والحاوية في آن واحد، وإلا تنازعت العمليتان على المنفذ نفسه.

نزّل نموذجك الأول وشغّله

ollama pull llama3.2:3b
ollama run llama3.2:3b

الأمر pull ينزّل طبقات النموذج إلى القرص (نحو 2 GB لهذا النموذج). والأمر run يحمّلها في الذاكرة ويضعك أمام سطر الأوامر >>>. اكتب سؤالًا. قد يستغرق أول token عدة ثوانٍ ريثما تُحمَّل الأوزان من القرص إلى RAM، ثم تتدفق الإجابة بعدها. اكتب /bye لمغادرة المحادثة؛ ويبقى Ollama يعمل في الخلفية.

طالع ما هو محمَّل حاليًا وكيف يتناسب مع الذاكرة:

ollama ps

عمود PROCESSOR يكشف الحقيقة. القيمة 100% CPU تعني عدم تدخّل أي GPU، ومن هنا يأتي البطء. قِس السرعة الحقيقية بخيار verbose:

ollama run --verbose llama3.2:3b "Write two sentences about Linux."

السطر eval rate المطبوع في النهاية هو عدد tokens في الثانية على هذا العتاد. وهذا هو الرقم الذي تخطط على أساسه.

أين تُخزَّن النماذج، وكم مساحة القرص التي عليك شراؤها

عند التثبيت بالسكربت والتشغيل كخدمة، تُخزَّن النماذج في المجلد الرئيسي لمستخدم ollama:

sudo du -sh /usr/share/ollama/.ollama/models

أما عند التشغيل تفاعليًا بمستخدمك الخاص، فتقع في ~/.ollama/models. وفي الحاوية تُخزَّن في وحدة التخزين المسمّاة (named volume) ollama. هذا يهم لأن الأوزان المكمَّمة تتراكم بسرعة: نموذج 3B نحو 2 GB، ونموذج 7-8B نحو 5 GB، ونموذج 14B نحو 9 GB. نزّل أربعة نماذج لتقارن بينها وستكون قد أنفقت 20 GB دون أن تنتبه. حجِّم القرص وفق النماذج التي تنوي الاحتفاظ بها، واحذف الباقي بالأمر ollama rm <model>.

شغّله كخدمة تتحكم بها

سجّل سكربت التثبيت خدمة ollama.service بالفعل، فهي تعيد التشغيل عند الإقلاع دون أي جهد إضافي. الإعداد الذي يستحق التغيير هو المدة التي يبقى فيها النموذج مقيمًا في الذاكرة، وفي بعض الإعدادات عنوان الاستماع (bind address) أيضًا — وكلاهما يوضع في ملف drop-in ضمن systemd حتى لا تطغى عليه ترقية لاحقة لـ Ollama:

sudo systemctl edit ollama.service

أضف ما يلي تحت الترويسة [Service] التي يعرضها لك المحرر:

[Service]
Environment="OLLAMA_KEEP_ALIVE=30m"

OLLAMA_KEEP_ALIVE هو المدة التي يبقى فيها النموذج في الذاكرة بعد آخر طلب (القيمة الافتراضية 5 دقائق). ارفعها على جهاز تستعلمه طوال اليوم لتفادي إعادة تحميل الأوزان في كل مرة؛ واضبطها على 0 على جهاز ضيق الذاكرة لتحرير RAM لحظة انتهاء الطلب. الأمر systemctl edit يعيد تحميل ملفات الوحدة (unit files) نيابة عنك، فأعد التشغيل لتطبيق التغيير:

sudo systemctl restart ollama

نقطة الأمان الأهم على الإطلاق

بشكل افتراضي يستمع Ollama على 127.0.0.1:11434، بحيث لا تستطيع الوصول إليه إلا العمليات القائمة على VPS نفسه. هذا الإعداد الافتراضي صحيح. أبقِ عليه.

الواجهة البرمجية لا تملك أي مصادقة. لا شيء إطلاقًا. لا يوجد مفتاح API، ولا تسجيل دخول، ولا تحديد لمعدل الطلبات (rate limit)، ولا قائمة سماح (allow-list). فأي شخص يستطيع الوصول إلى المنفذ 11434 يمكنه تشغيل أي نموذج نزّلته أنت، أو تنزيل نماذج جديدة، أو حذفها، أو إبقاء CPU أو GPU لديك عند الحمل الأقصى إلى ما لا نهاية. أدوات مسح مثل Shodan تفهرس آلاف النسخ المفتوحة من Ollama، وأي نسخة مكشوفة تُكتشف وتُستغل خلال ساعات.

وهذا إذن هو الخطأ الوحيد الذي لا يجوز ارتكابه أبدًا: لا تضبط OLLAMA_HOST=0.0.0.0 وتفتح المنفذ 11434 في جدار حمايتك. فذلك ينشر خادم استدلال بلا مصادقة على الإنترنت بأسره. ولا يوجد قدر من الضبط يجعل المنفذ 11434 مفتوحًا على 0.0.0.0 آمنًا، لأنه لا يوجد في Ollama أصلًا ما يمكن ضبطه — فالمصادقة ببساطة غير موجودة.

توجد ثلاث طرق آمنة للوصول إلى النموذج من مكان آخر غير الجهاز نفسه:

  • أبقِه محليًا. إن كان المستدعي الوحيد برنامجًا آخر على VPS نفسه — سكربت cron، أو روبوت، أو خادم MCP يربط أدواتك بالنموذج — فاترك الاستماع على 127.0.0.1 واجعل ذلك البرنامج يستدعي http://127.0.0.1:11434. لا شيء مكشوف ولا حاجة إلى أي شيء آخر.
  • صل إليه عبر نفق خاص. ضع VPS على شبكة WireGuard VPN تستضيفها بنفسك، واضبط OLLAMA_HOST على عنوان النفق (مثلًا 10.8.0.1، لا 0.0.0.0)، وعندها لا يستطيع الاتصال إلا أقران VPN. أما الإنترنت العام فلا يرى شيئًا على المنفذ 11434.
  • ضع أمامه وكيلًا عكسيًا (reverse proxy) يفرض مصادقة. أنهِ اتصال TLS واطلب كلمة مرور أو token عند nginx أو Traefik أو Caddy، ثم مرِّر الطلبات إلى 127.0.0.1:11434. يبقى Ollama على استماعه المحلي؛ والوكيل العكسي هو الشيء الوحيد الذي يستمع على المنفذ العام. هذا هو الشكل نفسه الذي يأخذه وضع شهادة Let's Encrypt على nginx أمام أي خدمة محلية.

وخيار الوكيل العكسي هو بالضبط ما توفره لك واجهة المحادثة بعد قليل، مع تسجيل دخول حقيقي مرفق به.

أضف واجهة محادثة بواسطة Open WebUI، خلف TLS

Open WebUI واجهة محادثة مستضافة ذاتيًا. شغّلها في Docker ووجّهها نحو Ollama المحلي:

docker run -d \
  --name open-webui \
  --network=host \
  -e OLLAMA_BASE_URL=http://127.0.0.1:11434 \
  -v open-webui:/app/backend/data \
  --restart always \
  ghcr.io/open-webui/open-webui:main

الخيار --network=host هو التفصيل المهم على VPS يعمل بـ Linux. فهو يضع الحاوية في مساحة أسماء الشبكة (network namespace) الخاصة بالمضيف، بحيث يصبح 127.0.0.1 داخل الحاوية هو loopback المضيف نفسه، وتصل الحاوية إلى Ollama على 127.0.0.1:11434 دون أن يستمع Ollama على أي واجهة أخرى. أما وصفة شبكة bridge التي ستراها في أماكن أخرى — --add-host=host.docker.internal:host-gateway مع OLLAMA_BASE_URL=http://host.docker.internal:11434 — فلا تعمل هنا: فذلك الاسم يُحلَّل إلى بوابة bridge في Docker، وخدمة مرتبطة بـ 127.0.0.1 على المضيف لا يمكن الوصول إليها عبر الـ bridge، فتبقى Open WebUI عاجزة وتبلّغ بأنها لا تستطيع الاتصال بـ Ollama.

والمفاضلة في استخدام شبكة المضيف هي أن Open WebUI تستمع الآن على المنفذ 8080 الخاص بالمضيف على كل الواجهات؛ ويُتجاهَل أي تعيين -p، ويطبع Docker تحذيرًا بذلك. لذا أغلق المنفذ 8080 في جدار حماية المضيف وجدار حماية المزوّد معًا، ودع الوكيل العكسي عبر TLS هو الباب العام الوحيد. وفي أول زيارة تطلب منك Open WebUI إنشاء حساب مسؤول (admin) — وهذا الحساب هو طبقة المصادقة لديك، فاختر كلمة مرور قوية.

لفتح المحادثة من حاسوبك المحمول عبر HTTPS، ضع وكيلًا عكسيًا عبر TLS أمام 127.0.0.1:8080. وإن كنت توجّه بالفعل عدة تطبيقات Docker على الجهاز، فإن Traefik مع TLS تلقائي عبر تطبيقات عديدة هو الأنسب: كتلة تسميات (labels) واحدة تصدر الشهادة وتوجّه chat.example.com إلى Open WebUI. وتبقى القاعدة نفسها من قسم الأمان سارية: الوكيل هو من يملك المنفذ العام وتسجيل الدخول، بينما يبقى Ollama على localhost ويبقى المنفذ 8080 الخاص بـ Open WebUI محميًا بجدار الحماية.

استخدم نقطة النهاية المتوافقة مع OpenAI من كودك

يدعم Ollama جزءًا فرعيًا من واجهة محادثة OpenAI عند /v1، لذا تعمل معظم مكتبات عميل OpenAI بعد تغيير أمرين فقط: عنوان URL الأساسي، ومفتاح مؤقت لا قيمة حقيقية له.

from openai import OpenAI

client = OpenAI(base_url="http://127.0.0.1:11434/v1", api_key="ollama")

resp = client.chat.completions.create(
    model="llama3.2:3b",
    messages=[{"role": "user", "content": "Name three Linux distributions."}],
)
print(resp.choices[0].message.content)

الحقل api_key مطلوب من مكتبة العميل لكن Ollama يتجاهله، فأي نص يفي بالغرض. أما model فيجب أن يكون اسمًا نزّلته بالفعل؛ واسم غير معروف يعيد model "x" not found, try pulling it first. واستدعاء curl مباشر يقوم على الفكرة نفسها:

curl http://127.0.0.1:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"llama3.2:3b","messages":[{"role":"user","content":"Hello"}]}'

وهذه أيضًا الطريقة التي تربط بها النموذج بأدوات الوكلاء (agents) والمحررات. وإن كنت تطوّر بالفعل على الجهاز، يمكن لنموذج محلي أن يشغّل سكربتات وإضافات (plugins) جنبًا إلى جنب مع Claude Code يعمل على VPS داخل tmux، بحيث يبقى العمل الرخيص والخاص في كتابة المسودات بعيدًا عن API مدفوعة، بينما يبقى الاستدلال الثقيل مع نموذج مستضاف.

أنماط الفشل، مع النصوص الدقيقة التي ستراها

تكون العملية «Killed» في منتصف التوليد. تبدأ نموذجًا كبيرًا وتطبع الطرفية Killed، أو يُظهر سجل الخادم llama runner process has terminated: signal: killed. مدير نفاد الذاكرة في Linux (OOM killer) أوقف العملية لأن النموذج احتاج إلى RAM أكثر مما يملكه الجهاز. تأكد من السبب بالأمر sudo dmesg | grep -i oom، حيث سترى سطرًا شبيهًا بـ Out of memory: Killed process ... (ollama). والحل هو نموذج أصغر أو أشد تكميمًا (quantization) — llama3.2:3b بدلًا من نموذج 13B — أو إضافة swap حتى يبقى حِمل يتجاوز RAM الفعلية بقليل فقط حيًّا ببطء بدلًا من أن يموت. الـ swap يحوّل انهيارًا فوريًا إلى إجابة بطيئة؛ لكنه لا يجعل نموذج 70B عمليًا على 4 GB.

«Error: model requires more system memory». يرفض Ollama تشغيل النموذج ويطبع Error: model requires more system memory (X GiB) than is available (Y GiB). وهذه هي النسخة المهذّبة من الانهيار السابق: أجرى Ollama الحساب وتوقف بدلًا من ترك OOM killer يفعل ذلك. بل إنه يمنحك الرقمين مباشرة. اختر نموذجًا يقل احتياجه عن RAM الحرة لديك (تحقق بالأمر free -h)، أو قلّص طول السياق، أو انتقل إلى VPS أكبر. لا يوجد خيار (flag) يجعل النموذج يتّسع — فالذاكرة حقيقية.

أول token يستغرق وقتًا طويلًا جدًا، ثم يسير كل شيء بسلاسة. نموذج بارد (لم يُحمَّل بعد) لا يطبع شيئًا لمدة خمس إلى ثلاثين ثانية، ثم يتدفق بشكل طبيعي. هذا التوقف هو تحميل الأوزان من القرص إلى RAM للمرة الأولى، ويزيده التخزين البطيء سوءًا. وبمجرد أن يُحمَّل النموذج، يبقى مقيمًا طوال مدة OLLAMA_KEEP_ALIVE، فيجيب الطلب الثاني فورًا. ارفع تلك القيمة إن كانت الفجوات تزعجك، واستخدم ollama ps لترى إن كان نموذج ما محمَّلًا حاليًا.

كل شيء بطيء ببساطة. عشرة tokens في الثانية أو أقل، دون أي خطأ على الإطلاق. هذا هو الاستدلال على CPU يفعل بالضبط ما يفعله الاستدلال على CPU. يُظهر ollama ps القيمة 100% CPU، أي أنه لا يوجد GPU. هذا ليس خللًا ولا يصلحه أي إعداد، لأن الحد هنا هو عرض النطاق الترددي للذاكرة، لا سوء ضبط. استخدم نموذجًا أصغر، أو تقبّل السرعة، أو انتقل إلى خادم بمعالج GPU — وقِس معدلك الحقيقي بخيار --verbose قبل أن تقرر أن هناك عطلًا.

رفض الاتصال (Connection refused) من جهاز آخر. من حاسوبك المحمول تحصل على curl: (7) Failed to connect to <ip> port 11434: Connection refused. هذا يعمل تمامًا كما صُمم: Ollama يستمع على localhost فقط. لا «تُصلح» الأمر بربطه بـ 0.0.0.0، فذلك هو بالضبط خطأ الانكشاف المذكور أعلاه. صل إلى النموذج عبر VPN أو عبر الوكيل العكسي الذي يفرض مصادقة بدلًا من ذلك.

كشفت المنفذ 11434 على الإنترنت. إن ضبطت فعلًا OLLAMA_HOST=0.0.0.0، وفتحت جدار الحماية، وترى الآن عمليات تنزيل نماذج لم تبدأها أنت أو معالجًا عالقًا عند 100% بفعل عملاء مجهولين، فأنت مكتشَف ومُستغَل بالفعل. هذا هو الخطأ الرئيسي، لا حالة نادرة هامشية. أعد الربط بـ 127.0.0.1 أو عنوان VPN، وأغلق المنفذ 11434 في جدار الحماية، وضع مصادقة أمامه. افترض أن كل ما كان يمكن الوصول إليه على ذلك العنوان أثناء انفتاحه قد استعلمه غرباء.

النسخ الاحتياطي والترقيات

ليست هناك حالة (state) تُذكر لتخسرها. النماذج قابلة لإعادة التنزيل، لذا فإن الأشياء الوحيدة التي تستحق النسخ الاحتياطي هي وحدة تخزين بيانات Open WebUI — الحسابات، وسجل المحادثات، والإعدادات — وأي ملف drop-in ضمن systemd كتبته بنفسك. انسخ وحدة التخزين احتياطيًا بحاوية مؤقتة تُستخدم مرة واحدة:

docker run --rm -v open-webui:/data -v "$PWD":/backup alpine \
  tar czf /backup/open-webui.tgz -C /data .

رقِّ Ollama بإعادة تشغيل سكربت التثبيت؛ ورقِّ Open WebUI بالأمر docker pull ghcr.io/open-webui/open-webui:main ثم إعادة إنشاء الحاوية. لا تثبّت أي إصدار على المدى الطويل: فجودة النماذج وبيئة التشغيل كلاهما يتطوران بسرعة، لذا اقرأ ملاحظات الإصدار وأعد قياس الأداء على جهازك أنت بدلًا من الوثوق بأرقام الربع الماضي.

FAQ

هل يمكنني فعلًا تشغيل LLM على VPS بمعالج CPU فقط؟

نعم، ضمن حدود معينة. النماذج الصغيرة المكمَّمة في مدى 3B إلى 8B تعمل على CPU وهي مفيدة فعلًا لكتابة المسودات والتلخيص والتصنيف — لكن ببطء، بمعدل من خانة واحدة إلى عشرات منخفضة من tokens في الثانية على vCPU مشترك. أما كل ما هو من 13B فما فوق فبطيء بشكل مؤلم أو لا يتّسع في RAM إطلاقًا. للحصول على سرعة حقيقية أو نماذج أكبر تحتاج إلى خادم بمعالج GPU.

كم من RAM يحتاج كل نموذج؟

قاعدة تقريبية للنماذج الافتراضية المكمَّمة على 4 بتات: نحو 0.5 GB من RAM لكل مليار معلمة (parameter) للأوزان، زائد نحو 1 GB من عبء التشغيل، وقليلًا أكثر للسياق. فنموذج 3B يحتاج إلى نحو 4 GB حرة، ونموذج 7-8B إلى نحو 8 GB، ونموذج 14B إلى نحو 16 GB. تحقق من هامشك المتاح بالأمر free -h واترك مساحة لنظام التشغيل ولأي شيء آخر يعمل على الجهاز.

هل واجهة Ollama البرمجية مُصادَق عليها؟

لا. لا يملك Ollama أي مصادقة مدمجة، ولا مفتاح API، ولا تحديد لمعدل الطلبات — فأي شخص يستطيع الوصول إلى المنفذ 11434 يملك تحكمًا كاملًا فيه. ولهذا بالضبط يستمع افتراضيًا على 127.0.0.1، ولهذا يجب ألا تكشف المنفذ 11434 على 0.0.0.0 أمام الإنترنت أبدًا. صل إليه محليًا، أو عبر VPN خاص، أو عبر وكيل عكسي يضيف تسجيل دخول.

كيف أضيف واجهة محادثة على الويب؟

شغّل Open WebUI في Docker مع --network=host حتى تشارك loopback المضيف وتصل إلى Ollama الأصلي على http://127.0.0.1:11434، ثم ضع وكيلًا عكسيًا عبر TLS أمام المنفذ 8080 الخاص بها للوصول من حاسوبك المحمول. أبقِ المنفذ 8080 مغلقًا في جدار الحماية حتى يكون الوكيل هو الباب العام الوحيد. حساب المسؤول الخاص بـ Open WebUI يوفّر تسجيل الدخول، وأنت تضبط كلمة مروره عند أول تشغيل.

كيف أستدعيه من تطبيقي الخاص؟

استخدم نقطة النهاية المتوافقة مع OpenAI عند http://127.0.0.1:11434/v1. وجّه أي SDK من OpenAI نحو عنوان URL الأساسي هذا، ومرر أي نص كمفتاح API لأنه يُتجاهَل، واضبط model على اسم نزّلته بالفعل. كود OpenAI الموجود يعمل عادة دون تغيير باستثناء عنوان URL الأساسي والمفتاح.