في هذا الدليل سوف نثبت Stalwart، وهو خادم بريد Mail Server في برنامج واحد مكتوب بلغة Rust يقوم بكل الأدوار من الداخل: SMTP لاستقبال البريد وإرساله، وIMAP وPOP3 وJMAP لقراءته، وManageSieve لقواعد الفرز Filtering Rules، وCalDAV وCardDAV وWebDAV للتقويم Calendar وجهات الاتصال Contacts والملفات، ومعها فلتر للرسائل المزعجة Spam، وتوقيع DKIM والتحقق من SPF وDMARC وARC، وإصدار شهادات Let's Encrypt عبر ACME، ولوحة إدارة Admin Panel من المتصفح. وبالتالي فبدل أن تضبط عشرة ملفات إعداد Configuration Files وتتأكد أنها متفقة فيما بينها كما في دليل خادم البريد مع Postfix وDovecot، أو تشغل حزمة من عدة Containers كما في دليل mailcow، سوف تشغل Container واحداً وتجيب على خمس شاشات في معالج الإعداد Setup Wizard.
وإذا لم تقرر بعد هل تستضيف بريد مؤسستك بنفسك، وأي الخيارات الثلاثة يناسبك، فالصورة الكاملة من القرار إلى خطة النقل في دليل استضافة البريد الإلكتروني للمؤسسات.
وسوف نناقش في هذا المقال ما يلي:
- ما هو Stalwart، وهل هو ناضج بما يكفي لبريد شركتك، وما الفرق بين الإصدار المجاني والإصدار التجاري Enterprise.
- المتطلبات والمنافذ Ports، والتثبيت باستخدام Docker Compose على Ubuntu 24.04، ثم معالج الإعداد الأول وكلمة مرور المدير المؤقتة.
- إضافة النطاقات Domains وصناديق البريد، وسجلات DNS التي يولدها Stalwart لك وطريقة نشرها، وسجل PTR لدى المزود.
- الشهادة عبر ACME المدمج أو خلف Reverse Proxy، وأي المنافذ يجب أن تبقى مباشرة.
- فلتر الرسائل المزعجة، والتحقق من الإرسال والاستقبال، والنسخ الاحتياطي Backup، والتحديث Upgrade، وأشهر المشكلات وحلولها.
ما هو Stalwart ولماذا خادم واحد بدل عدة خوادم؟
لكي تفهم ما الذي يغيره Stalwart، تخيل رسالة تصل إلى سيرفر Server بريد تقليدي: يستقبلها Postfix على المنفذ 25، ثم يمررها إلى Rspamd عبر بروتوكول Milter ليفحصها، ثم يسلمها إلى Dovecot عبر LMTP ليحفظها في صندوق المستخدم، وعندما يرسل المستخدم رداً يتحقق Postfix من كلمة مروره بسؤال Dovecot عبر SASL، ثم يمرر الرسالة إلى برنامج التوقيع ليضيف DKIM. وكل سهم في هذه السلسلة هو إعداد عليك أن تكتبه بنفسك، وكل برنامج يحتاج إلى تحديث منفصل، وعندما لا تصل رسالة فأنت تبحث في أربعة سجلات مختلفة.
والحل الذي جاء به mailcow هو أن يجمع هذه البرامج في Containers مضبوطة مسبقاً، وهذا حل ممتاز ومجرب، ولكنه لا يلغي التعدد، وإنما يخفيه خلف سكربت Script تثبيت، لذلك يحتاج mailcow إلى 6 GiB من الذاكرة على الأقل وإلى قرابة 18 Docker Image. أما Stalwart فكتب كل هذه الوظائف في برنامج واحد يشترك في قاعدة بيانات واحدة وسجل واحد ولوحة واحدة، وبالتالي تكفيه قرابة 1 GB من الذاكرة لفريق من 5 إلى 10 مستخدمين، ويحتاج وهو خامل إلى نحو 100 MB فقط بحسب التوثيق.
ولاحظ أن Stalwart لا يتضمن بريداً عبر الويب Webmail مثل SOGo في mailcow، حيث تقدم واجهته مسارين فقط: /admin لإدارة السيرفر، و/account ليغير المستخدم كلمة مروره ويدير كلمات مرور التطبيقات App Passwords والتحقق الثنائي Two-Factor Authentication. أما قراءة البريد فتكون من برامج البريد Mail Clients مثل Thunderbird وOutlook وتطبيقات الهواتف، فإذا كان فريقك يعتمد على البريد من المتصفح فعليك أن تضيف تطبيق Webmail مستقلاً، أو تختار mailcow.
هل Stalwart ناضج بما يكفي مقارنة بـ Postfix وDovecot؟
وقد يتساءل البعض: كيف أضع بريد الشركة على برنامج إصداره 0.16، بينما يعمل Postfix وDovecot منذ أكثر من عشرين عاماً على عدد كبير من سيرفرات البريد في العالم؟ والإجابة تحتاج إلى تفصيل، فمن جهة يذكر التوثيق الرسمي أن Stalwart يعمل في بيئات إنتاج Production حول العالم، وأنه اجتاز تدقيقاً أمنياً Security Audit أجرته شركة Radically Open Security في أكتوبر 2023 دون أن تجد ثغرات، ولغة Rust تمنع فئة كاملة من أخطاء الذاكرة Memory Safety Bugs التي عانت منها برامج البريد المكتوبة بلغة C. ومن جهة أخرى فهذا التدقيق كان على إصدار 0.3 والكود تغير كثيراً منذ ذلك الوقت، والمشروع نفسه يقول في التوثيق إن إصدارات ما قبل 1.0 قد تغير طريقة تخزين البيانات والإعداد وتحتاج إلى ترحيل Migration.
وهذا ليس كلاماً نظرياً، ففي الإصدار 0.16 تغيرت طبقة الإعداد والإدارة بالكامل، حيث اختفت ملفات TOML وأصبح كل الإعداد كائنات Objects داخل قاعدة البيانات تديرها عبر JMAP، واختفت واجهة /api القديمة، وأصبح اسم كل حساب عنوان بريد كاملاً، وتصف وثيقة الترقية من 0.15 هذا التغيير بأنه غير متوافق كلياً مع كل ما سبقه ويحتاج إلى ترحيل من عدة خطوات مع توقف للخدمة. لذلك فالحكم العملي كما يلي: إذا كنت تبني بريداً جديداً لفريق صغير أو متوسط وتقبل أن تقرأ ملاحظات الإصدار Release Notes قبل كل ترقية، فـ Stalwart خيار جيد وخفيف وحديث، أما إذا كانت جهتك لا تحتمل أي ترحيل غير مخطط له، أو تحتاج إلى بريد عبر الويب جاهز، فـ mailcow أو Postfix مع Dovecot هما الأنسب حتى يصدر Stalwart 1.0.
ما الذي تحصل عليه مجاناً وما الذي يحتاج ترخيص Enterprise؟
يصدر Stalwart بترخيصين Licenses على نفس الكود، فالإصدار المجتمعي Community Edition مجاني تحت ترخيص AGPL-3.0، والإصدار التجاري Enterprise تحت ترخيص Stalwart Enterprise License v2 ويباع اشتراكاً لكل صندوق بريد. ويتضمن الإصدار المجاني كل ما يحتاجه هذا الدليل: البروتوكولات كلها، وDKIM وSPF وDMARC وMTA-STS وDANE، وإدارة سجلات DNS التلقائية وتدوير Rotation مفاتيح DKIM، وفلتر الرسائل المزعجة، وLDAP وOpenID Connect، والتشفير على القرص Encryption at Rest. أما الميزات الحصرية للإصدار التجاري كما تسردها صفحة المقارنة فأهمها: لوحة المعلومات Dashboard بالإحصاءات المباشرة، وتعدد المستأجرين Multi-tenancy، وفلتر الرسائل المزعجة بالذكاء الاصطناعي AI / LLM، وأرشفة الحسابات واستعادة الرسائل المحذوفة، وSCIM، وسجل تسليم الرسائل Message Delivery History، والتنبيهات على المقاييس Metric Alerts. ولهذا السبب سوف ترى بجوار Dashboard وTenants في القائمة الجانبية رمز قفل في الإصدار المجاني.
ويجدر الإشارة هنا إلى أمرين: الأول أن ترخيص AGPL لا يفرض عليك شيئاً ما دمت تشغل البرنامج كما هو، وإنما يلزمك بنشر الكود إذا عدلته وقدمته خدمة عبر الشبكة، والثاني أن المشروع يمنح ترخيص Enterprise تلقائياً لمن يدعمه عبر Open Collective بخمسة دولارات شهرياً أو أكثر.
ما تحتاجه قبل أن تبدأ Requirements
السيرفر
- الذاكرة RAM والمعالج CPU: نواة واحدة و1 GB من الذاكرة تكفي لفريق صغير بحسب صفحة المتطلبات، ونحن ننصح بـ 2 GB على الأقل حتى يبقى هامش لنظام التشغيل وDocker وللحظات الضغط، وزد الموارد مع عدد الاتصالات المتزامنة Concurrent Connections، فالحد الافتراضي 8192 اتصالاً تتشاركها كل الخدمات.
- القرص Disk: الـ Docker Image نفسه قرابة 400 MB، وبقية المساحة للرسائل، فاحسبها من عدد الصناديق وحصة Quota كل صندوق.
- النظام: Ubuntu 24.04 مع Docker Engine وإضافة Docker Compose، وإذا لم يكن Docker مثبتاً فاتبع دليل تثبيت Docker على Ubuntu، وإذا كان السيرفر جديداً فابدأ بـ دليل تأمين خادم VPS من أول دخول.
- الاتصال الصادر Outbound: عند التشغيل الأول ينزل Stalwart واجهة الإدارة من إصدارات GitHub، ويتصل بـ Let's Encrypt لإصدار الشهادة، ويستعلم من DNS على المنفذ 53، فإذا كان جدار الحماية Firewall لدى المزود يمنع الاتصال الصادر فاسمح بهذه الثلاثة.
- عنوان IP ثابت Static IP ونظيف، والمنفذ 25 مفتوح: كثير من المزودين يحجبون المنفذ 25 الصادر ولا يفتحونه إلا بطلب، ولا يقبل البريد إلا سيرفر يملك سجل PTR صحيحاً، لذلك تحقق من الأمرين قبل الشراء كما شرحنا في دليل اختيار خادم VPS، وسوف نعود إلى المنفذ 25 في قسم مستقل.
المنافذ: ما الذي يفتح للإنترنت وما الذي يبقى مغلقاً؟
ينشئ Stalwart عند الإعداد مستمعات Listeners لعدة خدمات، ولكن توصية التوثيق الرسمي أن تفتح فقط ما تحتاجه، والسبب أن كل منفذ مفتوح هو باب إضافي لمحاولات التخمين Brute-force والفحص Scanning حتى لو كانت الخدمة خلفه آمنة. والجدول التالي يلخص القرار:
| المنفذ | الخدمة | القرار |
|---|---|---|
| 25/tcp | SMTP | مفتوح للإنترنت، وبه تستقبل البريد من السيرفرات الأخرى |
| 465/tcp | SMTPS (Submission عبر TLS مباشر Implicit TLS) | مفتوح، وبه يرسل المستخدمون من برامج البريد، والتوثيق يفضله على 587 |
| 993/tcp | IMAPS | مفتوح، لقراءة البريد من البرامج والهواتف |
| 443/tcp | HTTPS | مفتوح، للوحة الإدارة وJMAP وautoconfig وMTA-STS وللتحقق من ملكية الاسم عند إصدار الشهادة |
| 8080/tcp | HTTP | للإعداد الأول فقط، ولا يفتح للإنترنت أبداً، ونغلقه بعد الإعداد |
| 995 و4190 | POP3S وManageSieve | لهما مستمعان افتراضياً، ولكن لا تنشرهما إلا إذا احتاجهما مستخدموك |
| 587 و143 | Submission عبر STARTTLS وIMAP دون تشفير | لا ينشئ الإعداد الافتراضي في 0.16 مستمعاً لهما، وتضيفهما من Settings › Network › Listeners إذا احتاجهما برنامج قديم |
ولاحظ أن Docker ينشر المنافذ Publish متجاوزاً قواعد ufw كما شرحنا في دليل تثبيت Docker، لذلك فقائمة ports في ملف Compose هي جدار الحماية الحقيقي لهذه الخدمة، فلا تضع فيها منفذاً لا تريده مفتوحاً، ومع ذلك أضف القواعد إلى ufw حتى يبقى الإعداد واضحاً لمن يأتي بعدك:
sudo ufw allow 25,465,993,443/tcpأين يحفظ Stalwart بياناته؟
يقسم Stalwart التخزين Storage إلى أربعة مخازن: مخزن البيانات Data Store للبيانات المنظمة مثل ترويسات الرسائل والمجلدات والتقويم وكل إعدادات السيرفر، ومخزن الملفات Blob Store لمحتوى الرسائل والمرفقات Attachments، ومخزن البحث Search Store لفهرس البحث النصي Full-text Search، والمخزن المؤقت In-memory Store للعدادات وحدود المعدل Rate Limits والجلسات. والإعداد الافتراضي أن تكون الأربعة كلها في RocksDB، وهي قاعدة بيانات مدمجة Embedded Database تعمل داخل البرنامج نفسه وتحفظ ملفاتها في مجلد واحد، وهذا هو الأنسب لسيرفر واحد.
وفي الأنظمة الكبيرة يمكنك أن تنقل مخزن البيانات إلى PostgreSQL أو MySQL أو FoundationDB، والملفات إلى خدمة متوافقة مع S3، والبحث إلى Elasticsearch أو Meilisearch، والمخزن المؤقت إلى Redis، ولكن تغيير الخلفية Backend بعد التشغيل يحتاج إلى ترحيل البيانات بالتصدير والاستيراد والسيرفر متوقف، لذلك قرر من البداية، ونحن نبقى في هذا الدليل على RocksDB.
اسم السيرفر وسجل A قبل التشغيل
هنا اسمان مختلفان يخلط بينهما كثيرون، فالأول هو اسم خادم البريد Hostname مثل mail.example.com، وبه يعرف السيرفر نفسه أمام السيرفرات الأخرى وله تصدر الشهادة، والثاني هو نطاق البريد مثل example.com، وهو ما يظهر بعد @ في العناوين. وإذا لم تكن مصطلحات DNS واضحة لديك فراجع دليل مصطلحات الاستضافة الذاتية. أضف الآن سجل A للاسم mail.example.com يشير إلى عنوان سيرفرك، وضع عنوانك مكان 203.0.113.10، ثم تأكد منه قبل التثبيت، والسبب أن معالج الإعداد سوف يطلب الشهادة لهذا الاسم مباشرة بعد إعادة التشغيل:
dig +short A mail.example.comوبقية السجلات (MX وSPF وDKIM وDMARC وغيرها) لا تكتبها الآن، لأن Stalwart سوف يولدها لك بقيمها الصحيحة بعد الإعداد كما سيأتي.
التثبيت باستخدام Docker Compose
أنشئ مجلد الخدمة:
sudo mkdir -p /opt/stalwart
sudo chown $USER: /opt/stalwart
cd /opt/stalwartوالملف /opt/stalwart/compose.yaml سوف يكون كما يلي:
services:
stalwart:
image: stalwartlabs/stalwart:v0.16.24
container_name: stalwart
restart: unless-stopped
hostname: mail.example.com
ports:
- "25:25"
- "465:465"
- "993:993"
- "443:443"
- "127.0.0.1:8080:8080"
volumes:
- stalwart_etc:/etc/stalwart
- stalwart_data:/var/lib/stalwart
volumes:
stalwart_etc:
name: stalwart_etc
stalwart_data:
name: stalwart_dataفي الإعداد أعلاه لاحظ التالي:
- الوسم Tag: ثبتنا الإصدار
v0.16.24ولم نستخدمlatest، والسبب أن صفحة الترقية تحذر من أنlatestقد يسحب إصداراً غير متوافق مع بياناتك دون أن تنتبه. وينشر المشروع أيضاً الوسم المختصرv0.16الذي يتحرك مع الإصدارات التصحيحية Patch Releases داخل نفس السلسلة، فإذا أردت التحديثات التصحيحية تلقائياً عند كلpullفاستخدمه، أما نحن فنفضل الوسم الكامل حتى يكون كل تغيير بقرار منك. - ال Volumes: يحفظ
/etc/stalwartملف الإعدادconfig.jsonفقط، ويحفظ/var/lib/stalwartقاعدة RocksDB وفيها كل شيء آخر: الرسائل والحسابات والإعدادات ومفاتيح DKIM، وهما معاً كل ما تحتاج إلى نسخه احتياطياً. ويعمل البرنامج داخل ال Container بالمستخدمstalwartورقمه UID 2000، والتوثيق ينبه إلى أنك إذا استخدمت مجلدات من السيرفر Bind Mounts بدل ال Volumes فيجب أن تكون ملكيتها لهذا الرقم (chown 2000:2000). - المنفذ 8080: ربطناه بالعنوان
127.0.0.1فقط، لأن معالج الإعداد يعمل عليه عبر HTTP دون تشفير، وكلمة مرور المدير المؤقتة تمر فيه، فلا يصح أن يكون مفتوحاً للإنترنت ولو لدقائق. - hostname: يأخذ منه المعالج الاسم الافتراضي للسيرفر والنطاق، فاكتب اسم سيرفرك الحقيقي.
الآن سوف نقوم بالتشغيل:
docker compose up -dعند التشغيل الأول لا يجد Stalwart ملف config.json، فيدخل في وضع التهيئة Bootstrap Mode، وينشئ مديراً مؤقتاً بكلمة مرور عشوائية ويطبعها مرة واحدة فقط في السجل، فاقرأها بالأمر التالي:
docker logs stalwart 2>&1 | grep -A8 'bootstrap mode'والمخرج سوف يكون كما يلي (وكلمة المرور عندك ستة عشر حرفاً عشوائياً):
🔑 Stalwart bootstrap mode - temporary administrator account
username: admin
password: XXXXXXXXXXXXXXXX
Use these credentials to complete the initial setup at the
/admin web UI. Once setup is done, Stalwart will provision a
permanent administrator and this temporary account will no
longer apply.وإذا أردت كلمة مرور ثابتة بدل البحث في السجل، فيمكنك أن تمرر متغير البيئة Environment Variable STALWART_RECOVERY_ADMIN بالصيغة admin:كلمة-المرور، ولكن تذكر أن تحذفه بعد الإعداد كما يوصي التوثيق، والسبب أنه باب خلفي ثابت إلى لوحة الإدارة.
معالج الإعداد الأول Setup Wizard
المنفذ 8080 مربوط بالعنوان 127.0.0.1، لذلك سوف نصل إليه من جهازك عبر نفق SSH Tunnel، فنفذ الأمر التالي على جهازك وليس على السيرفر:
ssh -L 8080:127.0.0.1:8080 [email protected]ثم افتح http://127.0.0.1:8080/admin في متصفحك، واكتب admin ثم كلمة المرور المؤقتة، فيظهر المعالج مباشرة. والصورة التالية تبين الشاشة الأولى منه:

mail.example.com والنطاق example.com، ومعهما خيارا الشهادة التلقائية ومفاتيح التوقيعوالمعالج خمس خطوات، ولكل حقل قيمة افتراضية مناسبة:
- هوية السيرفر Server Identity: اسم السيرفر
mail.example.comونطاق البريد الافتراضيexample.com، ثم خياران تتركهما مفعلين: Automatically Obtain TLS Certificate لطلب شهادة Let's Encrypt تلقائياً، وGenerate Email Signing Keys لإنشاء مفاتيح DKIM للنطاق. ولا تعطل خيار الشهادة إلا إذا كنت سوف تضع Stalwart خلف Reverse Proxy أو ترفع شهادتك بنفسك. - التخزين Storage: اترك RocksDB في المسار
/var/lib/stalwart/، واترك المخازن الثلاثة الأخرى على Use data store. - دليل الحسابات Account Directory: اترك Use the internal directory لتدير الحسابات من اللوحة، أو اختر LDAP أو OIDC إذا كان لديك نظام دخول موحد SSO.
- السجلات Logging: غير القيمة من Log file إلى Console، والسبب كما يشرح التوثيق أن ملفات السجل داخل ال Container تضيع عند إعادة إنشائه، أما Console فيكتب إلى المخرج القياسي Standard Output الذي يحفظه Docker وتقرؤه بـ
docker logs. - إدارة DNS التلقائية: اترك Manual DNS server management إذا كنت سوف تنشر السجلات بيدك، أو اختر مزودك إذا كان في القائمة الطويلة (Cloudflare وAWS Route53 وDigitalOcean وHetzner وOVH وGoDaddy وNamecheap وغيرها، وخادم BIND عبر RFC 2136)، فينشر Stalwart السجلات ويحدثها بنفسه عبر API المزود.
وعند الضغط على Finish setup يعرض المعالج حساب المدير الدائم، وهو بالصيغة [email protected] مع كلمة مرور عشوائية جديدة، فاحفظهما الآن في مدير كلمات المرور Password Manager، لأن الشاشة لا تظهر مرة ثانية وكلمة المرور لا تكتب في السجل. ثم أعد تشغيل ال Container ليعمل بالإعداد الجديد:
docker compose restart stalwartولاحظ ما كتبه المعالج على القرص:
docker exec stalwart cat /etc/stalwart/config.jsonوالمخرج سوف يكون كما يلي:
{"@type":"RocksDb","path":"/var/lib/stalwart/","blobSize":16834,"bufferSize":134217728,"poolWorkers":null,"cacheSize":134217728}سطر واحد يصف قاعدة البيانات فقط، ولا يوجد فيه نطاق ولا حساب ولا منفذ، والسبب أن كل ذلك أصبح منذ الإصدار 0.16 كائنات داخل قاعدة البيانات نفسها، وبالتالي فلا يوجد ملف إعداد تعدله بيدك، وإنما تعدل كل شيء من اللوحة أو من أداة سطر الأوامر stalwart-cli. والآن تأكد من المستمعات التي بدأت بعد إعادة التشغيل:
docker logs stalwart 2>&1 | grep listen-startوالمخرج سوف يكون كما يلي:
INFO Network listener started (network.listen-start) listenerId = "smtp", localIp = ::, localPort = 25, tls = false
INFO Network listener started (network.listen-start) listenerId = "submissions", localIp = ::, localPort = 465, tls = true
INFO Network listener started (network.listen-start) listenerId = "imaps", localIp = ::, localPort = 993, tls = true
INFO Network listener started (network.listen-start) listenerId = "pop3s", localIp = ::, localPort = 995, tls = true
INFO Network listener started (network.listen-start) listenerId = "sieve", localIp = ::, localPort = 4190, tls = false
INFO Network listener started (network.listen-start) listenerId = "https", localIp = ::, localPort = 443, tls = true
INFO Network listener started (network.listen-start) listenerId = "http", localIp = ::, localPort = 8080, tls = falseوتجد القائمة نفسها في اللوحة تحت Settings › Network › Listeners، ومنها تضيف مستمعاً أو تحذفه:

بعد ذلك ادخل من العنوان النهائي https://mail.example.com/admin بحساب المدير الدائم، فإذا ظهر تحذير الشهادة في أول دقيقة فالسبب أن Stalwart يقدم شهادة مؤقتة Self-signed حتى تصدر شهادة Let's Encrypt، ثم احذف السطر "127.0.0.1:8080:8080" من ملف Compose ونفذ docker compose up -d، والتوثيق يوصي أيضاً بحذف المستمع http نفسه من القائمة أعلاه إذا لم تكن سوف تضع Stalwart خلف Reverse Proxy.
إضافة النطاقات وصناديق البريد
النطاق الذي كتبته في المعالج موجود مسبقاً، وتجده في Management › Domains › Domains، ومن الصفحة نفسها تضيف أي نطاق آخر بالزر Create domain، ولاحظ أن سيرفراً واحداً باسم mail.example.com يستطيع أن يخدم عدة نطاقات، وكل نطاق يحتاج إلى سجلاته الخاصة. وفي صفحة النطاق خيارات مفيدة مثل عنوان الالتقاط Catch-All الذي يستقبل الرسائل الموجهة إلى عناوين غير موجودة، والعناوين الفرعية Sub-addressing مثل [email protected].
ولإنشاء صندوق بريد افتح Directory › Accounts ثم Create user، واكتب الجزء الأيسر من العنوان في Username مثل alice، ثم اختر النطاق من زر البحث بجوار Domain، ثم من قسم Credentials اضغط Add item واكتب كلمة المرور، واحفظ بالزر Create. ومن نفس النموذج تضيف عناوين بديلة Email Aliases للحساب، وحصة Quota للمساحة، والمجموعات Groups والأدوار Roles. والصورة التالية تبين قائمة الحسابات بعد إنشاء صندوقين:

[email protected] و[email protected]ولاحظ أن اسم الدخول في Stalwart 0.16 هو العنوان الكامل دائماً، أي [email protected] وليس alice، وفي برامج البريد يكفي غالباً العنوان وكلمة المرور، لأن Stalwart يرد على طلبات الإعداد التلقائي Autoconfiguration، وللإعداد اليدوي استخدم IMAP على mail.example.com بالمنفذ 993 مع SSL/TLS، وSMTP بالمنفذ 465 مع SSL/TLS. وللتطبيقات التي ترسل عبر SMTP مثل listmonk أنشئ صندوقاً مخصصاً مثل [email protected]، واجعل التطبيق يستخدم كلمة مرور تطبيق App Password ينشئها المستخدم من /account، والسبب أن تسريبها لا يكشف الحساب كله وتستطيع إلغاءها وحدها.
وإذا كان لديك بريد قائم على سيرفر آخر، فقد شرحنا في دليل ترحيل البريد بين خادمي mailcow فكرة النقل بـ imapsync دون توقف، ويقدم Stalwart أداته الخاصة Vandelay التي تسحب الحساب من IMAP أو JMAP أو Exchange أو Google Takeout وتنقل معه التقويم وجهات الاتصال.
سجلات DNS التي يولدها Stalwart لك
سجلات DNS هي التي تحدد هل تصل رسائلك أم تضيع، فمنها يقرأ السيرفر المستقبل Receiving Server سجلات SPF وDKIM وDMARC والاستعلام العكسي PTR، وقد شرحنا ما يفعله كل واحد منها في شرح SPF وDKIM وDMARC للمبتدئين. وفي الطريقة اليدوية تكتب هذه السجلات بنفسك وتنسخ مفتاح DKIM من ملف إلى لوحة DNS، أما Stalwart فيبني ملف المنطقة Zone File كاملاً من إعداد النطاق نفسه. افتح Management › Domains › Domains، ثم من قائمة النقاط الثلاث بجوار النطاق اختر View Zone File:

example.com: مفتاحا DKIM وSPF وMX وDMARC وسجلات SRV وMTA-STS وTLS-RPT والإعداد التلقائيوالمخرج الكامل بصيغة نصية كما يلي، مع اختصار مفتاح RSA الطويل:
v1-ed25519-20261004._domainkey.example.com. IN TXT "v=DKIM1; k=ed25519; h=sha256; p=0Instn1qSGKZvePsvuCv6w+imtzCftifRmN9uqAFSTo="
v1-rsa-20261004._domainkey.example.com. IN TXT (
"v=DKIM1; k=rsa; h=sha256; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlebb3EoG…"
"…ZcktLQnuyZ1jVhZQIDAQAB"
)
mail.example.com. IN TXT "v=spf1 a -all"
example.com. IN TXT "v=spf1 mx -all"
example.com. IN MX 10 mail.example.com.
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:[email protected]"
_caldavs._tcp.example.com. IN SRV 0 1 443 mail.example.com.
_carddavs._tcp.example.com. IN SRV 0 1 443 mail.example.com.
_imaps._tcp.example.com. IN SRV 0 1 993 mail.example.com.
_jmap._tcp.example.com. IN SRV 0 1 443 mail.example.com.
_pop3s._tcp.example.com. IN SRV 0 1 995 mail.example.com.
_submissions._tcp.example.com. IN SRV 0 1 465 mail.example.com.
mta-sts.example.com. IN CNAME mail.example.com.
_mta-sts.example.com. IN TXT "v=STSv1; id=17174664717463327589"
_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:[email protected]"
ua-auto-config.example.com. IN CNAME mail.example.com.
_ua-auto-config.example.com. IN TXT "v=UAAC1; a=sha256; d=4PelYnAaYOkI5V2VklhpKxnMk5ou0cd/AVpeYtRzj2w="
autoconfig.example.com. IN CNAME mail.example.com.
autodiscover.example.com. IN CNAME mail.example.com.في الملف أعلاه لاحظ التالي:
- DKIM بمفتاحين: يوقع Stalwart كل رسالة بتوقيعين، الأول بخوارزمية Ed25519 الحديثة والثاني بـ RSA، والسبب أن بعض السيرفرات المستقبلة لا تدعم Ed25519 بعد فتجد مفتاح RSA. انشر السجلين، وانسخ قيمة RSA كاملة من الملف عندك، ولا مشكلة أن تقسمها لوحة DNS إلى عدة سلاسل Strings بين علامات تنصيص ما دامت متتالية.
- SPF بسجلين: سجل للنطاق
example.comيسمح للسيرفر المذكور في MX بالإرسال، وسجل للاسمmail.example.comنفسه، والسبب أن السيرفرات المستقبلة تفحص أيضاً الاسم الذي يقدمه سيرفرك في أمر EHLO. وإذا كنت ترسل باسم النطاق عبر خدمة أخرى مثل نشرة بريدية Newsletter فأضفها إلى سجل النطاق نفسه، مثلv=spf1 mx include:amazonses.com -all، ولا تنشئ سجل SPF ثانياً للنطاق، لأن وجود سجلين يجعل الفحص يفشل. - DMARC يبدأ بالرفض: القيمة التي يولدها Stalwart هي
p=reject، أي أن السيرفرات الأخرى سوف ترفض أي رسالة باسم نطاقك لا تجتاز الفحص، والأسلم أن تنشره أولاً بالقيمةp=noneوتجمع التقارير على[email protected]نحو أسبوعين، ثم تنتقل إلىp=quarantineثمp=reject، والسبب أن خدمة نسيتها ترسل باسم نطاقك سوف تختفي رسائلها بصمت إذا بدأت بالرفض. وأنشئ عنوان[email protected]اسماً بديلاً Alias لحسابك حتى تصلك التقارير. - MTA-STS وTLS-RPT: يخبر MTA-STS السيرفرات الأخرى أن بريد نطاقك يجب أن يصل عبر TLS بشهادة صالحة، ويخدم Stalwart ملف السياسة Policy بنفسه، ولكن هذا يعني أن الاسم
mta-sts.example.comيحتاج إلى شهادة صالحة على المنفذ 443، ويرسل لك سجل TLS-RPT تقارير يومية عن فشل TLS. - الإعداد التلقائي: سجلات
autoconfigوautodiscoverلبرامج Thunderbird وOutlook، وسجلات SRV للبرامج التي تبحث عنها، وسجلاua-auto-configللبروتوكول الجديد PACC الذي يعمل عليه IETF. - ما لا يكتبه Stalwart: سجل A للاسم
mail.example.com(وAAAA إذا كان لديك IPv6) تضيفه أنت كما فعلنا قبل التثبيت، وسجل PTR يضبط لدى مزود السيرفر كما سيأتي. وإذا كنت تستخدم Cloudflare فاجعل سجلmailعلى وضع DNS only دون ال Proxy، والسبب أن ال Proxy يمرر HTTP فقط ولا يمرر منافذ البريد.
بعد نشر السجلات تحقق منها من أي جهاز:
dig +short MX example.com
dig +short TXT example.com
dig +short TXT v1-ed25519-20261004._domainkey.example.com
dig +short TXT _dmarc.example.com
dig +short -x 203.0.113.10النشر التلقائي وتدوير مفاتيح DKIM
إذا كان مزود DNS لديك في قائمة المزودين المدعومين، فاختيار الإدارة التلقائية في المعالج أو في صفحة النطاق يجعل Stalwart ينشر هذه السجلات عند إنشاء النطاق ويحدثها بنفسه، وهذا مهم بشكل خاص لمفاتيح DKIM، لأن Stalwart يدعم تدوير المفاتيح Key Rotation كل 90 يوماً افتراضياً، ولكن صفحة النطاق تنص على أن التدوير يحتاج إلى إدارة DNS تلقائية، والسبب منطقي: المفتاح الجديد يجب أن ينشر في DNS قبل أن يبدأ التوقيع به، ولا يستطيع السيرفر فعل ذلك في لوحة لا يصل إليها. ومع الإدارة اليدوية تبقى المفاتيح التي أنشأها المعالج كما هي، فإذا أنشأت مفتاحاً جديداً بنفسك لاحقاً من Management › Domains › DKIM Signatures فانشر سجله قبل أن تفعله.
سجل PTR لدى مزود السيرفر
سجل PTR أو rDNS لا يضبط من لوحة DNS الخاصة بنطاقك، وإنما من لوحة مزود ال VPS باسم Reverse DNS، والسبب شرحناه في شرح DNS وسجلاته للمبتدئين. اضبطه على mail.example.com تماماً، وتأكد أن سجل A لهذا الاسم يعيد العنوان نفسه، وبدون هذا التطابق ترفض Gmail كثيراً من الرسائل أو تصنفها رسائل مزعجة، وإذا أضفت سجل AAAA فاضبط PTR لعنوان IPv6 أيضاً.
شهادة TLS: ACME المدمج أم Reverse Proxy؟
الشهادة المدمجة: الطريق الأبسط
إذا كان Stalwart وحده على السيرفر ويملك المنفذ 443، فالخيار الذي تركته مفعلاً في المعالج يكفي، حيث يطلب Stalwart الشهادة من Let's Encrypt ويجددها Renewal بنفسه ويستخدمها في SMTP وIMAP وHTTPS معاً. ويشرح دليل Docker الرسمي طريقة التحقق: مع الإدارة اليدوية لسجلات DNS يستخدم Stalwart التحقق عبر TLS-ALPN-01، أي أن Let's Encrypt تتصل مباشرة بسيرفرك على المنفذ 443، لذلك يجب أن يكون المنفذ مفتوحاً للإنترنت، وألا يعترضه Reverse Proxy أو Load Balancer، وأن يشير سجل A إلى السيرفر. أما مع مزود DNS تلقائي فيستخدم التحقق من ملكية النطاق عبر ال DNS (DNS Challenge) بطريقة DNS-01، ولا يحتاج إلى أي منفذ مفتوح. وتجد إعداد الشهادة لكل نطاق في صفحته تحت Certificate Management، ومزودي ACME في Settings › TLS › ACME Providers.
كيف تشغل Stalwart خلف Reverse Proxy؟
إذا كان لديك على السيرفر نفسه Reverse Proxy مثل Nginx Proxy Manager أو Traefik يملك المنفذين 80 و443 لتطبيقات أخرى، فالقاعدة الأولى أن ال Reverse Proxy يخدم HTTP فقط، أي لوحة الإدارة وJMAP وautoconfig وMTA-STS، أما منافذ البريد 25 و465 و993 فتبقى منشورة مباشرة من Container الخاص بـ Stalwart.
لنأخذ مثالاً مع Nginx Proxy Manager على الشبكة proxy التي أنشأناها في دليله، حيث يصل ال Proxy إلى Stalwart باسمه داخل شبكة Docker دون أن ننشر منفذ الواجهة على السيرفر، وقد شرحنا سبب ذلك في دليل شبكات Docker وأفضل الممارسات. فيصبح ملف Compose كما يلي، ولاحظ أن المنفذين 443 و8080 لم يعودا منشورين على السيرفر:
services:
stalwart:
image: stalwartlabs/stalwart:v0.16.24
container_name: stalwart
restart: unless-stopped
hostname: mail.example.com
environment:
STALWART_PUBLIC_URL: https://mail.example.com
ports:
- "25:25"
- "465:465"
- "993:993"
volumes:
- stalwart_etc:/etc/stalwart
- stalwart_data:/var/lib/stalwart
networks:
- proxy
volumes:
stalwart_etc:
name: stalwart_etc
stalwart_data:
name: stalwart_data
networks:
proxy:
external: trueفي الإعداد أعلاه لاحظ التالي:
- في NPM أنشئ Proxy Host للأسماء
mail.example.comوautoconfig.example.comوautodiscover.example.comوmta-sts.example.comيوجه الطلبات إلىhttp://stalwart:8080، ثم فعل Websockets Support وForce SSL وشهادة Let's Encrypt، وهذا هو نمط HTTP Upstream الذي يوصي به التوثيق لبساطته. - المتغير
STALWART_PUBLIC_URLيخبر Stalwart بالعنوان الذي يراه المستخدمون، لأنه يكتبه في مستندات الاكتشاف Discovery Documents الخاصة بـ OAuth وJMAP، وإذا لم يطابق عنوان ال Proxy فسوف تجد صفحة الدخول تدور في حلقة. وقيمته هنا تطابق القيمة الافتراضيةhttps://mail.example.com، ولكننا نكتبه صراحة لأنك سوف تحتاج إلى تغييره إذا نشرت ال Proxy على منفذ آخر غير 443 أو تحت مسار فرعي. - يرى Stalwart كل الطلبات قادمة من عنوان ال Proxy، ولأن الحظر التلقائي Auto-ban يحسب محاولات الدخول الفاشلة لكل عنوان، فقد يحظر ال Proxy نفسه ويغلق اللوحة على الجميع. لذلك فعل الحقل
useXForwardedفي Settings › Network › HTTP حتى يقرأ العنوان الحقيقي من الترويسة X-Forwarded-For، وأضف شبكة Docker الخاصة بال Proxy إلى الشبكات الموثوقة Trusted Networks كما يشرح التوثيق. - أكمل المعالج قبل أن تضع ال Proxy في الطريق، والتوثيق نفسه ينصح بالوصول إلى
http://<host>:8080/adminمباشرة أثناء المعالج وأول دخول، ثم إعادة ال Proxy بعد ذلك.
وتبقى مسألة الشهادة على منافذ البريد، فـ SMTP وIMAP يحتاجان إلى شهادة صالحة للاسم mail.example.com، ولكن ال Proxy أصبح يملك المنفذ 443، فلا تستطيع Let's Encrypt الوصول إلى Stalwart بطريقة TLS-ALPN-01. والحل الأنسب أن يصدر Stalwart شهادته عبر DNS-01 مع مزود DNS تلقائي، فلا يحتاج إلى أي منفذ، والبديل الذي يعرضه دليل Traefik الرسمي أن يقرأ Stalwart ملفات الشهادة التي يصدرها Traefik من Volume مشترك عبر كائن Certificate في Settings › TLS › Certificates.
المنفذ 25: تأكد منه قبل أن تبحث في الإعداد
أكثر سبب يضيع فيه وقت من يبني خادم بريد لأول مرة هو أن يقضي ساعات في مراجعة الإعداد، والمشكلة أن المزود يحجب المنفذ 25 الصادر من الأساس، فمثلاً تحجب Hetzner المنفذين 25 و465 على سيرفرات Cloud حتى تطلب فتحهما، وتحجب DigitalOcean منافذ SMTP، وتقيد AWS المنفذ 25 على EC2. لذلك نفذ هذا الأمر من السيرفر نفسه قبل أي شيء، فإذا انتهت المهلة دون اتصال فالمزود يحجبه:
nc -vz -w 5 gmail-smtp-in.l.google.com 25ومن جهاز آخر تأكد أن المنفذ 25 الداخل يصل إلى Stalwart:
nc -v mail.example.com 25والمخرج سوف يكون سطراً كما يلي:
220 mail.example.com Stalwart ESMTP at your serviceوإذا رفض المزود فتح المنفذ الصادر، فأرسل عبر خادم وسيط Relay مثل Amazon SES، ويدعم Stalwart ذلك من خلال مسارات التوجيه Routes من النوع Relay في Settings › MTA › Outbound › Routes، وعندها أضف الوسيط إلى سجل SPF وانشر سجلات DKIM التي يطلبها.
فلتر الرسائل المزعجة المدمج Spam Filter
في mailcow يقوم بهذا الدور Rspamd في Container مستقل، أما Stalwart فيحمل فلتره داخل البرنامج، ومعظم قواعده Rules منقولة من Rspamd مع بعضها من SpamAssassin، ومعه مصنف إحصائي Statistical Classifier يتعلم تلقائياً، وقوائم الحظر DNSBL، وPyzor، والحماية من التصيد Phishing. وطريقة عمله أن كل فحص يضيف وسماً Tag له درجة Score موجبة أو سالبة، فإذا تجاوز المجموع 5.0 (القيمة الافتراضية) صنفت الرسالة رسالة مزعجة، ولاحظ أن الفلتر لا يرفض أي رسالة افتراضياً بسبب درجتها، وإنما يضيف الترويستين X-Spam-Status وX-Spam-Result وينقل الرسالة إلى مجلد Junk Mail.
والآن لنكسر الأمر لنفهمه، فنرسل من سيرفر خارجي دون مصادقة Authentication رسالة فيها نص الاختبار GTUBE المعروف:
swaks --server mail.example.com --port 25 --ehlo client.example.net \
--from [email protected] --to [email protected] \
--header 'Subject: spam test' \
--body 'XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X'يقبل السيرفر الرسالة بالرد 250 2.0.0 Message queued، ولكنها لا تصل إلى صندوق الوارد Inbox، وإنما إلى مجلد Junk Mail، وفي ترويستها ما يشبه ما يلي:
X-Spam-Status: Yes
Authentication-Results: mail.example.com;
spf=none (mail.example.com: no SPF records found for [email protected]) [email protected];
dmarc=none header.from=example.net policy.dmarc=none
X-Spam-Result: …
RCVD_NO_TLS_LAST (0.10),
HELO_NORES_A_OR_MX (0.30),
AUTH_NA (1.00),
DMARC_NA (1.00),
HELO_IPREV_MISMATCH (1.00),
DIRECT_TO_MX (2.00),
PYZOR (3.50)
X-Spam-Score: spam, score=9.50في المخرج أعلاه لاحظ التالي:
- كل سطر في
X-Spam-Resultفحص مستقل ودرجته، وهنا جمعت الرسالة 9.50، أي ضعف الحد تقريباً، وأكبر جزء منها من Pyzor الذي عرف نص الاختبار في قاعدة بصماته المشتركة. - الترويسة
Authentication-Resultsهي نفس ما سوف تراه في Gmail عندما تفحص رسائلك أنت، فإذا ظهر فيهاspf=failأوdkim=failلرسالة من نطاقك فالمشكلة في سجلاتك وليست في الفلتر. - الحد والدرجات تغيرها من Settings › Spam Filter، فإذا أردت رفض الرسائل التي تتجاوز درجة معينة بدل نقلها إلى Junk Mail، فهناك حدان مستقلان للرفض Reject والحذف Discard.
التحقق من النجاح Verification
أول اختبار أن ترسل من صندوق إلى آخر عبر منفذ الإرسال 465 بأداة swaks (تثبتها بالأمر sudo apt install swaks)، وهذا الاختبار يمر بالمصادقة والتوقيع والتسليم المحلي معاً:
swaks --server mail.example.com --port 465 --tls-on-connect \
--auth PLAIN --auth-user [email protected] --auth-password 'ALICE_PASSWORD' \
--from [email protected] --to [email protected] \
--header 'Subject: Hello from Stalwart' --body 'First test message.'والمخرج سوف يكون مشابهاً لما يلي، وهنا ردود السيرفر فقط:
<~ 220 mail.example.com Stalwart ESMTP at your service
<~ 250-mail.example.com you had me at EHLO
<~ 250-SMTPUTF8
<~ 250-SIZE 104857600
<~ 250-REQUIRETLS
<~ 250-PIPELINING
<~ 250-NO-SOLICITING
<~ 250-ENHANCEDSTATUSCODES
<~ 250-CHUNKING
<~ 250-BINARYMIME
<~ 250-AUTH PLAIN LOGIN XOAUTH2 OAUTHBEARER
<~ 250 8BITMIME
<~ 235 2.7.0 Authentication succeeded.
<~ 250 2.1.0 OK
<~ 250 2.1.5 OK
<~ 354 Start mail input; end with <CRLF>.<CRLF>
<~ 250 2.0.0 Message queued with id 49fa5820c800000.
<~ 221 2.0.0 Bye.ثم اقرأ صندوق bob عبر IMAPS، ويكفي لذلك curl دون برنامج بريد:
curl --user '[email protected]:BOB_PASSWORD' imaps://mail.example.com/INBOX -X 'STATUS INBOX (MESSAGES UNSEEN)'
curl --user '[email protected]:BOB_PASSWORD' 'imaps://mail.example.com/INBOX;UID=1'والمخرج سوف يكون كما يلي، مع اختصار قيم التوقيع:
* STATUS "INBOX" (MESSAGES 1 UNSEEN 1)
Delivered-To: [email protected]
X-Spam-Status: No
DKIM-Signature: v=1; a=ed25519-sha256; s=v1-ed25519-20261004; d=example.com; c=relaxed/relaxed; r=y;
h=Message-Id:Subject:From:To:Date; t=1791146346; bh=yTj4jPdXqVNiOvyezvK+ypy…
DKIM-Signature: v=1; a=rsa-sha256; s=v1-rsa-20261004; d=example.com; c=relaxed/relaxed; r=y;
h=Message-Id:Subject:From:To:Date; t=1791146346; bh=yTj4jPdXqVNiOvyezvK+ypy…
Date: Sun, 04 Oct 2026 20:39:05 +0000
To: [email protected]
From: [email protected]
Subject: Hello from Stalwart
First test message.لاحظ التوقيعين بالمحددين Selectors v1-ed25519-20261004 وv1-rsa-20261004، وهما نفس أسماء سجلات DKIM في ملف المنطقة، فإذا اختلفا فالسجل الذي نشرته لن يجده أحد. وبعد ذلك أكمل بهذه الفحوص:
- أرسل رسالة إلى حساب Gmail ثم افتح Show original، وتأكد أن نتيجة SPF وDKIM وDMARC هي
PASS، وللتقييم الكامل أرسل رسالة إلى mail-tester.com.
أرسل من حساب خارجي إلى [email protected]، وعند أي مشكلة راجع السجل:
docker logs --tail 100 stalwartالشهادة من Let's Encrypt وليست الشهادة المؤقتة، على HTTPS وعلى منفذ الإرسال:
echo | openssl s_client -connect mail.example.com:443 -servername mail.example.com 2>/dev/null | openssl x509 -noout -issuer -dates
echo | openssl s_client -connect mail.example.com:465 2>/dev/null | openssl x509 -noout -issuerوإذا ظهر CN=rcgen self signed cert فما زالت الشهادة المؤقتة هي المستخدمة.
السيرفر ليس مفتوحاً للترحيل Open Relay، فنفذ من جهاز خارجي محاولة إرسال إلى نطاق آخر دون مصادقة:
swaks --server mail.example.com --port 25 --ehlo client.example.net \
--from [email protected] --to [email protected] --quit-after RCPTوالرد الصحيح هو 550 5.1.2 Relay not allowed.، ولا تكرر هذه المحاولة كثيراً، لأن الحظر التلقائي يحظر العنوان بعد 35 محاولة ترحيل في اليوم افتراضياً.
النسخ الاحتياطي والاستعادة Restore
مع RocksDB كل شيء في مجلدين: /etc/stalwart وفيه config.json، و/var/lib/stalwart وفيه قاعدة البيانات بكل الرسائل والحسابات والإعدادات ومفاتيح DKIM، والتوثيق ينص على أن نسخ هذا المجلد يكفي لنسخة كاملة. ولكن RocksDB قاعدة مدمجة تكتب ملفاتها باستمرار، والنسخ والسيرفر يعمل قد يعطيك نسخة غير متسقة، لذلك فالطريقة الآمنة التي يستخدمها دليل الترقية الرسمي نفسه أن توقف ال Container ثم تنسخ ثم تشغله، وهذا يستغرق ثوان، والسيرفرات المرسلة تعيد المحاولة تلقائياً إذا وجدت المنفذ 25 مغلقاً لحظتها:
sudo mkdir -p /opt/backup/stalwart
cd /opt/stalwart
docker compose stop stalwart
docker run --rm \
-v stalwart_etc:/etc/stalwart:ro \
-v stalwart_data:/var/lib/stalwart:ro \
-v /opt/backup/stalwart:/backup \
ubuntu:24.04 tar czf /backup/stalwart-$(date +%F).tar.gz /etc/stalwart /var/lib/stalwart
docker compose start stalwartال Container المؤقت يربط ال Volumes بوضع القراءة فقط ro ويضغطهما في ملف واحد باسم التاريخ، ثم يحذف نفسه. وللجدولة Scheduling اليومية ضع الأوامر في سكربت ثم أضفه إلى crontab في وقت هادئ مثل الثانية فجراً، ثم انقل الملفات إلى تخزين خارجي Offsite Storage بأداة مثل restic أو rclone، والسبب أن النسخة على قرص السيرفر نفسه لا تحميك إذا تعطل السيرفر. واحفظ معها ملف compose.yaml.
وللاستعادة على سيرفر جديد ثبت Docker وانسخ compose.yaml وملف النسخة، ثم أنشئ ال Volumes فارغة دون تشغيل، وفك النسخة فيها، ثم شغل:
cd /opt/stalwart
docker compose up --no-start
docker run --rm \
-v stalwart_etc:/etc/stalwart \
-v stalwart_data:/var/lib/stalwart \
-v /opt/backup/stalwart:/backup \
ubuntu:24.04 tar xzpf /backup/stalwart-2026-10-04.tar.gz -C /
docker compose start stalwartالخيار p في tar يحفظ الملكية للمستخدم 2000 كما كانت، وعند التشغيل لا يدخل Stalwart في وضع التهيئة لأنه يجد config.json، وتعود الحسابات والرسائل كما كانت. ولا تخلط هذا بالخيارين --export و--import في البرنامج، فهما لترحيل البيانات بين خلفيات التخزين، والتوثيق ينص صراحة على أنهما ليسا بديلاً عن النسخ الاحتياطي.
docker compose down -v بعد أن تتأكد أن ملف النسخة سليم، واختبر الاستعادة دورياً على سيرفر مؤقت حتى تعرف أن نسخك صالحة فعلاً.التحديث إلى إصدار أحدث
يتبع Stalwart الترقيم الدلالي Semantic Versioning، فالإصدار التصحيحي (الرقم الأخير، مثل الانتقال من 0.16.23 إلى 0.16.24) يحمل إصلاحات متوافقة فقط، والإصدار الثانوي (الرقم الأوسط، مثل 0.17) قد يحتاج إلى تغيير في الإعداد أو ترحيل للبيانات، وقبل 1.0 قد يحمل تغييرات غير متوافقة كما حدث في 0.16. لذلك فالتحديث التصحيحي بسيط: خذ نسخة احتياطية، ثم غير الوسم في compose.yaml إلى الإصدار الجديد من صفحة الإصدارات، ثم:
cd /opt/stalwart
docker compose pull
docker compose up -d
docker logs --tail 30 stalwartوتأكد في السجل من السطر Starting Stalwart Server ورقم الإصدار الجديد، ثم احذف ال Image القديم بوسمه، مثل docker image rm stalwartlabs/stalwart:v0.16.23، والسبب أن docker image prune وحده لا يحذف Image ما زال يحمل وسماً. أما الانتقال إلى إصدار ثانوي جديد فلا تفعله قبل أن تقرأ ملاحظات الإصدار وملف الترقية الخاص به في المجلد UPGRADING، وجربه أولاً على نسخة من بياناتك في سيرفر مؤقت. ولاحظ أن واجهة الإدارة تتحدث وحدها من GitHub بشكل مستقل عن البرنامج، فقد ترى تغييراً في شكلها دون أن تغير الوسم.
مشكلات شائعة وحلولها Troubleshooting
الصفحة /admin تعطي 404 Not Found
واجهة الإدارة ليست داخل ال Docker Image، وإنما ينزلها Stalwart من GitHub عند التشغيل الأول، فإذا كان الاتصال الصادر بـ github.com وobjects.githubusercontent.com ممنوعاً فلن يجد ما يعرضه، ويبقى باقي السيرفر يعمل بشكل طبيعي. والحل أن تسمح بالاتصال الصادر عبر HTTPS ثم تعيد التشغيل، وفي البيئات المغلقة يمكنك أن تضع الحزمة على سيرفر داخلي وتغير عنوانها كما يشرح توثيق الواجهة.
ضاعت كلمة المرور المؤقتة أو حساب المدير
كلمة مرور وضع التهيئة تظهر مرة واحدة، فإذا ضاعت قبل أن تكمل المعالج فأسهل حل أن تبدأ من جديد بالأمر docker compose down -v ثم docker compose up -d، لأنه لا توجد بيانات بعد. أما إذا فقدت الدخول بعد الإعداد فشغل Stalwart في وضع الاسترداد Recovery Mode بإضافة المتغيرين STALWART_RECOVERY_MODE: "1" وSTALWART_RECOVERY_ADMIN: admin:كلمة-مرور-مؤقتة إلى environment، وأعد السطر "127.0.0.1:8080:8080" إلى قائمة ports، فيفتح Stalwart المستمع 8080 ويقبل هذا الحساب، وبعد أن تصلح الحساب احذف المتغيرين والسطر وأعد التشغيل.
المتصفح وبرامج البريد تحذر من الشهادة
التحذير يعني أن Stalwart ما زال يقدم الشهادة المؤقتة، فراجع docker logs stalwart وابحث عن أخطاء ACME، والأسباب المعتادة: سجل A لا يشير إلى السيرفر، أو المنفذ 443 مغلق في جدار الحماية لدى المزود، أو Reverse Proxy يعترض الاتصال فيفشل التحقق بطريقة TLS-ALPN-01، وفي هذه الحالة انتقل إلى DNS-01 كما شرحنا في قسم ال Reverse Proxy.
الرد 550 5.5.0 Invalid EHLO domain
يرفض Stalwart الاتصال على المنفذ 25 إذا قدم الطرف الآخر في أمر EHLO اسماً غير صالح، مثل اسم Container قصير أو كلمة دون نطاق، وهذا فحص مقصود لأن السيرفرات الحقيقية تقدم اسماً كاملاً FQDN. فإذا ظهر لك هذا الخطأ وأنت تختبر من سكربت أو تطبيق، فمرر اسماً كاملاً مثل --ehlo client.example.net في swaks، أو اضبط اسم المضيف Hostname في التطبيق المرسل، وإذا كان التطبيق داخلياً فالأفضل أن يرسل عبر المنفذ 465 بمصادقة.
التحذير DANE has been disabled في السجل
ستجد في السجل عند التشغيل سطراً مثل:
WARN Configuration build warning (registry.build-warning) source = "DnsResolver", reason = "The configured DNS resolver cannot validate DNSSEC. DANE has been disabled to avoid deferring mail. Ensure the resolver is DNSSEC-capable and reachable over TCP."والمعنى أن خادم DNS الذي يستخدمه السيرفر لا يتحقق من DNSSEC، فعطل Stalwart التحقق عبر DANE حتى لا يؤخر الرسائل، والبريد يعمل بشكل طبيعي. وإذا أردت DANE فاجعل السيرفر يستخدم خادم DNS يتحقق من DNSSEC ويقبل الاستعلامات عبر TCP، ثم أعد التشغيل.
لا يستطيع أحد الدخول خلف ال Reverse Proxy
إذا كانت اللوحة تعمل ثم توقفت فجأة لكل المستخدمين، فغالب الظن أن الحظر التلقائي حظر عنوان ال Proxy نفسه بعد عدة محاولات دخول فاشلة، لأن Stalwart يرى كل الطلبات قادمة منه. افتح Settings › Security › Blocked IPs من داخل الشبكة واحذف العنوان، ثم فعل قراءة العنوان الحقيقي كما في قسم ال Reverse Proxy حتى لا يتكرر ذلك. وإذا كانت صفحة الدخول تدور في حلقة دون رسالة خطأ فالسبب غالباً أن STALWART_PUBLIC_URL لا يطابق العنوان الذي يفتحه المستخدم.
رسائلك تصل إلى الرسائل المزعجة لدى الآخرين
- PTR غير مطابق: تأكد أن
dig +short -x 203.0.113.10يعيدmail.example.com، وأن سجل A لهذا الاسم يعيد العنوان نفسه. - فشل DKIM: قارن المحدد في ترويسة
DKIM-Signatureبالسجل المنشور، فالسبب الأشهر مفتاح RSA نسخ ناقصاً أو بمسافات زائدة. - عنوان IP في قوائم الحظر: افحصه لدى Spamhaus وMXToolbox، فبعض المزودين يعطونك عنواناً يحمل سمعة سيئة من مستخدم سابق.
- سمعة Reputation جديدة: السيرفرات الأخرى تتعامل بحذر مع سيرفر ليس له تاريخ إرسال Sending History، لذلك ابدأ بحجم صغير، ولا ترسل الحملات التسويقية من خادم البريد الأساسي.
الخلاصة
وصلنا لنهاية الموضوع، وأهم ما فيه:
- Stalwart خادم بريد كامل في برنامج واحد، يكفيه 1 GB من الذاكرة لفريق صغير بدل 6 GiB في mailcow، ولكنه لا يتضمن بريداً عبر الويب، وما زال في 0.x وقد تحتاج إصداراته الثانوية إلى ترحيل، فثبت الوسم واقرأ ملاحظات كل إصدار.
- ثبته بـ Docker Compose مع Volume للإعداد وآخر للبيانات، واربط المنفذ 8080 بـ
127.0.0.1، واقرأ كلمة المرور المؤقتة من السجل، ثم احفظ حساب المدير الدائم من الشاشة الأخيرة في المعالج. - انشر السجلات من ملف المنطقة الذي يولده Stalwart، وابدأ DMARC بالقيمة
p=noneبدلp=reject، واضبط PTR لدى المزود، وتأكد من المنفذ 25 قبل أي شيء آخر. - خلف Reverse Proxy مرر HTTP فقط، واترك 25 و465 و993 مباشرة، واضبط
STALWART_PUBLIC_URLوالعنوان الحقيقي للمستخدمين، واستخدم DNS-01 للشهادة. - انسخ المجلدين والسيرفر متوقف إلى تخزين خارجي يومياً، واستعد دائماً إلى Volumes فارغة، وطبق الإصدارات التصحيحية دون تأجيل.
ولتختار بين mailcow وStalwart وPostfix مع Dovecot اقرأ مقارنة خوادم البريد، وفيها نقاط القوة ونقاط الضعف في كل منها حتى تختار ما يناسب فريقك.
سجل التحديثات Changelog
- أكتوبر 2026: كتابة الدليل واختباره على Stalwart 0.16.24.