لنفرض أن لديك متجراً أو شركة صغيرة، فسوف تجد أن عميلاً يسألك في نافذة الدردشة على الموقع، وآخر يرسل بريداً إلى عنوان الدعم، وثالثاً يكتب لك على WhatsApp، وكل رسالة من هذه الرسائل تصل إلى أداة مختلفة وإلى شخص مختلف في فريق الدعم Support Team، فتضيع بعض المحادثات Conversations بين هذه الأدوات، ويرد موظفان على العميل نفسه، ولا يعرف أحد هل تم الرد على العميل الثالث أم لا.
والحل الأول الذي يخطر على البال هو أن تجمع هذه القنوات في مجموعة دردشة داخلية يتابعها الفريق كله، وهذا يعمل في الأسبوع الأول، ولكنه يفشل بسرعة لأنه لا يوجد توزيع للمحادثات على الموظفين، ولا يوجد سجل لكل عميل، ولا توجد تقارير تعرف منها كم محادثة بقيت دون رد. والحل الثاني هو الاشتراك في خدمة سحابية Cloud Service مثل Intercom أو Zendesk أو Freshdesk، وهي خدمات ممتازة ولكن تكلفتها تزيد مع كل موظف تضيفه، وتبقى محادثات عملائك وبياناتهم على خوادم شركة أخرى.
لذلك فالحل الأنسب لمن يريد أن تبقى هذه البيانات عنده هو Chatwoot، وهي منصة مفتوحة المصدر Open Source لخدمة العملاء Customer Service تستضيفها على سيرفرك Self-hosted، وتجمع قنوات التواصل Channels كلها في صندوق وارد Inbox واحد، ومن هذه القنوات الدردشة المباشرة Live Chat على موقعك، والبريد الإلكتروني Email، وWhatsApp، وTelegram، وFacebook وInstagram، وSMS، ويمكنك أيضاً أن تضيف قنوات مخصصة Custom Channels عبر الـ API. وبعد ذلك يرى فريقك المحادثات كلها في مكان واحد، ويوزعها على الموظفين Agents والفرق، ويعمل بالردود الجاهزة Canned Responses والملاحظات الداخلية Private Notes والأتمتة Automation والتقارير Reports، وفي Chatwoot أيضاً مركز مساعدة Help Center تنشر فيه مقالات الأسئلة الشائعة FAQ.
وقد يتساءل البعض: هل Chatwoot مجاني بالكامل، أم أن الميزات المهمة مقفلة خلف اشتراك؟ والإجابة أن Chatwoot يأتي في نسختين من المستودع نفسه، النسخة المجتمعية Community Edition وهي مجانية وفيها كل ما يشرحه هذا الدليل من القنوات والصناديق والموظفين والأتمتة والتقارير، والنسخة المؤسسية Enterprise Edition وهي مدفوعة بترخيص License لكل موظف في الشهر، وفيها ميزات إضافية مثل إزالة شعار Chatwoot من الواجهة White Labeling، وإدارة اتفاقيات مستوى الخدمة SLA، وسجل التدقيق Audit Logs، والأدوار المخصصة Custom Roles، والمساعد الذكي Captain. والـ Image chatwoot/chatwoot:v4.18.0 التي سوف نستخدمها تحمل الكود المؤسسي أيضاً، ولكن ميزاته تبقى مقفلة حتى تشتري الترخيص من لوحة مدير المنصة، وبالتالي تعمل معك النسخة المجتمعية دون أي خطوة إضافية.
وتذكر أن Chatwoot أداة محادثات أكثر منه نظام تذاكر Ticketing System تقليدياً فيه مراحل موافقة Approval Workflows معقدة، فإذا كنت تحتاج إلى نظام ITSM كامل فيه إدارة الأصول Asset Management واتفاقيات SLA متشعبة فابحث عن أداة متخصصة، وتذكر أيضاً أن Chatwoot تطبيق Rails ثقيل نسبياً، فهو يحتاج إلى ذاكرة Memory كافية وإلى بعض المتابعة عند كل ترقية Upgrade.
وسوف نناقش في هذا المقال ما يلي:
- تشغيل Chatwoot باستخدام Docker Compose مع PostgreSQL التي تحمل امتداد pgvector، وRedis بكلمة مرور، وتوليد الأسرار وكتابة ملف
.env. - تهيئة قاعدة البيانات بالأمر
db:chatwoot_prepare، ولماذا يتوقف التطبيق إذا نسيت هذه الخطوة. - ربط النطاق مع شهادة TLS عبر الـ Reverse Proxy مع تمرير اتصال WebSocket، ثم إنشاء حساب المدير ونافذة الدردشة على موقعك وإعداد البريد والتخزين.
- النسخ الاحتياطي والاستعادة، والتحديث إلى إصدار أحدث، وأشهر المشكلات وحلولها.
ما تحتاجه قبل أن تبدأ Requirements
- سيرفر Linux بمعالجين CPU وذاكرة RAM بحجم 4 GB على الأقل لفريق صغير، ومساحة قرص Disk Space بحجم 20 GB أو أكثر بحسب حجم المرفقات Attachments التي يرسلها العملاء والموظفون.
- Docker Engine مع ملحق Docker Compose، وإذا لم يكونا مثبتين فاتبع دليل تثبيت Docker على Ubuntu.
- نطاق فرعي Subdomain مثل
chat.example.comبسجل A يشير إلى السيرفر (203.0.113.10)، وReverse Proxy يصدر شهادة TLS مثل Nginx Proxy Manager. - حساب SMTP يرسل منه Chatwoot دعوات الموظفين ورسائل إعادة تعيين كلمة المرور Password Reset وإشعارات Notifications المحادثات، مثل صندوق
[email protected]على خادم mailcow أو خدمة إرسال خارجية. - لا تفتح من المنافذ Ports إلا 80 و443 للـ Reverse Proxy، والسبب أن منفذ Chatwoot (3000) يجب أن يبقى على العنوان
127.0.0.1فقط فلا يصل إليه أحد إلا عبر الـ Reverse Proxy.
كيف يعمل Chatwoot من الداخل Architecture
سوف نشغل أربع خدمات، اثنتان منها من الـ Image نفسها الخاصة بـ Chatwoot، والجدول التالي يبين دور كل خدمة:
| الخدمة | الـ Image | الدور |
|---|---|---|
rails | chatwoot/chatwoot:v4.18.0 | الواجهة Frontend والـ API واتصال WebSocket (ActionCable) على المنفذ 3000 |
sidekiq | الـ Image نفسها | المهام الخلفية Background Jobs مثل إرسال البريد، واستقبال رسائل القنوات، والأتمتة، والإشعارات |
postgres | pgvector/pgvector:0.8.6-pg16 | قاعدة البيانات Database، ويحتاج Chatwoot 4 إلى الامتداد Extension vector لأن مخطط قاعدة البيانات Schema نفسه يفعله ويستخدمه في البحث الدلالي Semantic Search وميزات الذكاء الاصطناعي، وبالتالي فهو مطلوب حتى لو لم تستخدم هذه الميزات، لذلك نستخدم الـ Image الخاصة بـ pgvector بدلاً من الـ Image العادية لـ postgres |
redis | redis:8.10.2-alpine | طوابير Queues الخاصة بـ Sidekiq، والتخزين المؤقت Cache، وحالة الاتصال الفوري Real-time |
تثبيت Chatwoot خطوة بخطوة Installation
مجلد التثبيت
سوف نتبع هنا دليل النشر Deployment الرسمي عبر Docker، مع بعض التعديلات التي نشرح سبب كل واحد منها في مكانه، وأول خطوة هي أن ننشئ مجلد التثبيت:
sudo mkdir -p /opt/chatwoot
cd /opt/chatwootتوليد الأسرار Secrets
يحتاج Chatwoot إلى مفتاح طويل اسمه SECRET_KEY_BASE يوقع به الجلسات Sessions والـ Cookies والتوكنات Tokens، ويحتاج أيضاً إلى كلمتي مرور، واحدة لقاعدة البيانات والأخرى لـ Redis، ولا تقم بكتابة هذه القيم بيدك والسبب أن الكلمات التي نختارها بأنفسنا أسهل في التخمين، لذلك نولدها عشوائياً بالأمر التالي:
echo "SECRET_KEY_BASE=$(openssl rand -hex 64)"
echo "POSTGRES_PASSWORD=$(openssl rand -hex 24)"
echo "REDIS_PASSWORD=$(openssl rand -hex 24)"ملف .env
الملف الرسمي .env.example في المستودع Repository يشرح كل متغير بيئة Environment Variable، ولكنه طويل ولن تحتاج إلى أغلبه، لذلك وضعنا هنا القيم التي يحتاجها تثبيت إنتاجي Production أساسي، وكل ما عليك هو أن تغير النطاق Domain وبيانات SMTP وتضع القيم المولدة في مكانها:
sudo nano /opt/chatwoot/.env# التطبيق
SECRET_KEY_BASE=ضع_القيمة_المولدة
FRONTEND_URL=https://chat.example.com
DEFAULT_LOCALE=en
FORCE_SSL=false
ENABLE_ACCOUNT_SIGNUP=false
RAILS_ENV=production
NODE_ENV=production
INSTALLATION_ENV=docker
RAILS_MAX_THREADS=5
RAILS_LOG_TO_STDOUT=true
LOG_LEVEL=info
# قاعدة البيانات
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_DATABASE=chatwoot
POSTGRES_USERNAME=chatwoot
POSTGRES_PASSWORD=ضع_القيمة_المولدة
# Redis
REDIS_URL=redis://redis:6379
REDIS_PASSWORD=ضع_القيمة_المولدة
# البريد الصادر
MAILER_SENDER_EMAIL=Example Co Support <[email protected]>
SMTP_DOMAIN=example.com
SMTP_ADDRESS=smtp.example.com
SMTP_PORT=587
[email protected]
SMTP_PASSWORD=كلمة_مرور_SMTP
SMTP_AUTHENTICATION=login
SMTP_ENABLE_STARTTLS_AUTO=true
SMTP_OPENSSL_VERIFY_MODE=peer
# التخزين
ACTIVE_STORAGE_SERVICE=local
# إشعارات تطبيقات الهاتف الرسمية
ENABLE_PUSH_RELAY_SERVER=trueفي الإعداد أعلاه لاحظ التالي:
FRONTEND_URLهو العنوان العام Public URL الذي يفتحه المستخدمون، ومنه يبني Chatwoot الروابط في رسائل البريد وكود نافذة الدردشة Widget Script، لذلك إذا قمت بتغييره لاحقاً فعليك أن تنسخ كود الدردشة إلى موقعك من جديد.- القيمة
FORCE_SSL=falseمقصودة، والسبب أن الـ Reverse Proxy هو الذي ينهي اتصال TLS (TLS Termination) ثم يمرر الطلب إلى Chatwoot داخلياً عبر HTTP، وهو أيضاً الذي يقوم بالتحويل Redirect من HTTP إلى HTTPS. ENABLE_ACCOUNT_SIGNUP=falseيمنع الزوار من إنشاء حسابات بأنفسهم، فأنت الذي تضيف الموظفين عن طريق الدعوات Invitations.- إذا كان خادم البريد يقبل الاتصال دون مصادقة Authentication وChatwoot يرسل بيانات المصادقة فسوف يفشل الإرسال، والعكس كذلك، لذلك اضبط
SMTP_AUTHENTICATIONبما يوافق خادمك (loginأوplain)، ولا تتركSMTP_USERNAMEوSMTP_PASSWORDفارغين إلا مع خادم لا يطلب المصادقة.
وبعد ذلك اجعل الملف مقروءاً للمالك فقط، لأن فيه كل أسرار التثبيت:
sudo chmod 600 /opt/chatwoot/.envملف docker-compose.yml وشرح ما فيه
بنينا هذا الملف على الملف الرسمي docker-compose.production.yaml، والملف الرسمي يستخدم الوسم latest وينشر منفذي PostgreSQL وRedis على السيرفر ولا ينتظر جاهزية قاعدة البيانات، لذلك قمنا بتعديله، والملف سوف يكون كما يلي:
sudo nano /opt/chatwoot/docker-compose.ymlname: chatwoot
x-chatwoot: &chatwoot
image: chatwoot/chatwoot:v4.18.0
env_file: .env
volumes:
- storage_data:/app/storage
restart: unless-stopped
services:
rails:
<<: *chatwoot
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
ports:
- "127.0.0.1:3000:3000"
entrypoint: docker/entrypoints/rails.sh
command: ["bundle", "exec", "rails", "s", "-p", "3000", "-b", "0.0.0.0"]
sidekiq:
<<: *chatwoot
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
command: ["bundle", "exec", "sidekiq", "-C", "config/sidekiq.yml"]
postgres:
image: pgvector/pgvector:0.8.6-pg16
restart: unless-stopped
environment:
POSTGRES_DB: chatwoot
POSTGRES_USER: chatwoot
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U chatwoot -d chatwoot"]
interval: 10s
timeout: 5s
retries: 10
redis:
image: redis:8.10.2-alpine
restart: unless-stopped
command: ["sh", "-c", "exec redis-server --requirepass \"$$REDIS_PASSWORD\" --appendonly yes"]
environment:
REDIS_PASSWORD: ${REDIS_PASSWORD:?set REDIS_PASSWORD in .env}
volumes:
- redis_data:/data
healthcheck:
test: ["CMD-SHELL", "redis-cli -a \"$$REDIS_PASSWORD\" --no-auth-warning ping | grep -q PONG"]
interval: 10s
timeout: 5s
retries: 10
volumes:
storage_data:
postgres_data:
redis_data:في الإعداد أعلاه لاحظ التالي:
- ثبتنا الوسوم Tags على إصدارات محددة بدلاً من
latest، والسبب أنlatestقد يرقي التطبيق دون أن تشعر عند أولdocker compose pull، والترقية في Chatwoot تحتاج إلى خطوة ترحيل Migration كما سيأتي. - أضفنا فحوص الصحة Healthchecks لقاعدة البيانات وRedis، وجعلنا
railsوsidekiqينتظران حالةservice_healthy، فلا يبدأ التطبيق قبل أن تكون قاعدة البيانات جاهزة لاستقبال الاتصال. - منفذ الواجهة مربوط بالعنوان المحلي Localhost فقط (
127.0.0.1:3000)، وأزلنا نشر منفذي PostgreSQL وRedis على المضيف Host بالكامل، لأن التطبيق يصل إليهما عبر شبكة Compose الداخلية ولا يحتاج أحد غيره إليهما. - يقرأ Compose قيمتي
POSTGRES_PASSWORDوREDIS_PASSWORDمن ملف.envنفسه، فتبقى كلمات المرور في مكان واحد، وتأكد أن اسم المستخدم فيPOSTGRES_USERيطابقPOSTGRES_USERNAMEفي.env.
تهيئة قاعدة البيانات Initialization والتشغيل
هنا يخطئ كثيرون، فالطريقة التي تخطر على البال هي أن تشغل الخدمات كلها مباشرة بالأمر docker compose up -d، وهذه الطريقة سوف تفشل لأن الـ Container rails لا ينشئ جداول Tables قاعدة البيانات بنفسه، فتتوقف الواجهة بأخطاء عن جداول غير موجودة. والطريقة الصحيحة هي أن تشغل قاعدة البيانات وRedis أولاً، ثم تنفذ مهمة التهيئة في Container مؤقت كما يلي:
cd /opt/chatwoot
sudo docker compose pull
sudo docker compose up -d postgres redis
sudo docker compose run --rm rails bundle exec rails db:chatwoot_prepareوالمهمة db:chatwoot_prepare تنشئ قاعدة البيانات إذا لم تكن موجودة وتحمل المخطط كاملاً، وإذا كانت القاعدة موجودة فإنها تنفذ الترحيلات migrations الجديدة فقط، لذلك سوف تستخدم الأمر نفسه في كل ترقية. وقد ترى في بداية المخرج تحذيراً مثل relation "installation_configs" does not exist، وهذا متوقع في التشغيل الأول لأن الجداول لم تنشأ بعد، وبعد انتهاء المهمة قم بتشغيل الخدمات كلها:
sudo docker compose up -d
sudo docker compose psثم تأكد أن التطبيق يستجيب، وأن اتصاله بقاعدة البيانات وRedis سليم:
curl -s http://127.0.0.1:3000/apiوالمخرج سوف يكون كما يلي:
{"version":"4.18.0","timestamp":"2026-09-26 13:17:19","queue_services":"ok","data_services":"ok"}الوصول عبر النطاق مع شهادة TLS
يقوم Chatwoot بتحديث المحادثات فوراً في لوحة الموظفين Agent Dashboard وفي نافذة الدردشة Chat Widget عند العميل عبر اتصال WebSocket على المسار /cable، لذلك يجب أن يمرر الـ Reverse Proxy هذا الاتصال، وإلا فلن يرى الموظف الرسالة الجديدة إلا بعد أن يحدث الصفحة. وإذا كان Chatwoot وNginx Proxy Manager على السيرفر نفسه، وNPM يعمل بشبكة المضيف Host Network أو يصل إلى 127.0.0.1، فأنشئ Proxy Host بهذه القيم:
- Domain Names:
chat.example.com - Forward Hostname / IP و Port: عنوان السيرفر الداخلي و
3000، أو اسم الـ Containerrailsإذا قمت بربط NPM بشبكة Chatwoot - فعل Websockets Support وBlock Common Exploits، ثم اطلب من تبويب SSL شهادة Let's Encrypt مع Force SSL وHTTP/2.
ولأن الموظفين والعملاء يرفعون مرفقات، فعليك أن ترفع الحد الأقصى لحجم الطلب Request Size Limit من تبويب Advanced:
client_max_body_size 50m;
proxy_read_timeout 300s;وإذا كنت تستخدم Caddy فيكفي هذا الإعداد القصير، لأن Caddy يمرر WebSocket ويصدر الشهادة تلقائياً:
chat.example.com {
reverse_proxy 127.0.0.1:3000
}وبعد تفعيل النطاق تأكد أن قيمة FRONTEND_URL في .env هي https://chat.example.com، ثم أعد إنشاء الـ Containers حتى تقرأ القيمة الجديدة:
cd /opt/chatwoot
sudo docker compose up -d --force-recreate rails sidekiqالإعداد الأول بعد التثبيت
إنشاء حساب المدير Admin
افتح https://chat.example.com، وفي الزيارة الأولى سوف ينقلك Chatwoot إلى الصفحة /installation/onboarding لتنشئ أول مستخدم، وهذا المستخدم يصبح مدير المنصة Super Admin ومدير أول حساب Account، فأدخل اسمك واسم الشركة وبريدك وكلمة مرور قوية:

وقم بهذه الخطوة فور التشغيل، والسبب أن هذه الصفحة مفتوحة لأي زائر حتى يوجد أول مستخدم، فمن يصل إليها قبلك يصبح هو مدير المنصة. وبعد ذلك تسجل الدخول، فتظهر صفحة تراجع فيها بيانات الشركة مثل اللغة والمنطقة الزمنية Time Zone، ثم لوحة المحادثات، وأما لوحة مدير المنصة فهي على https://chat.example.com/super_admin، ومنها تدير الحسابات والمستخدمين وإعدادات التثبيت العامة.
صندوق الدردشة المباشرة للموقع
كل قناة تواصل في Chatwoot اسمها صندوق Inbox، ولكي تضيف الدردشة إلى موقعك افتح Settings ← Inboxes ← Add Inbox واختر Website:

ثم أدخل اسم الموقع ونطاقه، واختر لون النافذة ورسالة الترحيب Welcome Message:

وفي الخطوة التالية اختر الموظفين الذين يستقبلون محادثات هذا الصندوق وأضف نفسك معهم، والسبب أن المدير لا يرى محادثات صندوق ليس عضواً فيه، وبعدها يعرض Chatwoot كود JavaScript تضعه في موقعك:

وهذا شكل الكود، ومعه التوكن websiteToken الخاص بصندوقك، فضعه قبل </body> في قالب الموقع Template:
<script>
(function(d,t) {
var BASE_URL="https://chat.example.com";
var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
g.src=BASE_URL+"/packs/js/sdk.js";
g.async = true;
s.parentNode.insertBefore(g,s);
g.onload=function(){
window.chatwootSDK.run({
websiteToken: 'YOUR_WEBSITE_TOKEN',
baseUrl: BASE_URL
})
}
})(document,"script");
</script>وعندما تضع الكود في أي صفحة سوف تجد أيقونة الدردشة في زاوية الصفحة، وحين تفتحها تظهر رسالة الترحيب وحالة الفريق:

ثم يكتب الزائر رسالته، فيطلب منه Chatwoot بريده حتى يصله الرد إذا غادر الصفحة:

وتصل المحادثة فوراً إلى لوحة الموظفين، فيرد عليها الموظف، أو يكتب ملاحظة داخلية Private Note لا يراها العميل، أو يسندها إلى زميل أو فريق:

ومن إعدادات الصندوق (Settings ← Inboxes ← الصندوق ← Settings) تضبط ساعات العمل Business Hours ورسالة خارج الدوام Out of Office Message، وإذا كان عملاؤك يسجلون الدخول في موقعك فقم بتفعيل Enforce User Identity Validation، والسبب أنه من دونه يستطيع أي شخص أن ينتحل هوية Impersonation عميل آخر عبر نافذة الدردشة ويقرأ محادثاته.
إضافة الموظفين وإعداد البريد
من Settings ← Agents ← Add Agent تضيف الموظف باسمه وبريده ودوره (Agent أو Administrator)، فيرسل إليه Chatwoot دعوة ليعين كلمة المرور، وهذه الدعوة هي أول اختبار عملي لإعدادات SMTP:

وإذا أردت أن تختبر البريد قبل ربط خادم حقيقي فوجهه إلى Mailpit، وهو خادم SMTP تجريبي يلتقط الرسائل ويعرضها في واجهة ويب ولا يرسلها إلى أحد:

وإذا لم تصل الدعوة فالسبب غالباً في إعدادات SMTP، فراجع سجلات Logs الخاصة بـ Sidekiq لأنه هو الذي يرسل البريد وليس rails:
cd /opt/chatwoot
sudo docker compose logs --tail=100 sidekiq | grep -iE 'smtp|mail'والخطأ Net::SMTPAuthenticationError: 502 5.5.1 Command not implemented يعني أن خادم SMTP لا يقبل المصادقة بينما Chatwoot يحاولها، فقم بتفعيل المصادقة في الخادم وسوف يعيد Sidekiq المحاولة تلقائياً فتصل الرسالة، وهذا سلوك مفيد لأن الرسائل الفاشلة تبقى في طابور إعادة المحاولة Retry Queue ولا تضيع.
[email protected] تختلف عن إعداد SMTP الخاص بالإشعارات، فهي قناة مثل نافذة الدردشة تضيفها من Add Inbox ← Email، ثم تربطها بصندوق البريد عبر IMAP وSMTP من الواجهة.أين تحفظ المرفقات Storage
مع القيمة ACTIVE_STORAGE_SERVICE=local يحفظ Chatwoot المرفقات والصور الرمزية Avatars في المجلد /app/storage داخل الـ Volume المسمى storage_data، وهذا يكفي لسيرفر واحد بشرط أن يشمل النسخ الاحتياطي Backup هذا الـ Volume. وأما إذا أردت أن تفصل الملفات عن السيرفر، أو كنت تشغل أكثر من نسخة Instance من التطبيق، فاستخدم تخزيناً متوافقاً مع S3 مثل MinIO أو Garage أو خدمة سحابية:
ACTIVE_STORAGE_SERVICE=s3_compatible
STORAGE_BUCKET_NAME=chatwoot
STORAGE_ACCESS_KEY_ID=ACCESS_KEY
STORAGE_SECRET_ACCESS_KEY=SECRET_KEY
STORAGE_REGION=us-east-1
STORAGE_ENDPOINT=https://s3.example.com
STORAGE_FORCE_PATH_STYLE=trueوتذكر أن تغيير نوع التخزين لا ينقل الملفات الموجودة، لذلك اختره قبل أن يبدأ الفريق العمل، أو خطط لنقل الملفات يدوياً.
كيف تتأكد أن كل شيء يعمل
- افتح موقعك من متصفح آخر وأرسل رسالة من نافذة الدردشة، ويجب أن تظهر فوراً في لوحة الموظفين دون تحديث الصفحة Refresh، فإذا لم تظهر إلا بعد التحديث فاتصال WebSocket لا يمر عبر الـ Reverse Proxy.
- أضف موظفاً وتأكد أن رسالة الدعوة وصلت إلى بريده.
امتداد pgvector مثبت في قاعدة البيانات:
sudo docker compose exec postgres psql -U chatwoot -d chatwoot -c "select extname, extversion from pg_extension where extname='vector';"نقطة النهاية Endpoint /api تعيد الإصدار 4.18.0 والقيمتين "queue_services":"ok" و"data_services":"ok":
curl -s https://chat.example.com/apiالخدمات الأربع تعمل، وحالة قاعدة البيانات وRedis هي healthy:
cd /opt/chatwoot
sudo docker compose psالنسخ الاحتياطي والاستعادة Restore
ما تحتاج إلى نسخه هو قاعدة PostgreSQL وفيها المحادثات وجهات الاتصال Contacts والإعدادات، والـ Volume storage_data وفيه المرفقات، والملفان .env وdocker-compose.yml، وأما Redis ففيه طوابير وبيانات مؤقتة ولا تحتاج عادة إلى نسخه. ونسخ مجلد قاعدة البيانات وهي تعمل لا يعطيك نسخة يمكن الاعتماد عليها، لذلك نستخدم pg_dump كما يلي:
sudo mkdir -p /opt/backup/chatwoot
cd /opt/chatwoot
sudo docker compose exec -T postgres pg_dump -U chatwoot -Fc chatwoot | sudo tee /opt/backup/chatwoot/chatwoot-$(date +%F).dump >/dev/nullsudo docker compose run --rm --no-deps -v /opt/backup/chatwoot:/backup --entrypoint sh rails -c 'tar czf /backup/storage-$(date +%F).tgz -C /app storage'
sudo cp .env docker-compose.yml /opt/backup/chatwoot/وبعد ذلك قم بجدولة هذه الأوامر عبر cron لتعمل كل يوم، وانقل مجلد النسخ إلى تخزين خارج السيرفر Off-site Storage، لأن النسخة التي تبقى على السيرفر نفسه تضيع معه.
وللاستعادة على سيرفر جديد بالإصدار نفسه، ضع .env وdocker-compose.yml في مكانهما، وشغل قاعدة البيانات وحدها، ثم استورد النسخة وأعد المرفقات:
cd /opt/chatwoot
sudo docker compose up -d postgres redis
sudo docker compose exec -T postgres pg_restore -U chatwoot -d chatwoot --clean --if-exists --no-owner < /opt/backup/chatwoot/chatwoot-2026-09-26.dump
sudo docker compose run --rm --no-deps -v /opt/backup/chatwoot:/backup --entrypoint sh rails -c 'tar xzf /backup/storage-2026-09-26.tgz -C /app'
sudo docker compose run --rm rails bundle exec rails db:chatwoot_prepare
sudo docker compose up -d.env جديد، والسبب أن SECRET_KEY_BASE يوقع جلسات الموظفين والتوكنات التي تحفظها نافذة الدردشة في متصفحات الزوار، فإذا تغير خرج الجميع وفقد الزوار محادثاتهم السابقة في النافذة. وإذا أضفت لاحقاً مفاتيح ACTIVE_RECORD_ENCRYPTION_* التي تحتاجها المصادقة متعددة العوامل MFA، فإن Chatwoot يشفر Encrypt بها أسرار المصادقة الثنائية وكلمات مرور قنوات البريد وتوكنات بعض القنوات داخل قاعدة البيانات، ومن دون هذه المفاتيح لا يمكن قراءتها بعد الاستعادة، لذلك احفظ .env كاملاً مع كل نسخة احتياطية.التحديث إلى إصدار أحدث Upgrade
يصدر فريق Chatwoot إصداراً جديداً كل شهر تقريباً، وبين هذه الإصدارات إصدارات تصحيحية Patch Releases، وخطوات الترقية ثابتة: نسخة احتياطية، ثم تغيير الوسم، ثم سحب الـ Image، ثم الترحيلات، ثم التشغيل. وابدأ دائماً بقراءة ملاحظات الإصدار Release Notes على GitHub، والسبب أن بعض الإصدارات الكبيرة تحتاج إلى خطوات إضافية، ومثال ذلك الانتقال إلى الإصدار 4 الذي اشترط وجود امتداد pgvector في قاعدة البيانات:
cd /opt/chatwoot
sudo sed -i 's|chatwoot/chatwoot:v4.18.0|chatwoot/chatwoot:v4.19.0|' docker-compose.yml
sudo docker compose pull
sudo docker compose down
sudo docker compose up -d postgres redis
sudo docker compose run --rm rails bundle exec rails db:chatwoot_prepare
sudo docker compose up -dضع مكان v4.19.0 الإصدار المستقر Stable Release الذي تريده، واختر وسماً بصيغة vX.Y.Z، ولا تستخدم latest ولا develop. وإذا كان تثبيتك قديماً جداً فلا تقفز إلى آخر إصدار مباشرة، وإنما مر بالإصدارات الوسيطة Intermediate Versions ونفذ db:chatwoot_prepare بعد كل خطوة، كما توصي الوثائق الرسمية Documentation.
وأما ترقية PostgreSQL نفسها إلى إصدار رئيسي Major Version أحدث مثل pg17، فتكون عبر pg_dump ثم الاستعادة في Container جديد، ولا تقم بتغيير وسم الـ Image على الـ Volume نفسه، والسبب أن ملفات البيانات في الإصدار الرئيسي القديم لا يقرؤها الإصدار الجديد فلن تعمل القاعدة.
أشهر المشكلات وحلولها
الـ Container rails يعيد التشغيل باستمرار (Restart Loop)
أشهر سبب لهذه المشكلة أنك شغلت الخدمات قبل تنفيذ db:chatwoot_prepare، فنفذ المهمة كما في قسم التثبيت ثم أعد التشغيل. وإذا ظهر في السجل PG::UndefinedFile: could not open extension control file ... vector فأنت تستخدم الـ Image العادية لـ postgres، وعليك أن تنقل البيانات إلى الـ Image pgvector/pgvector بالإصدار الرئيسي نفسه.
خطأ NOAUTH أو WRONGPASS من Redis
هذا الخطأ يعني أن قيمة REDIS_PASSWORD التي يقرؤها Chatwoot لا تطابق كلمة المرور التي بدأ بها Redis، فتأكد أنها معرفة مرة واحدة في .env، ثم أعد إنشاء الخدمات بالأمر sudo docker compose up -d --force-recreate.
الرسائل لا تظهر إلا بعد تحديث الصفحة
والسبب أن اتصال WebSocket لا يمر عبر الـ Reverse Proxy، فقم بتفعيل Websockets Support في NPM، أو أضف proxy_set_header Upgrade $http_upgrade; وproxy_set_header Connection "upgrade"; في Nginx، وتأكد أيضاً أن FRONTEND_URL يطابق تماماً العنوان الذي يفتحه المستخدمون.
نافذة الدردشة لا تظهر على الموقع
افتح أدوات المطور Developer Tools في المتصفح، فإذا فشل تحميل /packs/js/sdk.js فالعنوان في BASE_URL خاطئ أو الشهادة غير صالحة، وإذا ظهر خطأ Mixed Content فموقعك يعمل عبر HTTPS بينما BASE_URL يبدأ بـ http://. وتأكد أيضاً أن سياسة Content-Security-Policy في موقعك تسمح بتحميل السكربت والإطار iframe من نطاق Chatwoot.
البريد لا يصل
راجع سجل sidekiq كما في قسم الموظفين، وأكثر الأخطاء تكراراً هو منفذ لا يوافق نوع التشفير Encryption، فالمنفذ 587 يعمل مع STARTTLS، والمنفذ 465 يحتاج إلى SMTP_SSL=true. ومن الأخطاء أيضاً SMTP_OPENSSL_VERIFY_MODE=peer مع شهادة غير صالحة على خادم البريد، أو عنوان في MAILER_SENDER_EMAIL لا يحق للحساب أن يرسل باسمه، وبعد تعديل .env أعد إنشاء rails وsidekiq حتى يقرآ القيم الجديدة.
الخلاصة
وصلنا لنهاية الموضوع، وأهم ما فيه:
- جمع القنوات في مجموعة دردشة داخلية لا يوزع المحادثات ولا يحفظ سجل العميل، والخدمات السحابية تكلفتها تزيد مع كل موظف، وChatwoot يجمع القنوات كلها في صندوق واحد على سيرفرك، ونسخته المجتمعية تكفي أغلب الفرق.
- استخدم الـ Image الخاصة بـ pgvector لقاعدة البيانات لأن Chatwoot 4 لا يعمل من دونها، وثبت الوسوم، واربط منفذ التطبيق بالعنوان
127.0.0.1، ولا تنشر منفذي PostgreSQL وRedis. - نفذ
db:chatwoot_prepareقبل تشغيلrailsفي التثبيت الأول، وبعد كل ترقية. - فعل WebSocket في الـ Reverse Proxy، واجعل
FRONTEND_URLمطابقاً للعنوان العام، وأنشئ حساب المدير فور التشغيل. - انسخ قاعدة البيانات والـ Volume
storage_dataوملف.envكاملاً وانقلها خارج السيرفر، واقرأ ملاحظات الإصدار قبل كل ترقية.
سجل التحديثات (Changelog)
- سبتمبر 2026: كتابة الدليل واختباره على Chatwoot 4.18.0.
- أكتوبر 2026: مراجعة تقنية على Chatwoot 4.18.0 (آخر إصدار مستقر)، وتصحيح وصف دور
SECRET_KEY_BASEومفاتيح التشفير، وتوضيح النسخة المجتمعية والمؤسسية، وإعادة كتابة الدليل بأسلوب الموقع.