لنفرض أن نقاشات فريقك وقراراته والملفات التي يتبادلها موجودة اليوم على Slack أو Microsoft Teams، فسوف تجد أن هذا مريح جداً إلى أن تتغير الأسعار أو شروط الخطة المجانية Free Plan، أو تطلب منك سياسة مؤسستك أن تبقى المحادثات داخلها، وعندها تكتشف أن تاريخ فريقك كله محفوظ على سيرفر Server لا تملكه ولا تتحكم في مدة الاحتفاظ بما عليه.
والحل الأول الذي يخطر على البال هو أن تبقى على الخدمة السحابية Cloud وتدفع الاشتراك، وهذا يعيد إليك التاريخ القديم ولكنه لا يغير الأصل، فالبيانات تبقى عند جهة أخرى والسعر يحدده غيرك. والحل الثاني هو أن تأخذ المستودع الرسمي mattermost/docker وتشغله كما هو، والمشكلة هنا أن هذا المستودع يستخدم افتراضياً الـ Docker Image الخاصة بـ Enterprise Edition، وهذه الـ Image عندما تعمل دون ترخيص License تتحول إلى خطة مجانية اسمها Mattermost Entry، وفيها ميزات أكثر ولكن مع حد قدره 10,000 رسالة على مستوى السيرفر كله، وما زاد عن ذلك يبقى في قاعدة البيانات Database ولكنه لا يظهر في القنوات ولا في البحث، والتوثيق نفسه يذكر أنها تناسب الفرق التي يقل عددها عن 50 مستخدماً.
لذلك فالحل الأنسب لفريق صغير أو متوسط يريد أن يبقى تاريخه كاملاً هو Mattermost بنسخة Team Edition، وهو منصة محادثة Chat مفتوحة المصدر Open Source تعمل بطريقة قريبة من Slack، ففيها الفرق Teams والقنوات Channels العامة Public والخاصة Private، والرسائل المباشرة Direct Messages وسلاسل الردود Threads والبحث Search في الرسائل، ولها تطبيقات لسطح المكتب Desktop والجوال Mobile، وتكاملات Integrations عبر الـ Webhooks والـ Slash Commands والـ Bots. ونسخة Team Edition مجانية ومرخصة بترخيص MIT، ولا يوجد فيها حد لعدد الرسائل، والرسائل والملفات كلها تبقى على سيرفرك.
وقد يتساءل البعض: لماذا لا أختار Entry ما دامت مجانية وفيها ميزات أكثر؟ والإجابة أن الأمر يتوقف على ما يحتاجه فريقك، فإذا كنت تحتاج تسجيل الدخول الموحد SSO عبر LDAP أو SAML أو حتى GitLab، أو حسابات الضيوف Guest Accounts، فهذه غير موجودة في Team Edition، حيث أزالت Mattermost تسجيل الدخول عبر GitLab منها في الإصدار 11.0، وتوقفت فيها Playbooks أيضاً، والتوثيق يحددها لفرق يقل عدد مستخدميها المفعلين Activated Users عن 250 ولا تحتاج SSO. وأما إذا كان المهم عندك أن يبقى تاريخ المحادثات كاملاً ويمكن البحث فيه، فـ Team Edition هي الخيار الصحيح، وهي التي سوف نستخدمها في هذا الدليل. ومتطلبات الامتثال Compliance المتقدمة، مثل eDiscovery وسياسات الاحتفاظ بالرسائل Message Retention، موجودة في الخطط المدفوعة Paid Plans فقط.
وسوف نناقش في هذا المقال ما يلي:
- تثبيت Mattermost Team Edition باستخدام Docker Compose مع PostgreSQL، وشرح الأسطر المهمة في الملف.
- ربط النطاق Domain مع شهادة TLS عبر الـ Reverse Proxy، وإنشاء أول مدير وأول فريق.
- أهم إعدادات System Console: العنوان Site URL والبريد SMTP وتخزين الملفات File Storage والتسجيل Signup.
- إرسال تنبيهات من أنظمتك عبر Incoming Webhook، ثم النسخ الاحتياطي Backup والاستعادة Restore.
- الفرق بين إصدارات الدعم الممتد ESR والإصدارات الشهرية، والتحديث Upgrade بأمان، وأشهر المشكلات وحلولها.
ما تحتاجه قبل أن تبدأ Requirements
- سيرفر Linux، ومتطلبات العتاد Hardware الرسمية تذكر أن سيرفراً واحداً بمعالج 1 vCPU وذاكرة RAM بحجم 2 GB يكفي حتى 1,000 مستخدم مسجل، ومعالجين 2 vCPU و4 GB من 1,000 إلى 2,000 مستخدم، ولأن PostgreSQL سوف تعمل على نفس السيرفر فاجعل الذاكرة 4 GB إذا استطعت. وأما المساحة Storage فتكفي 10 GB للبداية، وتزيد الحاجة مع الملفات المرفقة Attachments.
- Docker Engine مع Compose v2، وإذا لم يكن مثبتاً فاتبع دليل تثبيت Docker.
- نطاق فرعي Subdomain مثل
chat.example.comيشير إلى السيرفر، وReverse Proxy يصدر شهادة TLS Certificate ويدعم WebSocket، مثل Nginx Proxy Manager. - حساب SMTP للإشعارات Notifications ودعوات Invitations المستخدمين واستعادة كلمات المرور Password Reset.
- المنفذ Port رقم
8443(UDP وTCP)، وتحتاجه فقط للمكالمات الصوتية والمرئية Voice and Video Calls عبر إضافة Plugin اسمها Calls، ولاحظ أن Team Edition تسمح بمكالمات ثنائية 1:1 ومشاركة الشاشة Screen Sharing لمدة أقصاها 40 دقيقة، وأما المكالمات الجماعية Group Calls فهي في الخطط المدفوعة.
تثبيت Mattermost خطوة بخطوة Installation
مجلد التثبيت وملف .env
أول خطوة هي أن ننشئ مجلداً للتثبيت:
sudo mkdir -p /opt/mattermost
cd /opt/mattermostثم نضع فيه ملف .env يحمل رقم الإصدار Version وكلمة مرور قاعدة البيانات، والسبب أننا لا نريد أن نكتب كلمة المرور داخل ملف Compose نفسه فتظهر في كل نسخة منه، ولذلك نولدها عشوائياً ونجعل الملف مقروءاً للمالك فقط:
cat > .env <<EOF
MM_TAG=11.11.1
POSTGRES_PASSWORD=$(openssl rand -hex 24)
EOF
chmod 600 .envوالإصدار 11.11.1 هو أحدث إصدار مستقر Stable Release حتى كتابة هذا الدليل، وهو من الإصدارات الشهرية Feature Releases، وأما إذا كنت تفضل أن تحدث السيرفر مرات أقل فاختر إصدار الدعم الممتد ESR، والتفصيل في قسم التحديث أدناه.
ملف docker-compose.yml وشرح ما فيه
هذا الملف مبني على المستودع الرسمي mattermost/docker مع بعض التعديلات التي سوف نشرحها بعد الملف، وتجد طريقة التثبيت الرسمية في دليل التثبيت عبر Containers. والملف سوف يكون كما يلي:
services:
postgres:
image: postgres:18.6-alpine
restart: unless-stopped
security_opt:
- no-new-privileges:true
environment:
POSTGRES_USER: mmuser
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?}
POSTGRES_DB: mattermost
TZ: UTC
volumes:
# PostgreSQL 18 يحفظ بياناته تحت /var/lib/postgresql/18/docker
- db:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U mmuser -d mattermost"]
interval: 10s
timeout: 5s
retries: 10
mattermost:
image: mattermost/mattermost-team-edition:${MM_TAG}
restart: unless-stopped
security_opt:
- no-new-privileges:true
depends_on:
postgres:
condition: service_healthy
environment:
TZ: UTC
MM_SQLSETTINGS_DRIVERNAME: postgres
MM_SQLSETTINGS_DATASOURCE: postgres://mmuser:${POSTGRES_PASSWORD}@postgres:5432/mattermost?sslmode=disable&connect_timeout=10
MM_SERVICESETTINGS_SITEURL: https://chat.example.com
# يسمح بـ mmctl --local من داخل الـ Container (ويستخدمه الـ Healthcheck المدمج في الـ Image)
MM_SERVICESETTINGS_ENABLELOCALMODE: "true"
ports:
- "127.0.0.1:8065:8065"
# للمكالمات فقط (إضافة Calls)
# - "8443:8443/udp"
# - "8443:8443/tcp"
volumes:
- config:/mattermost/config
- data:/mattermost/data
- logs:/mattermost/logs
- plugins:/mattermost/plugins
- client-plugins:/mattermost/client/plugins
networks:
- default
- proxy
volumes:
db:
config:
data:
logs:
plugins:
client-plugins:
networks:
proxy:
external: trueفي الإعداد أعلاه لاحظ التالي:
- الـ Image هي
mattermost/mattermost-team-editionوليستmattermost-enterprise-editionالتي يستخدمها المستودع الرسمي افتراضياً، والسبب هو حد الرسائل في Entry الذي شرحناه في البداية. - استخدمنا Volumes مسماة Named Volumes بدل المجلدات المربوطة Bind Mounts، والسبب أن Mattermost يعمل داخل الـ Container بالمستخدم UID 2000، والمستودع الرسمي يطلب منك لذلك أن تنفذ
chown -R 2000:2000على المجلدات قبل التشغيل، أما الـ Volume الجديد فيأخذ ملكية المجلد الموجود داخل الـ Image تلقائياً، فلا تحتاج إلى هذه الخطوة. - حذفنا الـ Volume الخاص بـ
bleve-indexesوالمتغيرMM_BLEVESETTINGS_INDEXDIRالموجودين في المستودع الرسمي، والسبب أن Mattermost أزال البحث عبر Bleve في الإصدار 11.0، وأصبح البحث يعمل من قاعدة البيانات مباشرة. - منفذ الويب مربوط بالعنوان
127.0.0.1فقط، والسبب أن الـ Reverse Proxy وحده هو الذي يصل إليه عبر الشبكةproxy، فلا يستطيع أحد أن يتجاوز شهادة TLS ويفتح Mattermost مباشرة على المنفذ 8065. - الصيغة
${POSTGRES_PASSWORD:?}تجعل Compose يتوقف برسالة خطأ إذا لم يجد المتغير في ملف.env، بدل أن يشغل قاعدة البيانات بكلمة مرور فارغة، والشرطservice_healthyيجعل Mattermost ينتظر حتى تصبح PostgreSQL جاهزة فعلاً. - الـ Image الخاصة بـ PostgreSQL 18 تحفظ بياناتها تحت
/var/lib/postgresqlوليس/var/lib/postgresql/dataكما في الإصدارات السابقة، ولذلك ربطنا الـ Volume بهذا المسار، والإصدار 18 مدعوم لأن الحد الأدنى في Mattermost هو PostgreSQL 14، ويصبح 15 بدءاً من الإصدار 12.0.
وكل إعداد في System Console تستطيع تثبيته بمتغير بيئة Environment Variable بحروف كبيرة على الصيغة MM_<SECTION>_<SETTING>، مثل MM_SERVICESETTINGS_SITEURL، كما في صفحة إعدادات التهيئة Configuration Settings، وعندها يظهر الإعداد في الواجهة Web UI مقفلاً Locked، وبجانبه العبارة «This setting has been set through an environment variable»، لذلك استخدم هذه الطريقة للقيم التي لا تريد أن يغيرها أحد من الواجهة.
ويجدر الإشارة هنا إلى أن التوثيق الرسمي يصنف التثبيت عبر Docker للتجربة والتطوير، والسبب أنه لا يدعم التشغيل على عدة سيرفرات Cluster ولا التوافرية العالية High Availability، ويوصي بـ Kubernetes لمن يحتاجها. وهذا لا يمنعك من تشغيله لفريقك على سيرفر واحد، ولكن تذكر أن أي تحديث أو عطل في السيرفر يعني توقف المحادثات لدقائق.
تشغيل الخدمات Services
الآن سوف نقوم بإنشاء الشبكة المشتركة مع الـ Reverse Proxy، ثم تشغيل الخدمتين ومتابعة السجلات Logs:
docker network create proxy
docker compose up -d
docker compose logs -f mattermostوإذا كانت الشبكة موجودة من قبل فسوف يفشل الأمر الأول برسالة أنها موجودة، وهذا لا يضر بشيء. وفي الـ Image فحص صحة Healthcheck مدمج يعتمد على الأمر mmctl system status --local، لذلك انتظر حتى يظهر الـ Container بالحالة healthy في مخرجات Output الأمر docker compose ps، ثم تحقق بهذا الأمر:
curl -s http://127.0.0.1:8065/api/v4/system/pingوالمخرج سوف يكون رداً Response فيه "status":"OK".
ربط النطاق Domain وشهادة TLS عبر الـ Reverse Proxy
في Nginx Proxy Manager أضف مضيفاً Proxy Host للنطاق chat.example.com يوجه الطلبات Requests إلى الـ Container الخاص بـ mattermost على المنفذ 8065، وفعل Websockets Support، والسبب أن الرسائل الفورية Real-time Messages تمر عبر WebSocket، فإذا لم تفعله فلن تظهر الرسائل إلا بعد تحديث الصفحة. ثم اطلب شهادة Let's Encrypt مع Force SSL، وقم بزيادة حد الرفع Upload Limit في الإعدادات المتقدمة Advanced ليطابق حد الملفات في Mattermost، وهو 100 MB افتراضياً (راجع توثيق client_max_body_size ودليل إعداد NGINX لـ Mattermost):
client_max_body_size 100m;
proxy_read_timeout 600s;وإذا كنت تستخدم Caddy فيكفي هذا:
chat.example.com {
reverse_proxy mattermost-mattermost-1:8065
}والسبب أن التوجيه Directive reverse_proxy في Caddy يمرر اتصالات WebSocket تلقائياً. وفي الحالتين تأكد أن قيمة MM_SERVICESETTINGS_SITEURL تطابق العنوان العام Public URL تماماً، وإلا فسوف تتعطل الروابط في الإشعارات ويفشل تسجيل الدخول Login من التطبيقات.
إنشاء أول مدير Admin وأول فريق
افتح https://chat.example.com/ واختر View in Browser، وتذكر أن أول حساب تنشئه يصبح مدير النظام System Admin، لذلك أنشئه فور التشغيل وقبل أن تنشر الرابط لأي أحد.

بعد ذلك يطلب منك المعالج Wizard اسم المؤسسة، وينشئ به أول فريق Team مع قناتيه الافتراضيتين Town Square وOff-Topic، ثم يعرض عليك تكاملات اختيارية مثل GitHub وGitLab وJira وتستطيع تخطيها.

أهم الإعدادات في System Console
افتح System Console من قائمة المنتجات Product Menu، وهي أيقونة المربعات في أعلى اليسار، وفيما يلي أهم الإعدادات بعد التثبيت.
العنوان العام Site URL
هذا الإعداد في Environment ← Web Server، وسوف تجده مقفلاً لأننا ضبطناه بمتغير بيئة، فاضغط Test Live URL لتتأكد أن العنوان يعمل.

إعداد البريد SMTP
في Environment ← SMTP أدخل عنوان سيرفر البريد والمنفذ، وفعل Enable SMTP Authentication مع اسم المستخدم Username وكلمة المرور، ثم اختر Connection Security: إما STARTTLS على المنفذ 587 أو TLS على المنفذ 465. واحفظ الإعدادات قبل أن تضغط على Test Connection، والسبب أن الاختبار يستخدم الإعدادات المحفوظة وليس ما كتبته في الحقول.

بعد ذلك فعل الإشعارات من Site Configuration ← Notifications، حيث تجعل Enable Email Notifications = true، وتضبط Notification From Address (مثل [email protected]) واسم المرسل. وتستطيع أيضاً تثبيت إعدادات البريد بمتغيرات البيئة كما يلي:
MM_EMAILSETTINGS_SMTPSERVER: smtp.example.com
MM_EMAILSETTINGS_SMTPPORT: "587"
MM_EMAILSETTINGS_ENABLESMTPAUTH: "true"
MM_EMAILSETTINGS_SMTPUSERNAME: [email protected]
MM_EMAILSETTINGS_SMTPPASSWORD: ${SMTP_PASSWORD}
MM_EMAILSETTINGS_CONNECTIONSECURITY: STARTTLS
MM_EMAILSETTINGS_SENDEMAILNOTIFICATIONS: "true"
MM_EMAILSETTINGS_FEEDBACKEMAIL: [email protected]ونجاح الاختبار يعني أن Mattermost وصل إلى سيرفر البريد، وأما وصول الرسائل إلى صناديق البريد الحقيقية دون أن تذهب إلى الرسائل المزعجة Spam فيتوقف على مزود البريد Email Provider وعلى سجلات Records من نوع SPF وDKIM في النطاق كما شرحنا في شرح SPF وDKIM وDMARC للمبتدئين، لذلك أرسل دعوة إلى بريد تجريبي وتأكد أنها وصلت.
تخزين الملفات File Storage
الخيار الافتراضي في Environment ← File Storage هو Local File System في المسار ./data/، أي في الـ Volume المسمى data، وهو مناسب لسيرفر واحد. وإذا قمت بتعديل Maximum File Size فعدل حد الـ Reverse Proxy معه، وإلا فسوف يرفض الـ Reverse Proxy الملف قبل أن يصل إلى Mattermost.
وإذا كان لديك تخزين متوافق مع S3 (S3-compatible)، مثل MinIO أو خدمة سحابية، فاختر Amazon S3 وأدخل الـ bucket والمفاتيح Access Keys والـ endpoint، وعندها يصبح الـ bucket هو ما تنسخه احتياطياً بدل الـ Volume المسمى data.

التسجيل Signup ودعوة الزملاء
في Authentication ← Signup اترك Enable Open Server معطلاً كما هو افتراضياً، والسبب أن تفعيله يسمح لأي شخص يصل إلى الرابط بإنشاء حساب، وقيد Restrict new system and team members to specified email domains بنطاق مؤسستك، ثم ادع زملاءك من قائمة الفريق ← Invite People.
إرسال رسائل من أنظمتك عبر Incoming Webhooks
الـ Incoming Webhook هو أبسط أنواع التكامل، وهو عنوان سري Secret URL يستقبل بيانات JSON وينشرها رسالة في قناة، وبالتالي فهو مناسب لتنبيهات Alerts الـ CI/CD والمراقبة Monitoring والنسخ الاحتياطي. تأكد أولاً أن Integrations ← Integration Management ← Enable Incoming Webhooks مفعل، وهو مفعل افتراضياً، ثم افتح من قائمة الفريق Integrations ← Incoming Webhooks ← Add Incoming Webhook:

فعل Lock to this channel، والسبب أن الـ Webhook دون هذا الخيار يستطيع النشر في أي قناة يكون منشئه عضواً فيها إذا أرسل الحقل channel. وبعد الحفظ تحصل على عنوان مثل https://chat.example.com/hooks/xxxxxxxxxxxxxxxxxxxxxxxxxx، فاحمه كما تحمي كلمة المرور، لأن كل من يعرفه يستطيع النشر في قناتك. الآن سوف نرسل رسالة، والنص يدعم Markdown والجداول Tables:
curl -s -X POST -H 'Content-Type: application/json' \
-d '{"text":"#### :white_check_mark: Build succeeded\n| Repository | Branch | Commit |\n|:--|:--|:--|\n| gitadmin/demo-app | main | 59d070b9 |\n[Open the run](https://git.example.com/gitadmin/demo-app/actions/runs/2)"}' \
https://chat.example.com/hooks/xxxxxxxxxxxxxxxxxxxxxxxxxxوالمخرج سوف يكون كلمة ok مع رمز الحالة Status Code رقم 200، والرسالة تظهر في القناة كما يلي:

ولاحظ أن Mattermost يتجاهل الحقلين username وicon_url في الـ JSON إلا إذا فعلت Enable integrations to override usernames وprofile picture icons في Integration Management، ولذلك تظهر الرسالة باسم منشئ الـ Webhook مع شارة Badge مكتوب فيها BOT.
وفي Gitea Actions (راجع دليل Gitea Actions) احفظ الرابط في سر Secret، واستدعه في الخطوة Step الأخيرة مع if: always() حتى يصلك التنبيه سواءً نجح البناء أو فشل.
كيف تتأكد أن كل شيء يعمل Verification
- الأمر
docker compose psيعرض الـ Containers الاثنين بالحالةhealthy. - الأمر
curl -s https://chat.example.com/api/v4/system/pingيعيد"status":"OK". - الرسائل تصل فوراً بين متصفحين Browsers دون تحديث الصفحة، وهذا يعني أن اتصال WebSocket يمر عبر الـ Reverse Proxy.
- رفع ملف بحجم 20 MB في قناة ينجح.
- Test Connection في إعدادات SMTP ينجح، ورسالة الدعوة تصل إلى بريد تجريبي.
- الإصدار المتوقع يظهر في قائمة المنتجات ← About Mattermost.
النسخ الاحتياطي Backup والاستعادة Restore
النسخة الكاملة تتكون من قاعدة البيانات، ففيها الرسائل والمستخدمون والقنوات، ومن الـ Volume المسمى data وفيه الملفات المرفقة، وconfig وفيه الملف config.json بكل ما ضبطته من الواجهة، وplugins وفيه الإضافات التي ثبتها من الـ Marketplace، ومعها الملفان .env وdocker-compose.yml. ولاحظ أن أسماء الـ Volumes على القرص Disk تبدأ باسم المشروع Project Name، مثل mattermost_data، والأوامر كما يلي:
cd /opt/mattermost
mkdir -p backups
docker compose exec -T postgres pg_dump -U mmuser -d mattermost -Fc > backups/mattermost-db-$(date +%F).dump
docker run --rm \
-v mattermost_config:/v/config:ro \
-v mattermost_data:/v/data:ro \
-v mattermost_plugins:/v/plugins:ro \
-v "$PWD/backups:/backup" \
alpine:3 tar czf /backup/mattermost-files-$(date +%F).tar.gz -C /v config data pluginsولا تحتاج إلى إيقاف Mattermost أثناء النسخ، ولكن الملفات التي ترفع في تلك اللحظة قد لا تدخل النسخة، لذلك اجعل النسخ في الليل. وفي تثبيت جديد يكون ملف pg_dump بحجم 200 KB تقريباً، وأرشيف Archive الملفات بحجم 86 MB تقريباً، ومعظمها للإضافات المدمجة، ثم انقل النسختين خارج السيرفر، لأن النسخة التي تبقى على نفس القرص تضيع معه.
الاستعادة تكون كما يلي:
cd /opt/mattermost
docker compose up -d postgres
docker compose exec -T postgres pg_restore -U mmuser -d mattermost --clean --if-exists --no-owner < backups/mattermost-db-2026-09-26.dump
docker run --rm \
-v mattermost_config:/v/config \
-v mattermost_data:/v/data \
-v mattermost_plugins:/v/plugins \
-v "$PWD/backups:/backup" \
alpine:3 sh -c 'tar xzf /backup/mattermost-files-2026-09-26.tar.gz -C /v && chown -R 2000:2000 /v'
docker compose up -dفي الأوامر أعلاه لاحظ التالي:
- نستعيد قاعدة البيانات بالأداة
pg_restoreقبل تشغيل Mattermost، والخياران--clean --if-existsيحذفان الجداول الموجودة قبل إنشائها من النسخة. - نعيد ضبط المالك إلى
2000:2000بعد فك الأرشيف، والسبب أن Mattermost يعمل داخل الـ Container بالمستخدم UID 2000، فإذا بقيت الملفات باسم root فسوف يتوقف بخطأ صلاحيات Permissions. - الاستعادة تكون على نفس إصدار Mattermost الذي أخذت منه النسخة، ثم تحدث بعدها إذا أردت.
التحديث Upgrade إلى إصدار أحدث
تحديث Mattermost
تصدر Mattermost نوعين من الإصدارات: إصدار شهري Feature Release يدعم لمدة ثلاثة أشهر تقريباً، فالإصدار 11.11 مثلاً صدر في سبتمبر 2026 وينتهي دعمه في 15 ديسمبر 2026، وإصدار الدعم الممتد Extended Support Release واختصاراً ESR يدعم لمدة سنة تقريباً، مثل الإصدار 11.7 الذي ينتهي دعمه في 15 مايو 2027. فإذا اخترت الإصدارات الشهرية فعليك أن تحدث كل شهر أو شهرين، وأما إذا اخترت ESR فتحدث مرة في السنة من ESR إلى الذي يليه، والتوثيق يذكر أن هذا المسار مدعوم ومختبر بالكامل.
وعندما تشغل الإصدار الجديد يقوم Mattermost بترحيل Migrate قاعدة البيانات تلقائياً إلى الشكل الجديد، وبين الإصدارات الثانوية Minor Versions، مثل 11.10 إلى 11.11، يكون التحديث مباشراً، وأما إذا كنت تقفز عبر عدة إصدارات أو إلى إصدار رئيسي Major Version، مثل 11 إلى 12، فاقرأ قبله Important Upgrade Notes، والسبب أن بعض الترحيلات يأخذ وقتاً طويلاً على القواعد الكبيرة، وبعضها يحتاج خطوات يدوية، وفي الإصدار 11.0 مثلاً توقف دعم MySQL وأصبح الحد الأدنى PostgreSQL 14. والإجراء الرسمي تجده في صفحة تحديث السيرفر، وأما في Docker فالخطوات كما يلي:
- أنشئ نسخة احتياطية كاملة كما في القسم السابق.
تحقق من الإصدار الجديد:
curl -s "https://chat.example.com/api/v4/config/client?format=old" | grep -o '"Version":"[^"]*"'اسحب Pull الـ Image، وأعد إنشاء الـ Container الخاص بالتطبيق وحده، وراقب السجل:
docker compose pull mattermost
docker compose up -d mattermost
docker compose logs -f mattermostاختر الوسم Tag الجديد، وغيره في .env:
sed -i 's/^MM_TAG=.*/MM_TAG=11.11.1/' .envوبهذه الخطوات، من 11.10.2 إلى 11.11.1، يعود الـ Container إلى الحالة healthy خلال دقيقة تقريباً، وتبقى الرسائل والـ Webhooks كما هي، وتتحدث الإضافات المدمجة تلقائياً.

وبعد أن تتأكد من سلامة التحديث احذف الـ Image القديمة بالأمر docker image prune. وإذا فشل التحديث فأوقف التطبيق، واستعد نسخة قاعدة البيانات، ثم ارجع إلى الوسم القديم، ولا تقم بتشغيل الإصدار القديم على قاعدة بيانات رحلها الإصدار الجديد، والسبب أن الإصدار القديم لا يعرف شكل الجداول الجديد، وفي الإصدار 11 مثلاً تغيرت طريقة تخزين كلمات المرور إلى PBKDF2، فالمستخدم الذي سجل دخوله بعد التحديث لا يستطيع الدخول إذا رجعت إلى إصدار أقدم من 11.
ويجدر بك أن تعرف أن الإصدار 12.0 مجدول في 14 أكتوبر 2026، وسوف يرفع الحد الأدنى إلى PostgreSQL 15، وهذا لا يؤثر على الملف أعلاه لأنه يستخدم PostgreSQL 18، ولكن انتظر الإصدار التصحيحي الأول منه واقرأ ملاحظاته قبل أن تنتقل إليه.
تحديث PostgreSQL إلى إصدار رئيسي جديد
تغيير وسم PostgreSQL من إصدار رئيسي إلى آخر، مثل 17 إلى 18، لا يكفي وحده، والسبب أن ملفات البيانات غير متوافقة بين الإصدارين، فسوف يتوقف الـ Container بالرسالة «database files are incompatible with server». والطريقة الآمنة كما في توثيق التحديث في PostgreSQL هي أن تفرغ Dump قاعدة البيانات كاملة، ثم تستعيدها في Volume جديد:
cd /opt/mattermost
docker compose stop mattermost
docker compose exec -T postgres pg_dumpall -U mmuser > backups/all-before-pg-upgrade.sql
docker compose rm -sf postgres
docker volume rm mattermost_dbبعد ذلك غير وسم postgres في docker-compose.yml إلى الإصدار الجديد، وانتبه إلى أن الـ Image الخاصة بـ PostgreSQL 18 تستخدم المسار /var/lib/postgresql، وليس المسار /var/lib/postgresql/data الذي استخدمته الإصدارات السابقة، ثم نفذ:
docker compose up -d postgres
docker compose exec -T postgres psql -U mmuser -d postgres < backups/all-before-pg-upgrade.sql
docker compose up -d mattermostوالرسالة «role mmuser already exists» أثناء الاستعادة طبيعية، لأن الـ Image أنشأت المستخدم عند أول تشغيل، وpg_dumpall يحفظ كلمة مرور المستخدم فتبقى مطابقة لما في .env. ولا تقم بحذف الـ Volume القديم قبل أن تتأكد أن ملف التفريغ موجود وأن حجمه منطقي.
مشكلات شائعة وحلولها Troubleshooting
يتوقف الـ Container بالخطأ «permission denied» على /mattermost/config أو data
وهذا يحدث مع المجلدات المربوطة Bind Mounts، والسبب أن Mattermost يعمل بالمستخدم UID 2000 والمجلد على السيرفر ملك لمستخدم آخر، والحل أن تنفذ sudo chown -R 2000:2000 ./volumes/app/mattermost، أو أن تستخدم Volumes مسماة كما في هذا الدليل.
لا تظهر الرسائل إلا بعد تحديث الصفحة، أو تظهر الرسالة «Cannot connect to the server»
والسبب أن اتصال WebSocket لا يمر عبر الـ Reverse Proxy، والحل أن تفعل Websockets Support في NPM، أو تتحقق من الترويستين Headers Upgrade وConnection في Nginx.
روابط الإشعارات تشير إلى localhost، أو يظهر التحذير «Site URL is not set»
والسبب أن المتغير MM_SERVICESETTINGS_SITEURL غير مضبوط أو خاطئ، فاضبطه على العنوان العام مع https، ثم نفذ docker compose up -d.
Test Connection يظهر الرسالة «Please save unsaved changes first»
والسبب أن الاختبار يستخدم الإعدادات المحفوظة، فاضغط Save أولاً ثم أعد الاختبار.
يبقى الـ Container بالحالة unhealthy مع أن الموقع يعمل
والسبب أن الـ Healthcheck في الـ Image يعتمد على mmctl --local، وهذا يحتاج MM_SERVICESETTINGS_ENABLELOCALMODE=true. ولا تقلق من تفعيله، لأن الوضع المحلي Local Mode يعمل عبر مقبس Socket من نوع Unix داخل الـ Container فقط، ولا يفتح أي منفذ خارجي.
الخطأ «413 Request Entity Too Large» عند رفع ملف
والسبب هو حد حجم الطلب في الـ Reverse Proxy، والحل أن ترفع قيمة client_max_body_size لتطابق Maximum File Size في Mattermost.
الخلاصة
وصلنا لنهاية الموضوع، وأهم ما فيه:
- الخدمة السحابية تقرر نيابة عنك كم تبقى رسائلك، والـ Image الخاصة بـ Enterprise Edition دون ترخيص تخفي ما زاد عن 10,000 رسالة، ولذلك فـ Team Edition هي الخيار المناسب لفريق يقل عن 250 مستخدماً ولا يحتاج SSO.
- اربط منفذ الويب بالعنوان
127.0.0.1خلف الـ Reverse Proxy مع تفعيل WebSocket، واضبطMM_SERVICESETTINGS_SITEURLبدقة لأن منه تبنى كل الروابط. - أنشئ حساب المدير فور التشغيل، واترك Open Server معطلاً، وفعل Lock to this channel لكل Webhook واحفظ رابطه كما تحفظ كلمة المرور.
- خذ نسخة
pg_dumpونسخة الـ Volumes وانقلهما خارج السيرفر، ولا تشغل إصداراً أقدم على قاعدة بيانات رحلها إصدار أحدث. - اختر بين الإصدارات الشهرية وESR حسب عدد المرات التي تستطيع أن تحدث فيها، واقرأ Important Upgrade Notes قبل كل تحديث رئيسي.
سجل التحديثات Changelog
- سبتمبر 2026: كتابة الدليل واختباره على Mattermost 11.11.1 (مع ترقية مجربة من 11.10.2).
- أكتوبر 2026: مراجعة الدليل، وحذف إعدادات Bleve التي أزيلت في الإصدار 11.0، وتصحيح متطلبات العتاد، وإضافة الفرق بين Team Edition وEntry وحدود المكالمات، وشرح الإصدارات الشهرية وESR والإصدار 12.0.