إعداد البريد الإلكتروني الوارد بالتسليم المباشر للمواقع المستضافة ذاتيًا باستخدام Mail-Receiver

كيف يمكن تعطيل دعم DMARC بالضبط؟

أي، إضافة INCLUDE_DMARC: false إلى قسم env في mail-receiver.yml لا يبدو أنه يقوم بذلك. هذا يبدو أنه يتسبب في عدم تشغيل عمليتي opendkim و opendmarc (مما يؤدي إلى تحذير في السجلات)، ولكن لا يزال يتم إجراء فحص SPF.

تم التعديل للإضافة:
أعتقد أنني تمكنت من تعطيل فحوصات SPF عن طريق إضافة سطر POSTCONF_ التالي أيضًا إلى قسم env:

env:
  ...
  INCLUDE_DMARC: false
  POSTCONF_smtpd_recipient_restrictions: check_policy_service unix:private/policy
  ...

حصلت على هذا من خلال النظر إلى الالتزام الذي قدم فحوصات DMARC، ورؤية ما يجب أن يحدث عندما يكون INCLUDE_DMARC خاطئًا.

لا أعرف شيئًا تقريبًا عن كيفية بناء صور docker، ولكني أصبحت أدرك أن علامة INCLUDE_DMARC هي شيء مخصص ليتم تعيينه بواسطة شخص آخر، في مكان آخر، في وقت آخر — وليس شيئًا يمكن القيام به في mail-receiver.yml.

إعجابَين (2)

لقد وجدت الحاجة إلى فتح المنفذ 443 على ufw — وإلا حصلت على API Request Preparation Failed في logs. أعتقد أنه من الأفضل ذكر ذلك لأن تعليمات التثبيت القياسية تذكر تمكين ufw.

يتم ذكر المنفذ 25 في mail-receiver.yml ويبدو أنه يتجاوز ufw.

إعجاب واحد (1)

هل يجب أن يكون مستودع GitHub في OP؟

3 إعجابات

مستخدمو مستقبِل البريد، يرجى الاطلاع على Remove smtp_should_reject & discourse-smtp-fast-rejection

سنقوم بإزالة الرفض السريع بالكامل لأن الميزة الأصلية كانت معطلة وتسبب مشاكل للمستخدمين، وتحديداً هذا النوع من الأشياء:

كما أنه يؤثر على البريد المُعاد توجيهه لأن اختبار ما قبل التسليم كان يتحقق من envelope-from و envelope-to، بينما يستخدم Discourse القيم الموجودة في الرؤوس فقط.

إعجاب واحد (1)

لقد أرسلت للتو طلب سحب لإزالة علامات الاقتباس غير الضرورية حول قيمة DISCOURSE_BASE_URL في ملف العينة mail-receiver.yml. كانت علامات الاقتباس هذه تعطل الإعداد الخاص بي. التخلص من علامات الاقتباس يسمح بالإكمال الناجح لهذه الوثيقة.

هل يمكنك شرح كيف؟ وجود/عدم وجود علامات اقتباس حول هذه القيمة لا ينتج عنه أي فرق:

[2] pry(main)=> YAML::load("env:\n  DISCOURSE_BASE_URL: 'https://discourse.example.com'")
=> {"env"=>{"DISCOURSE_BASE_URL"=>"https://discourse.example.com"}}

[3] pry(main)=> YAML::load("env:\n  DISCOURSE_BASE_URL: https://discourse.example.com")
=> {"env"=>{"DISCOURSE_BASE_URL"=>"https://discourse.example.com"}}

عندما كنت أتابع سجلات تلك الحاوية وأرسل رسائل إليها، كنت أرى الكثير من الأخطاء التي تذكر شيئًا مثل discourse.example.com is not part of MX records أو ما شابه. أزلت علامات الاقتباس، وأعدت بناء الحاوية، وبدأ العمل :person_shrugging:

قد تكون لتسلسل الأحداث أهمية أيضًا:

  1. قمت بتهيئة وتشغيل حاوية استقبال البريد (mail-receiver container)
  2. بعد بضعة أيام، قمت بإعداد سجلات MX DNS
  3. تحققت من أن سجلات MX تم تعيينها بشكل صحيح ثم بدأت الاختبار. لم يكن الأمر يعمل
  4. أزلت علامات الاقتباس، وأعدت بناء الحاوية، وبدأ العمل

لذا، لست متأكدًا مما إذا كان الحل متعلقًا بإزالة علامات الاقتباس، أو إعادة بناء الحاوية بعد إنشاء سجلات MX.

في أسوأ الأحوال، تجعل طلب السحب (PR) ملف yml متسقًا :slight_smile:

إعجاب واحد (1)

يبدو أن هناك افتراضًا بأن مستلم البريد سيكون دائمًا بنفس نطاق المنتدى الأساسي. عندما لا تكون هذه هي الحالة، كيف نقوم بإعداد بروتوكول أمان طبقة النقل (TLS)؟

على سبيل المثال:
forum => forum.domain.tld
mail-receiver => mail.domain.tld

في ملف mail-receiver.yml، يشير بروتوكول TLS إلى شهادات المنتدى الأساسي. هل هناك طريقة لجعل مستلم البريد يحصل على شهاداته الخاصة؟

لا أعرف الإجابة المباشرة، على الرغم من أنني أظن أن هذا سيتطلب خيارات إضافية في ملف yml لإجراء تعديلات في الحاوية أثناء البناء.

المزيد حول هذا سيأتي لاحقًا، ولكن أتساءل ما هو سبب رغبتك في تشغيله على نطاق مختلف. إن مستقبل البريد الإلكتروني مُصمم خصيصًا ويعمل، بدون تعديلات، حصريًا لاستقبال رسائل البريد الإلكتروني لمثيل Discourse مقترن به، لذا فمن المعقول عادةً أن يعمل على نفس النطاق مثل ذلك المثيل.


إذا ألقيت نظرة على بعض القوالب لإدراجها في ملف Discourse yml الخاص بك، وبعضها سيتم استخدامه بالفعل، فيجب أن تكون قادرًا على الحصول على بعض التلميحات حول كيفية تشغيل الأوامر وتعديل الملفات عبر ملف yml (أثناء بناء الحاوية).

يحتوي web.onion.template.yml على بعض الأمثلة حول كيفية استبدال السلاسل النصية داخل الملفات، وweb.letsencrypt.ssl.template.yml هو الملف الذي يضيف Let’s Encrypt إلى حاوية Discourse الرئيسية.

لا أعرف مدى اعتماد ذلك على الأشياء الموجودة في الصورة الأساسية، لذا فمن المحتمل أن يكون من الأسهل جعل حاوية Discourse الرئيسية تحصل على شهادة ثانية، ثم مجرد تغيير مسارات الشهادة/المفتاح في mail-receiver.yml لتتطابق.

كن حذرًا مع هذه الأنواع من التغييرات إذا اتبعت هذا النهج، وتأكد من معرفتك الدقيقة للتأثير الذي سيحدثه التغيير. قد يؤدي التغيير الخاطئ في إعدادات Let’s Encrypt إلى فشل تجديد الشهادات بصمت، على سبيل المثال، وهو ما قد لا تلاحظه حتى حوالي 3 أشهر لاحقًا عندما يبدأ الزوار في رؤية أخطاء الشهادات منتهية الصلاحية.

حالة استخدام CloudFlare

هذه التعليمات مخصصة لمنتديات Discourse المستضافة ذاتيًا والتي تستخدم وكيل Cloudflare.

عند استخدام وكيل Cloudflare، يمنع هذا وصول أي حركة مرور SMTP (المنفذ 25) إلى الخادم الخاص بك على الإطلاق. يتطلب هذا منك إعداد اسم نطاق فرعي مختلف لكي يعمل مُستقبِل البريد.

على سبيل المثال، إذا كان اسم النطاق الخاص بك هو forums.domain.tld، فستحتاج إلى إنشاء اسم نطاق فرعي جديد، مثل mail.domain.tld.

مع Cloudflare، لديك خطوات إضافية أدناه.

  1. إنشاء سجل A لاسم النطاق الفرعي الجديد. سيستخدم نفس عنوان IP الخاص بـ forums.domain.tld الخاص بك.
  2. إنشاء سجل MX لاسم النطاق الفرعي الجديد كما هو موضح في التعليمات الرئيسية.

اتبع مجموعات التعليمات الرئيسية مع هذا التغيير الطفيف. سيعمل بشكل جيد تمامًا مع إيقاف تشغيل أمان TLS.

إذا كنت ترغب في تشغيل أمان TLS، فسيتطلب هذا عملًا إضافيًا.

نظرة عامة على إعداد TLS

ستقوم هذه التعليمات بتثبيت Certbot وإضافة مكون إضافي لـ Certbot الخاص بـ CloudFlare. ستحصل الأوامر على شهادات LetsEncrypt في وضعية الاستقلال عبر عملية شهادة DNS. بمجرد توفر الشهادات، يتم نسخها إلى منطقة البريد المُستقبِل المشتركة ليستخدمها الحاوية. يجب علينا استخدام نموذج DNS، نظرًا لأن Discourse لديه بالفعل المنفذ 80 مستخدماً.

تحدي DNS

بدلاً من إثبات ملكية النطاق عبر HTTP، يثبت Certbot ذلك عن طريق إنشاء سجل TXT في نظام أسماء النطاقات (DNS) الخاص بك. نظرًا لأن نظام أسماء النطاقات الخاص بك هو Cloudflare، يمكن أتمتة هذا بالكامل باستخدام رمز وصول API الخاص بـ Cloudflare — لا حاجة للمنفذ 80، ولا حاجة لإيقاف تشغيل خادم الويب.

كيف يعمل

Certbot → ينشئ سجل TXT باسم _acme-challenge.mail.lotuselan.net في Cloudflare
Let's Encrypt → يبحث عن سجل TXT هذا → يتحقق → يصدر الشهادة
Certbot → يحذف سجل TXT

يتم كل هذا على الخادم الأساسي الخاص بك، وليس داخل حاوية Discourse.

الإعداد

1 — تثبيت cerbot والمكوّن الإضافي لـ Cloudflare Certbot:

apt install certbot python3-certbot-dns-cloudflare -y

2 — إنشاء رمز وصول API لـ Cloudflare:

  1. انتقل إلى Cloudflare ← ملفي الشخصي ← رموز وصول API ← إنشاء رمز
  2. استخدم قالب “تحرير DNS للمنطقة”
  3. الأذونات: المنطقة ← DNS ← تحرير
  4. موارد المنطقة: تضمين ← منطقة محددة ← lotuselan.net
  5. قيود IP: قم بالإعداد للسماح فقط من عنوان IP الخاص بالخادم الخاص بك
  6. انسخ الرمز

3 — حفظ الرمز في ملف بيانات الاعتماد:

mkdir -p /etc/letsencrypt/cloudflare
nano /etc/letsencrypt/cloudflare/credentials.ini

ألصق:

dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN

قم بتأمين الملف:

chmod 600 /etc/letsencrypt/cloudflare/credentials.ini

4 — طلب الشهادة:

قم بتحديث الأمر التالي بعنوان البريد الإلكتروني للمسؤول واسم النطاق الخاص بك.

certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini \
  --non-interactive \
  --agree-tos \
  --email youremailadress@domain.tld \
  -d mail.domain.tld

في النتائج، يجب أن يكون هناك بيان يقول:

Certbot has set up a scheduled task to automatically renew this certificate in the background.

سيقوم Certbot بإعداد مهمة cron للتحقق من انتهاء صلاحية الشهادة مرتين في اليوم. سيقوم بتجديد الشهادات عندما تكون ضمن 30 يومًا من انتهاء صلاحيتها. يمكنك التحقق من ذلك عن طريق:

# التحقق مما إذا كان مؤقت systemd نشطًا (معظم أنظمة Ubuntu الحديثة)
systemctl status certbot.timer

# أو التحقق مما إذا تمت إضافة مهمة cron
cat /etc/cron.d/certbot

لديك الآن شهادات TLS على الخادم الخاص بك لاسم نطاق مُستقبِل البريد الجديد. إنها ليست في مكان يمكن استخدامه.

5 — إعداد برنامج نصي للنشر لنقل الملفات
نظرًا لأن certbot يقوم بالتجديد التلقائي، فأنت تحتاج فقط إلى البرنامج النصي الخاص بك للتعامل مع أجزاء Discourse الخاصة - نسخ الشهادات المجددة وإعادة بناء مُستقبِل البريد. يمكنك تبسيط البرنامج النصي بشكل كبير باستخدام خطاف النشر (deploy hook) المدمج في certbot، والذي يتم تشغيله تلقائيًا بعد التجديد الناجح.

إنشاء ملف خطاف النشر:

nano /etc/letsencrypt/renewal-hooks/deploy/mail-receiver-deploy.sh
chmod +x /etc/letsencrypt/renewal-hooks/deploy/mail-receiver-deploy.sh

ألصق هذا:

#!/bin/bash
DOMAIN="mail.domain.tld"
DISCOURSE_DIR="/var/discourse"
CERT_SRC="/etc/letsencrypt/live/${DOMAIN}"
CERT_DEST_1="${DISCOURSE_DIR}/shared/mail-receiver/letsencrypt/${DOMAIN}"
CERT_DEST_2="${DISCOURSE_DIR}/shared/mail-receiver/letsencrypt/${DOMAIN}_ecc"
ADMIN_EMAIL="admin email address"
LOG_FILE="/var/log/mail-cert-renewal.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

log "=== Certbot deploy hook triggered for ${DOMAIN} ==="

# نسخ الشهادات (استخدم -L لحل الروابط الرمزية)
for DEST in "$CERT_DEST_1" "$CERT_DEST_2"; do
    mkdir -p "$DEST"
    cp -L "${CERT_SRC}/fullchain.pem" "${DEST}/fullchain.pem"
    cp -L "${CERT_SRC}/privkey.pem"   "${DEST}/privkey.pem"
    cp -L "${CERT_SRC}/cert.pem"      "${DEST}/cert.pem"
    cp -L "${CERT_SRC}/chain.pem"     "${DEST}/chain.pem"
    chmod 644 "${DEST}/fullchain.pem" "${DEST}/cert.pem" "${DEST}/chain.pem"
    chmod 600 "${DEST}/privkey.pem"
    log "Certs copied to ${DEST}"
done

# إعادة بناء مُستقبِل البريد
cd "$DISCOURSE_DIR" || { echo "Cannot cd to ${DISCOURSE_DIR}" | mail -s "[FAILURE] Mail cert deploy hook failed" "$ADMIN_EMAIL"; exit 1; }
log "Rebuilding mail-receiver..."
if ./launcher rebuild mail-receiver >> "$LOG_FILE" 2>&1; then
    log "mail-receiver rebuilt successfully"
else
    log "ERROR: rebuild failed"
    echo "mail-receiver rebuild failed after cert renewal. Check ${LOG_FILE}" | \
        mail -s "[FAILURE] Mail cert deploy hook failed" "$ADMIN_EMAIL"
    exit 1
fi

log "=== Deploy hook completed successfully ==="

لا حاجة إلى مهمة cron يدوية على الإطلاق — يقوم certbot بتنظيم العملية بأكملها. يتم تشغيل خطاف النشر فقط عند حدوث تجديد فعلي، لذلك لن يخضع مُستقبِل البريد الخاص بك لإعادة بناء غير ضرورية في الأيام التي يتحقق فيها certbot ولكنه لا يقوم بالتجديد.

لاختبار خطاف التجديد، قم بتشغيل ما يلي:

bash /etc/letsencrypt/renewal-hooks/deploy/mail-receiver-deploy.sh

إذا تم إعداد كل شيء بشكل صحيح، فسيقوم بما يلي:
← نسخ الشهادات إلى أدلة Discourse
← إعادة بناء مُستقبِل البريد
← تسجيل كل شيء

6 — إعداد TLS في mail-receiver.yml

تبدو المشكلة الرئيسية هنا هي أن سجل A للسجل forum.domain.tld محجوب بواسطة الوكيل، بدلاً من الرغبة الصريحة في أن يكون خادم البريد على نطاق مختلف.
عند التفاوض على TLS، تتم مقارنة الاسم الشائع للشهادة باسم المضيف لسجل MX، أي اسم المضيف الذي يحاول العميل (الذي قد يكون خادم بريد آخر) الاتصال به، بدلاً من سجل A الذي يشير إليه. هذا يعني أنه يمكنك إنشاء سجل A الخاص بك mail.domain.tld مضبوطًا على DNS Mode Only، ثم إنشاء سجل MX لـ forum.domain.tld يشير إلى mail.domain.tld ولا يلزم اتخاذ خطوات إضافية خاصة في هذا الترتيب.

[quote=“Simon_Manning, post:542, topic:49487”]مجموعة سجل تم تعيينها على DNS Mode Only، ثم قم بإنشاء سجل MX لـ forum.domain.tld يشير إلى mail.domain.tld ولا يلزم اتخاذ خطوات خاصة أخرى في هذا الترتيب.
[/quote]

نعم، يمكنك استخدام وضع نظام أسماء النطاقات فقط (DNS mode only) لسجل A لمنتدى موقعك الرئيسي. يعني استخدام هذا النهج أنك تفقد إمكانيات الوكيل العالمي العكسي (reverse global proxy) الخاصة بـ CloudFlare. (لم يكن هذا خيارًا لتثبيت Discourse الخاص بي.)

لهذا السبب، يحدد السطر الأول أن هذا الحل مخصص للمواقع التي تستخدم وكيل CloudFlare.

كنت أشير إلى سجل A الخاص بـ mail.domain.tld مضبوطًا على وضع DNS فقط بدلاً من سجل A الخاص بـ forum.domain.tld، ومع ذلك أدركت أنني كنت أسيء تفسير كيفية مصادقة عملاء SMTP لشهادات TLS.

السلوك الذي كنت أراه كان أثرًا للطريقة الافتراضية الانتهازية التي لا تتحقق من صحة اسم المضيف، لذا فإن تأكيدي على أنه يتحقق من صحة اسم المضيف الخاص بسجل MX بدلاً من الهدف الفعلي لسجل MX كان غير صحيح. سيعمل في معظم الحالات ولكن ليس إذا تم استخدام DANE أو MTA-STS لفرض مصادقة هوية TLS.

إن وجود سجل A مضبوطًا على “مُرحَّل” (proxied) وسجل MX مضبوطًا على “DNS فقط” (DNS Only) لا يعمل. تنص وثائق CloudFlare على أنه يتم حظر جميع حركة مرور SMTP لأي نطاق يكون سجل A الخاص به مُرحَّلاً.

أتحقق من ذلك من خلال عدة جولات من الاختبارات. في اللحظة التي تزيل فيها خاصية الترحيل عن سجل A، تتدفق بيانات SMTP. قم بتشغيل خاصية الترحيل، ولا تتدفق بيانات SMTP أبدًا. (تم إجراء الاختبارات باستخدام TELNET على المنفذ 25.)

لذلك إذا كنت تريد:

  • منتدى Discourse الخاص بك لاستخدام خدمات وكيل CloudFlare
  • مُستقبِل البريد SMTP الخاص بك لقبول البريد

فيجب أن يكون لديك نطاقات مختلفة للبريد الوارد الخاص بك.

إذا كنت تريد TLS لمُستقبِل البريد SMTP الخاص بك:

  • يجب عليك إعداد LetsEncrypt عبر التحقق من DNS

تبدو التعليمات شاقة، لكن كتابة التعليمات استغرقت وقتًا أطول من التنفيذ الفعلي للحل.

لم أقصد ذلك، ما كنت أقترحه تحديداً هو ثلاثة سجلات DNS:
A: forum.domain.tld → عنوان IP للمُضيف (الوكيل مُفعّل)
A: mail.domain.tld → عنوان IP للمُضيف (وضع DNS فقط)
MX: forum.domain.tldmail.domain.tld

ومع ذلك، كما ذكرت، أدركت لاحقاً أن ذلك سيعمل فقط في وضع TLS الانتهازي الافتراضي، ولن يعمل إذا أراد شخص ما تفعيل DANE أو MTA-STS لفرض مصادقة الهوية (للتأكد من الاتصال بالخادم الصحيح بدلاً من مجرد تشفير حركة المرور).

تبدو جيدة جداً، وسهلة المتابعة وتنفذ كل شيء خارج الحاوية، لذا لا يوجد خطر من أن تتعطل بسبب تحديثات Discourse. أنا معجب بشكل خاص باستخدام خطاف تجديد (renewal hook) لـ certbot الذي لم أكن على دراية به من قبل.

إعجاب واحد (1)

لاحظ أن هذا يعرض عنوان IP الخاص بمنتدى الخاص بك ويجعل من الممكن للأشخاص تجاوز آليات حماية Cloudflare مثل الحماية من هجمات DDoS وجدار حماية تطبيقات الويب (WAF). من الأفضل تشغيل مستقبل البريد على خادم منفصل.

كان قصدي الأول هو تشغيل مستقبل البريد على خادم مختلف لهذا السبب. في كل مرة حاولت فيها تشغيل تطبيق المشغل (launcher app) لبدء تشغيل مستقبل البريد، كان يريد تثبيت نظام discourse الكامل. هل هناك طريقة بسيطة لتشغيل مستقبل البريد فقط على خادم docker مستقل؟

لستُ على دراية تامة بتطبيق المشغل نظرًا لأننا نقوم بإدارة بنيتنا التحتية الخاصة بنا، ولكن فكرتي ستكون عدم استخدام تطبيق المشغل ثم تشغيله مثل أي حاوية أخرى. المتغيرات البيئية التي تحتاجها موجودة في ملف القراءة.

@Simon_Manning و @RGJ - تم تحديث مقال Cloudflare لتقديم الخيارات الرئيسية الثلاثة ومقايضاتها. نأمل أن هذا يعالج القضايا المختلفة التي أثارتموها مع الخيارات الأولى المقدمة.

@kelv قد تفكر في إضافة ملاحظة حاشدة في الوصف الرئيسي لمقال Cloudflare. هذا سيوفر الوقت على الأشخاص الذين تنطبق عليهم. Configure direct-delivery incoming email for self-hosted sites with Mail-Receiver - #541 by LotusJeff

إعجابَين (2)