SSD Nodes Learn 8GB RAM — $66/سنة
الأدلة Matt Connorبقلم Matt Connor · آخر تحديث في 2026-08-01

كيف تثبّت Listmonk على VPS وتستضيف نشرتك بنفسك

ثبّت Listmonk v6.2.0 على Ubuntu 24.04 مع PostgreSQL وconfig.toml وsystemd وTLS، ثم اربطه بـSMTP وافهم لماذا تحتاج سمعة الإرسال أسابيع.

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, July 30, 2026.

ما يحتاجه النشر الذاتي لنشرة إخبارية على Listmonk

Listmonk هو مدير مستضاف ذاتيًا للنشرات الإخبارية وقوائم البريد: ملف ثنائي واحد مكتوب بلغة Go، وقاعدة بيانات PostgreSQL واحدة، وملف إعداد واحد، ووحدة systemd واحدة. يشغّله VPS صغير دون عناء، لأن Listmonk يخزّن المشتركين ويضع الحملات في قائمة الانتظار، لكنه لا يرسل البريد بنفسه. بل يسلّم كل رسالة إلى خادم SMTP (بروتوكول نقل البريد البسيط)، لذلك يحدد معدل وصول رسائلك سمعة ذلك الخادم، وليس هذا البرنامج.

يثبّت هذا الدليل Listmonk v6.2.0، وهو الإصدار الحالي في يوليو 2026، على Ubuntu 24.04. تحتاج إلى VPS بعنوان IP عام، واسم نطاق تتحكم فيه، وPostgreSQL 12 أو إصدار أحدث. يستغرق التثبيت نحو ساعة. أما بناء سمعة الإرسال فيستغرق أسابيع، ويغطي هذا الدليل ذلك الجزء قرب النهاية.

تثبيت PostgreSQL وإنشاء قاعدة البيانات

يأتي Ubuntu 24.04 مع PostgreSQL 16 في مستودعه الخاص، وهو إصدار أحدث بكثير مما يحتاج إليه Listmonk.

sudo apt update
sudo apt install -y postgresql curl
sudo systemctl enable --now postgresql

أنشئ الدور وقاعدة البيانات في جلسة psql واحدة. يجعل -v ON_ERROR_STOP=1 ‏psql يخرج عند أول عبارة فاشلة، لذلك لا يترك خطأ مطبعي إعدادًا ناقصًا يبدو مكتملًا.

sudo -u postgres psql -v ON_ERROR_STOP=1 <<'SQL'
CREATE USER listmonk WITH PASSWORD 'pick-a-long-random-password';
CREATE DATABASE listmonk OWNER listmonk;
SQL

إن OWNER listmonk ليس للزينة. ينشئ تثبيت المخطط جداول وأنواعًا وفهارس ودوال، لذلك يجب أن يملك الدور قاعدة البيانات. إذا وجّهت Listmonk إلى قاعدة بيانات يملكها دور آخر، يتوقف التثبيت مع permission denied، حتى بعد تشغيل GRANT CONNECT.

تأكد من وجود قاعدة البيانات قبل المتابعة.

sudo -u postgres psql -tAc "SELECT datname FROM pg_database WHERE datname='listmonk';"

يطبع ذلك listmonk. يشير السطر الفارغ إلى أن عبارة CREATE لم تُنفَّذ، لذا اقرأ مخرجات psql مرة أخرى.

تثبيت ملف Listmonk التنفيذي

ينشر Listmonk ملفًا تنفيذيًا ثابتًا لكل بنية. تحقّق من بنيتك أولًا، لأن ملف amd64 التنفيذي على VPS يعمل ببنية ARM هو ملف يرفض kernel تنفيذه.

dpkg --print-architecture
cd /tmp
curl -fsSLO https://github.com/knadh/listmonk/releases/download/v6.2.0/listmonk_6.2.0_linux_amd64.tar.gz
tar -xzf listmonk_6.2.0_linux_amd64.tar.gz
sudo install -m 755 listmonk /usr/bin/listmonk
listmonk --version

على VPS يعمل ببنية ARM، استبدل amd64 بـ arm64 في اسم الملف. إن طبع listmonk --version سلسلة إصدار، فهذا أول دليل على أن الملف التنفيذي يطابق الجهاز.

إنشاء config.toml وتأمينه

--new-config يكتب config.toml في دليل العمل الحالي. لذلك يوجد cd داخل sh -c، وليس قبل sudo.

sudo install -d -m 750 /etc/listmonk
sudo sh -c 'cd /etc/listmonk && listmonk --new-config'

الملف المُنشأ قصير. ضمن [app]، يربط address = "localhost:9000" خادم HTTP بواجهة loopback فقط، لذلك لا يمكن الوصول إلى لوحة الإدارة من الإنترنت إلى أن تضع reverse proxy أمامه. اترك هذا السطر كما هو. ضمن [db]، تحصل على host = "localhost" وport = 5432 وuser = "listmonk" وdatabase = "listmonk" وssl_mode = "disable". تتوافق هذه القيم الافتراضية مع قاعدة البيانات التي أنشأتها، لذلك السطر الوحيد الذي يجب تغييره هو كلمة المرور.

تكون ssl_mode = "disable" صحيحة عندما يستمع Postgres على loopback في الجهاز نفسه، لأن حركة الشبكة هذه لا تغادر الجهاز. إذا نقلت قاعدة البيانات إلى مضيف آخر، فاضبطها على require، وإلا ستعبر كلمة المرور الشبكة بنص واضح.

عدّل سطر كلمة المرور ضمن [db] ليطابق الدور، ثم أنشئ حساب الخدمة وامنع جميع حسابات الدخول الأخرى من الوصول إلى الملف.

sudo useradd --system --home-dir /var/lib/listmonk --create-home --shell /usr/sbin/nologin listmonk
sudo chown -R root:listmonk /etc/listmonk
sudo chmod 640 /etc/listmonk/config.toml

يمكن لحساب الخدمة الآن قراءة الملف، ولا يستطيع أي حساب آخر ذلك.

sudo -u listmonk cat /etc/listmonk/config.toml > /dev/null && echo readable
stat -c '%U:%G %a' /etc/listmonk/config.toml

يطبع الأمر الأول readable. ويطبع الأمر الثاني root:listmonk 640. سيحصل أي حساب آخر غير متمتع بامتيازات يحاول تنفيذ cat نفسه على Permission denied. وهذا هو الهدف: يحتوي هذا الملف على كلمة مرور قاعدة البيانات بنص واضح، وعادةً ما يضم الخادم أكثر من حساب دخول واحد. وينطبق المنطق نفسه على كل خدمة تشغّلها، لذلك اقرأ عن حسابات مستخدمي الخدمة ذات أقل قدر من الامتيازات مرة واحدة وطبّقه في كل مكان.

إنشاء المخطط باستخدام --install

ينشئ --install الجداول ويملأ الإعدادات الافتراضية. عيّن بيانات تسجيل دخول المسؤول الأول باستخدام متغيرات البيئة، حتى يصبح الحساب موجودًا قبل أن تصبح لوحة التحكم متاحة.

sudo -u listmonk env LISTMONK_ADMIN_USER=admin \
  LISTMONK_ADMIN_PASSWORD='another-long-random-password' \
  listmonk --config /etc/listmonk/config.toml --install --yes

يجيب --yes عن مطالبة التأكيد. اقرأ هذه المطالبة مرة واحدة قبل أتمتة الأمر، لأن --install هو أمر التثبيت الأول، وهو يحذف مخطط Listmonk موجودًا. يؤدي تشغيله مرة ثانية على قاعدة بيانات قيد الاستخدام إلى حذف المشتركين. في أي برنامج نصي قد يعمل مرتين، استخدم --install --idempotent --yes، إذ لا يفعل شيئًا عندما تكون الجداول موجودة مسبقًا. تُطبَّق تغييرات المخطط التي تأتي مع إصدار جديد باستخدام --upgrade، وليس باستخدام --install.

تحقق من النتيجة من جهة قاعدة البيانات بدلًا من المتصفح.

sudo -u postgres psql -d listmonk -c '\dt'
sudo -u postgres psql -d listmonk -tAc "SELECT username FROM users;"

يعرض الأمر الأول جداول Listmonk، ومنها subscribers وlists وcampaigns وtemplates وbounces. يطبع الأمر الثاني admin. تعني النتيجة الفارغة من الأمر الثاني أن متغيرات البيئة لم تصل إلى العملية، ولذلك ستطلب منك لوحة التحكم إنشاء المستخدم الأول في المتصفح بدلًا من ذلك.

تشغيل Listmonk باستخدام systemd

اكتب /etc/systemd/system/listmonk.service.

[Unit]
Description=Listmonk newsletter and mailing list manager
After=network-online.target postgresql.service
Wants=network-online.target

[Service]
Type=simple
User=listmonk
Group=listmonk
WorkingDirectory=/var/lib/listmonk
ExecStart=/usr/bin/listmonk --config /etc/listmonk/config.toml
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true

[Install]
WantedBy=multi-user.target

يهم WorkingDirectory لأن Listmonk يحل المسارات النسبية، بما في ذلك مسار رفع الوسائط في نظام الملفات، بالاستناد إليه. يرتب After=postgresql.service بدء التشغيل فقط، ولا ينتظر حتى يقبل Postgres الاتصالات. لذلك يعالج Restart=on-failure الحالة التي يبدأ فيها Listmonk قبل الأوان بقليل ولا يتمكن من الاتصال.

sudo systemctl daemon-reload
sudo systemctl enable --now listmonk
ss -ltnp | grep 9000
curl -sI http://127.0.0.1:9000/

يجب أن يعرض ss 127.0.0.1:9000 في حالة LISTEN. ويعني إرجاع curl لأي سطر حالة HTTP أن الخادم يستجيب. ويعني فشل curl مع Connection refused أن العملية توقفت أثناء بدء التشغيل، وسيذكر journalctl -u listmonk -n 50 --no-pager السبب. لاحظ أن enable --now هو الجزء الذي يستمر بعد إعادة التشغيل: إذ تختفي العملية التي بدأتها يدويًا بعد ترقية kernel التالية.

ضع nginx وTLS في الواجهة

يستخدم Listmonk بروتوكول HTTP العادي على loopback، لذلك ينهي nginx جلسة TLS (أمان طبقة النقل) ويمرر الطلب.

server {
    listen 443 ssl;
    server_name lists.example.com;

    client_max_body_size 25m;

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

يجب رفع client_max_body_size لأن استيراد المشتركين ورفع الوسائط يرسلان ملفات، ويرفض nginx افتراضيًا أي ملف يتجاوز 1 MB باستخدام 413 Request Entity Too Large. أصدر الشهادة باستخدام certbot، الذي يكتب أيضًا أسطر listen 443 ssl وإعادة التوجيه من المنفذ 80 نيابةً عنك: توجد الخطوات في دليل شهادة Let's Encrypt لـ nginx. افتح المنفذين 80 و443، واترك المنفذ 9000 مغلقًا، لأن الوكيل يصل إليه عبر loopback. إذا لم تكن قد عدّلت الجدار الناري بعد، فابدأ من أساسيات جدار ufw الناري.

بعد ذلك افتح لوحة الإدارة واضبط عنوان الجذر ضمن الإعدادات على https://lists.example.com. يتضمن التثبيت الجديد القيمة http://localhost:9000، ويكتب Listmonk هذه القيمة في كل رابط لإلغاء الاشتراك وكل عنوان URL للوسائط يضعه في رسالة بريد إلكتروني. إذا أرسلت حملة قبل تغييرها، فستحصل كل جهة مستلمة على روابط تشير إلى جهازها الخاص. لن تعمل هذه الروابط لدى القارئ، وستبدو لمرشح البريد العشوائي كأن المرسل عاجز عن ضبط نطاقه.

ربط SMTP، وهو غير موجود في config.toml

ابحث في config.toml عن قسم SMTP، ولن تجد واحدًا. توجد إعدادات البريد في قاعدة البيانات، في جدول settings، ويمكنك تعديلها من لوحة الإدارة ضمن Settings وSMTP. لذلك يظل الملف المُنشأ قصيرًا، ولأن تغيير إعدادات SMTP لا يتطلب إعادة التشغيل.

لديك خياران عمليان لخادم SMTP نفسه. شغّل خادمك الخاص، فتكون سمعته بالكامل تحت مسؤوليتك، لكنه مشروع مستقل فعليًا: يوضّح تشغيل خادم بريدك الخاص باستخدام Mailcow ما يتطلبه ذلك. أو وجّه Listmonk إلى مرحّل معاملات بريدية، واترك إدارة سمعة عنوان IP لجهة أخرى.

في كلتا الحالتين، استخدم المنفذ 587 مع STARTTLS، أو المنفذ 465 مع TLS الضمني. لا تعتمد على المنفذ الصادر 25. يحظر معظم مزوّدي VPS هذا المنفذ افتراضيًا للحسابات الجديدة. ويبدو المنفذ 25 المحظور تمامًا مثل اتصال عالق، لأن الحزم تُسقط بدلًا من رفضها. لذلك ينتظر العميل انتهاء المهلة بدلًا من فشل الاتصال فورًا.

اختبر الإعداد قبل الاعتماد عليه. أنشئ قائمة، وأضف عنوانك الخاص كمشترك، وأرسل حملة إلى مستلم واحد. افتح الرسالة المستلمة واقرأ الترويسات كاملة. يوضح ترويس Authentication-Results الذي يضيفه الطرف المستلم ما إذا كان SPF وDKIM قد اجتازا التحقق.

قابلية التسليم هي المهمة بأكملها

ينشئ Listmonk الرسالة، ويتتبع القائمة، ويسلّم البريد إلى خادم البريد. يحدد مزود البريد المستلم ما إذا كانت الرسالة ستصل إلى صندوق الوارد، وذلك باستخدام عنوان IP المرسِل ونطاق الإرسال. لا يملك عنوان IP جديد على VPS أي سجل سابق، ويعتبر كل مزود كبير لصناديق البريد انعدام السجل هذا موضع اشتباه، ولو بدرجة محدودة.

هناك أربعة أمور لا يمكن الاستغناء عنها:

  • سجل SPF (إطار سياسة المرسِل) من نوع TXT، يحدد المضيف المسموح له بالإرسال نيابة عن نطاقك.
  • مفتاح DKIM (البريد المحدد بمفاتيح النطاق) منشور كسجل TXT، على أن ينفذ خادم البريد عملية التوقيع، لا Listmonk.
  • سجل DMARC (مصادقة الرسائل المستندة إلى النطاق وإعداد التقارير والمطابقة)، يحدد للمستلمين الإجراء الذي يجب اتخاذه عند فشل العنصرين الأولين.
  • صندوق بريد للرسائل المرتدة يقرأه Listmonk، لكي تُزال العناوين التي ترفض البريد من القائمة بدلاً من إعادة المحاولة إلى الأبد.

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

يحتاج كل قالب أيضاً إلى رابط إلغاء اشتراك يعمل. في قالب Listmonk يكون هذا الرابط هو {{ UnsubscribeURL }}، ويظهر نص الحملة في موضع {{ template "content" . }}، الذي يجب أن يظهر مرة واحدة بالضبط في كل قالب. تؤدي الحملة التي لا تحتوي على رابط لإلغاء الاشتراك إلى شكاوى من الرسائل غير المرغوب فيها بدلاً من إلغاء الاشتراكات. والشكاوى هي أسرع طريقة لفقدان سمعة إرسال قضيت أسابيع في بنائها.

النسخ الاحتياطية، وما يحتاج إليه الاسترجاع فعليًا

يجب إخراج عنصرين من الخادم: تفريغ قاعدة البيانات وconfig.toml. أضف دليل الوسائط إذا كنت ترفع الصور إلى الحملات.

sudo -u postgres pg_dump -Fc listmonk > listmonk-$(date +%F).dump

يحتوي هذا التفريغ على المشتركين والحملات والقوالب وجميع الإعدادات، بما في ذلك بيانات اعتماد SMTP، لذلك شفّره واحتفظ به خارج هذا الخادم. جدولة ذلك أمر محسوم: راجع النسخ الاحتياطية المشفرة باستخدام restic إلى وحدة تخزين بعيدة. يتكون config.toml من بضعة أسطر، لكنه يحتوي على كلمة مرور قاعدة البيانات، لذا تعامل معه بالطريقة نفسها.

تُجرى الترقيات بترتيب محدد. أوقف الخدمة، وأنشئ تفريغًا، واستبدل الملف الثنائي في /usr/bin، وشغّل listmonk --config /etc/listmonk/config.toml --upgrade، ثم ابدأ الخدمة. تعمل عمليات ترحيل المخطط إلى الأمام فقط، لذلك يمثل ذلك التفريغ طريقك الوحيد للعودة.

لماذا يفشل Listmonk في التشغيل؟

اقرأ السجل أولًا باستخدام journalctl -u listmonk -n 50 --no-pager. تكون معظم حالات فشل التشغيل عبارة عن سطر واحد في كتلة [db].

pq: password authentication failed for user "listmonk" تعني أن كلمة المرور في [db] لا تطابق دور Postgres. تذكر البادئة pq أن برنامج تشغيل Postgres أبلغ عن رفض الخادم، ولذلك تمت قراءة الإعدادات بشكل صحيح، لكن بيانات الاعتماد كانت خاطئة. أعد تعيين الدور باستخدام sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';"، ثم ضع السلسلة نفسها في الملف.

pq: database "listmonk" does not exist تعني أن قيمة database في [db] لا تشير إلى قاعدة بيانات موجودة فعلًا. يعرض sudo -u postgres psql -l قواعد البيانات الموجودة على الخادم، بما في ذلك طريقة الكتابة التي استخدمتها بالخطأ.

permission denied أثناء --install تعني أن الدور يمكنه الاتصال، لكنه لا يملك قاعدة البيانات، ولذلك لا يمكنه إنشاء الجداول فيها. أصلح ذلك باستخدام sudo -u postgres psql -c "ALTER DATABASE listmonk OWNER TO listmonk;"، ثم شغّل التثبيت مرة أخرى.

لا تبدأ الخدمة مطلقًا، ويذكر السجل ملف الإعدادات. لا يمكن لعملية تعمل باسم listmonk فتح ملف config.toml إذا كان مملوكًا لـ root:root وبوضع 600. يجب أن يطبع stat -c '%U:%G %a' /etc/listmonk/config.toml القيمة root:listmonk 640، ويجب أن يكون الدليل الموجود فوقه مملوكًا لـ root:listmonk 750.

تعمل لوحة التحكم، لكن لا تصل أي رسائل بريد. هذه ليست مشكلة في التشغيل. تحقّق أولًا من Settings وSMTP، ثم راجع سجل الحملة نفسه في لوحة الإدارة؛ فهو يسجل الخطأ الذي أعاده خادم البريد لكل محاولة.

FAQ

هل أحتاج إلى خادم بريد خاص بي لاستخدام Listmonk؟

لا. Listmonk ليس خادم بريد. يحتاج إلى بيانات اعتماد SMTP لخادم يقبل رسائلك ويرسلها، وقد يكون هذا الخادم مرحّلًا للرسائل المعاملاتية أو خادم بريد تديره بنفسك. أدخل بيانات الاعتماد هذه ضمن Settings ثم SMTP في لوحة الإدارة، وليس في config.toml، لأن إعدادات البريد محفوظة في قاعدة البيانات. استخدم المنفذ 587 مع STARTTLS أو المنفذ 465 مع TLS الضمني، لأن معظم موفري VPS يحظرون المنفذ الصادر 25 في الحسابات الجديدة.

لماذا تشير الروابط في حملتي إلى localhost:9000؟

لا يزال إعداد عنوان URL الجذر مضبوطًا على القيمة الافتراضية للتثبيت، وهي http://localhost:9000. يكتب Listmonk هذه القيمة في روابط إلغاء الاشتراك وعناوين URL للوسائط عند إرسال الحملة. افتح Settings في لوحة الإدارة، واضبط عنوان URL الجذر على عنوان HTTPS الحقيقي، ثم احفظ الإعداد. لا يمكن تصحيح الرسائل التي سُلّمت بالفعل، لذلك أرسل حملة اختبار إلى نفسك وانقر على رابط إلغاء الاشتراك فيها قبل مراسلة قائمة حقيقية.

هل سيؤدي تشغيل --install مرة أخرى إلى حذف المشتركين؟

نعم. --install هو مُثبّت التشغيل الأول، ويحذف مخطط Listmonk الحالي، بينما يزيل --yes المطالبة التي كانت ستحذّرك من ذلك. في أي برنامج نصي قد يُشغَّل مرتين، استخدم --install --idempotent --yes، لأنه لا يفعل شيئًا عند وجود الجداول مسبقًا. لتطبيق تغييرات المخطط في إصدار جديد، أوقف الخدمة، وأنشئ pg_dump، ثم شغّل --upgrade.

لماذا يقول Listmonk إن مصادقة كلمة المرور فشلت للمستخدم listmonk؟

كلمة المرور الموجودة في كتلة [db] ضمن /etc/listmonk/config.toml لا تطابق كلمة مرور دور Postgres الذي يحمل الاسم نفسه. سطر السجل هو pq: password authentication failed for user "listmonk"، ويمثل pq برنامج تشغيل Postgres الذي ينقل رفض الخادم، ما يعني أن ملف الإعدادات عُثر عليه وقُرئ. أعد تعيين كلمة مرور الدور باستخدام sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';"، واكتب السلسلة نفسها في ملف الإعدادات، ثم شغّل sudo systemctl restart listmonk.