התקנת Listmonk על שרת Ubuntu 24.04: מדריך מלא
למדו כיצד להתקין Listmonk על Ubuntu 24.04 עם PostgreSQL ו-systemd. המדריך כולל הגדרת TLS, חיבור SMTP וטיפים קריטיים לשיפור מוניטין המשלוח של הניוזלטר שלכם בניהול עצמי.
מה נדרש עבור ניוזלטר בניהול עצמי עם 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צרו את התפקיד (role) ואת מסד הנתונים בסשן 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] כך שתתאים לתפקיד (role), לאחר מכן צור את חשבון השירות ומנע גישה לקובץ מכל משתמש אחר.
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.targetWorkingDirectory חשוב מכיוון ש-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 (transport layer security) termination ומעביר את הבקשה הלאה.
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 כיוון שייבוא מנויים והעלאת מדיה מבוצעים כ-file posts, ו-nginx דוחה כברירת מחדל כל קובץ הגדול מ-1 MB עם 413 Request Entity Too Large. הנפיקו את התעודה באמצעות certbot, אשר גם כותב עבורכם את שורות ה-listen 443 ssl ואת ההפניה מפורט 80: הצעדים מפורטים ב-מדריך תעודות Let's Encrypt עבור nginx. פתחו את פורטים 80 ו-443, והשאירו את 9000 סגור, שכן ה-proxy ניגש אליו דרך ה-loopback. אם ה-firewall עדיין לא הוגדר, התחילו ב-יסודות ה-firewall מסוג ufw.
לאחר מכן, פתחו את לוח הניהול והגדירו את ה-root URL תחת Settings ל-https://lists.example.com. התקנה חדשה מגיעה עם http://localhost:9000, ו-Listmonk כותב ערך זה לתוך כל קישור להסרה מרשימת תפוצה וכתובת URL של מדיה שהוא משלב בהודעות דוא"ל. אם תשלחו קמפיין לפני שתשנו זאת, כל נמען יקבל קישורים המצביעים על המחשב שלו עצמו. קישורים אלו ייכשלו עבור הקורא, ועבור מסנן דואר זבל הם ייראו כניסיון של שולח שאינו מסוגל להגדיר את הדומיין שלו כראוי.
חיבור SMTP, שאינו מופיע ב-config.toml
חפשו config.toml אחר מקטע SMTP ולא תמצאו כזה. הגדרות הדואר נמצאות במסד הנתונים, בטבלה settings, ואתם עורכים אותן בלוח הבקרה תחת Settings ו-SMTP. זו הסיבה שהקובץ שנוצר נשאר קצר, וזו גם הסיבה ששינוי ב-SMTP אינו דורש הפעלה מחדש.
קיימות שתי אפשרויות סבירות עבור שרת ה-SMTP עצמו. הריצו שרת משלכם, מה שמעביר את האחריות למוניטין במלואה לידיכם ומהווה פרויקט בפני עצמו: הרצת שרת דואר עצמאי עם Mailcow מכסה את המשמעויות של מהלך כזה. לחלופין, כוונו את Listmonk לממסר (relay) טרנזקציוני ותנו לאחרים לנהל את מוניטין ה-IP.
כך או כך, השתמשו בפורט 587 עם STARTTLS, או בפורט 465 עם TLS מובלע. אל תבנו על פורט 25 לתעבורה יוצאת. רוב ספקי ה-VPS חוסמים אותו כברירת מחדל בחשבונות חדשים, ופורט 25 חסום נראה בדיוק כמו חיבור תקוע, כיוון שהחבילות נזרקות במקום להידחות, מה שגורם ללקוח להמתין ל-timeout במקום להיכשל באופן מיידי.
בדקו זאת לפני שתסתמכו על כך. צרו רשימה, הוסיפו את הכתובת שלכם כמנויים, ושלחו קמפיין לנמען אחד. פתחו את ההודעה שהתקבלה וקראו את ה-headers המלאים. ה-header מסוג Authentication-Results שנוסף על ידי הצד המקבל יציין אם בדיקות SPF ו-DKIM עברו בהצלחה.
יכולת המסירה היא העבודה כולה
Listmonk בונה את ההודעה, מנהלת את הרשימה ומעבירה את הדואר הלאה. כל החלטה בשאלה האם דואר זה יגיע לתיבת הנכנס מתקבלת על ידי ספקית הדואר המקבלת, בהתבסס על כתובת ה-IP השולחת ועל הדומיין השולח. לכתובת IP של שרת VPS חדש אין היסטוריה כלל, והיעדר היסטוריה נתפס כחשוד במידה מתונה על ידי כל ספקית תיבות דואר גדולה.
ארבעה דברים אינם נתונים לבחירה:
- רשומת TXT מסוג SPF (sender policy framework) המציינת את המארח המורשה לשלוח דואר עבור הדומיין שלך.
- מפתח DKIM (domainkeys identified mail) המפורסם כרשומת TXT, כאשר החתימה מבוצעת על ידי שרת הדואר ולא על ידי Listmonk.
- רשומת DMARC (domain based message authentication, reporting and conformance), המורה למקבלים כיצד לפעול כאשר שני התנאים הראשונים נכשלים.
- תיבת דואר לטיפול ב-bounces ש-Listmonk קוראת, כדי שכתובות שדוחות דואר יוסרו מהרשימה במקום לבצע ניסיונות חוזרים לנצח.
לאחר מכן, שלחו לאט בהתחלה. דומיין שמעולם לא שלח דואר ופתאום מוסר עשרת אלפים הודעות בשעה נראה בדיוק כמו חשבון שנפרץ, ולכן הוא מסונן ככזה. התחילו עם המנויים הפעילים ביותר שלכם והעלו את הנפח בהדרגה לאורך ימים.
כל תבנית זקוקה גם לקישור הסרה מרשימת תפוצה (unsubscribe) תקין. בתבנית של Listmonk זהו {{ UnsubscribeURL }}, וגוף הקמפיין ממוקם היכן ש-{{ template "content" . }} נמצא, אשר חייב להופיע בדיוק פעם אחת בכל תבנית. קמפיין ללא קישור הסרה גורר תלונות על דואר זבל במקום הסרות, ותלונות הן הדרך המהירה ביותר לאבד מוניטין שליחה שבניתם במשך שבועות.
גיבויים, ומה נדרש בפועל עבור שחזור
שני דברים חייבים לצאת מהשרת: ה-dump של מסד הנתונים ו-config.toml. אם אתם מעלים תמונות לקמפיינים, הוסיפו גם את תיקיית המדיה.
sudo -u postgres pg_dump -Fc listmonk > listmonk-$(date +%F).dumpה-dump הזה מכיל מנויים, קמפיינים, תבניות וכל הגדרה, כולל פרטי הגישה ל-SMTP; לכן, הצפינו אותו ושמרו אותו מחוץ לשרת זה. תזמון פעולה זו הוא בעיה פתורה: ראו גיבויים מוצפנים באמצעות restic לאחסון מרוחק. הקובץ config.toml מכיל רק כמה שורות, אך הוא כולל את סיסמת מסד הנתונים, לכן התייחסו אליו באותה צורה.
שדרוגים מתבצעים לפי סדר קבוע. עצרו את השירות, בצעו dump, החליפו את הקובץ הבינארי ב-/usr/bin, הריצו את listmonk --config /etc/listmonk/config.toml --upgrade, ולאחר מכן הפעילו את השירות מחדש. מיגרציות של סכימה (schema migrations) רצות רק קדימה, כך שה-dump הוא הדרך היחידה שלכם לחזור לאחור.
מדוע Listmonk לא מצליח לעלות?
תחילה, קראו את הלוגים באמצעות journalctl -u listmonk -n 50 --no-pager. כמעט כל כשל בעלייה מופיע כשורה אחת בבלוק [db].
pq: password authentication failed for user "listmonk" מציין שהסיסמה בתוך [db] אינה תואמת לתפקיד (role) ב-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.
לוח הבקרה עובד אך לא מגיעים מיילים. זו אינה בעיית עלייה. בדקו תחילה את ההגדרות ואת ה-SMTP, ולאחר מכן את הלוג של הקמפיין בתוך לוח הניהול; שם מתועדת השגיאה שהחזיר שרת המייל עבור כל ניסיון שליחה.
FAQ
האם אני זקוק לשרת דואר משלי כדי להשתמש ב-Listmonk?
לא. Listmonk אינו שרת דואר. הוא זקוק לפרטי גישה (credentials) של שרת SMTP שמקבל את הדואר שלך ומפיץ אותו; זה יכול להיות שירות ממסר (relay) טרנזקציוני או שרת דואר שאתה מנהל בעצמך. הגדר את פרטי הגישה הללו תחת Settings ו-SMTP בלוח הבקרה, ולא ב-config.toml, כיוון שהגדרות הדואר נשמרות בבסיס הנתונים. השתמש בפורט 587 עם STARTTLS או בפורט 465 עם TLS מובלע, כיוון שרוב ספקי ה-VPS חוסמים תעבורה יוצאת בפורט 25 בחשבונות חדשים.
מדוע הקישורים בקמפיין שלי מצביעים על localhost:9000?
הגדרת ה-root URL עדיין נמצאת בערך ברירת המחדל של ההתקנה: http://localhost:9000. Listmonk כותב את הערך הזה לתוך קישורי הסרה מרשימת תפוצה וכתובות מדיה ברגע שליחת הקמפיין. פתח את Settings בלוח הבקרה, הגדר את ה-root URL לכתובת ה-HTTPS האמיתית שלך, ושמור. לא ניתן לתקן הודעות שכבר נשלחו, לכן שלח לעצמך קמפיין ניסיון ולחץ על קישור ההסרה שבו לפני שתשלח לרשימה אמיתית.
האם הרצה חוזרת של --install תמחק את המנויים שלי?
כן. --install הוא מתקין ראשוני והוא מוחק את הסכימה הקיימת של Listmonk, ו---yes מסיר את ההנחיה שהייתה מזהירה אותך. בכל סקריפט שעלול לרוץ פעמיים, השתמש ב---install --idempotent --yes, שאינו מבצע דבר כאשר הטבלאות כבר קיימות. כדי להחיל שינויי סכימה בגרסה חדשה, עצור את השירות, בצע pg_dump, ולאחר מכן הרץ את --upgrade.
מדוע Listmonk מדווח על כשל באימות סיסמה עבור המשתמש listmonk?
הסיסמה בבלוק [db] של הקובץ /etc/listmonk/config.toml אינה תואמת לתפקיד (role) ב-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.