התקנת Discourse על שרת VPS באמצעות Docker
מדריך מעשי להתקנת Discourse על שרת VPS עם Docker. למדו כיצד להגדיר את קובץ app.yml, לנהל זיכרון ו-swap, להגדיר SMTP ולבצע rebuild תקין למערכת ללא שגיאות נפוצות.
התקנת Discourse על שרת VPS: מכולה אחת, קובץ הגדרות אחד
כדי להתקין את Discourse על שרת VPS, יש להריץ את תוכנית ההתקנה של הפרויקט, לענות על אשף קצר ולהמתין לבנייה. Discourse מופץ כמכולת Docker יחידה המכילה את יישום ה-Rails, את PostgreSQL, את Redis ואת nginx. כל שינוי שתבצעו בהמשך מתבצע בקובץ אחד, /var/discourse/containers/app.yml, וכל שינוי מוחל על האתר באמצעות בנייה מחדש (rebuild).
ההתקנה הרשמית היא discourse_docker: סקריפט shell מסוג launcher בצירוף קבוצת תבניות YAML. Discourse אינו תומך בקובץ Compose שתכתבו בעצמכם, והמכולה אינה מיועדת לפירוק ידני. אם אתם רגילים ל-הרצת שירותים על VPS באמצעות Docker Compose, צפו למבנה שונה. אין כאן docker compose up -d, והפקודה ./launcher rebuild app היא זו שמבצעת את הפריסה.
מה Discourse דורש לפני שמתחילים
ארבע דרישות גורמות למשתמשים להיתקל בקשיים, וכל אחת מהן עלולה להכשיל אתכם עוד לפני שתגיעו לדף ההתחברות.
- זיכרון. מכולה (container) אחת מריצה את PostgreSQL, Redis, Sidekiq ושרת אינטרנט מבוסס Ruby. שלב ה-build מהדר קבצים וזקוק ליותר זיכרון מאשר האתר בזמן פעילות שוטפת.
- שם מתחם (domain name) אמיתי. קובץ התצורה לדוגמה שמגיע עם התוכנה מציין זאת במפורש: "Discourse לא יעבוד עם כתובת IP בלבד".
- נתיב דואר יוצא. הפעלת חשבונות, איפוס סיסמאות, הזמנות מנהלים וסיכומי דואר נשלחים כולם דרך SMTP (פרוטוקול העברת דואר פשוט).
- פורטים 80 ו-443 פנויים בשרת המארח, אלא אם בחרתם במכוון להציב את Discourse מאחורי proxy שכבר מוגדר אצלכם.
The data behind this chart
[
{
"label": "Documented minimum",
"ram_gb": 1,
"storage_gb": 10
},
{
"label": "Documented recommended",
"ram_gb": 2,
"storage_gb": 20
}
]תיעוד ההתקנה הרשמי מציב את הרף המינימלי על 1 GB של RAM עם swap ו-10 GB של שטח אחסון, וממליץ על 2 GB של RAM עם 20 GB של שטח אחסון. התייחסו לשורה הראשונה כמספר המינימלי המאפשר למתקין לסיים את עבודתו, ולא כמספר שתרצו להריץ עליו קהילה. הפער משמעותי כיוון ששיא צריכת הזיכרון מתרחש בזמן ה-build, ולא בזמן התעבורה השוטפת.
הפניית הדומיין לשרת לפני ההתקנה
צרו רשומת A עבור שם המארח (hostname) שבו תשתמשו, ולאחר מכן ודאו את תקינותה מתוך השרת עצמו.
dig +short forum.example.com
curl -4 -s https://ifconfig.coשתי הפקודות חייבות להציג את אותה כתובת. עליהן להיות מסונכרנות, כיוון שאשף ההתקנה מריץ בדיקת חיבור מול שם המארח שלכם; רשומה שעדיין מצביעה למקום אחר תגרום לכישלון הבדיקה. רשומה שיצרתם לפני שתי דקות עשויה עדיין להיות ב־cache, לכן המתינו עד לסיום ה־TTL (זמן חיים) הישן במקום לנסות לעקוף את האשף.
החליטו כעת אם הרשומה תעבור דרך CDN. רשומה שעוברת דרך proxy מסתירה את כתובת השרת שלכם, ובמקרה כזה בקשת התעודה של המכולה תיכשל, כיוון שהאתגר של ACME (סביבת ניהול תעודות אוטומטית) נענה על ידי ה־proxy במקום על ידי Discourse. השאירו את הרשומה ללא proxy עבור ההתקנה הראשונית.
הרצת המתקין הרשמי
פקודה אחת מתקינה את git, מתקינה את Docker באמצעות סקריפט ההתקנה הרשמי של Docker, משכפלת את discourse_docker לתוך /var/discourse, ומפעילה את אשף ההתקנה.
wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/main/install-discourse | sudo bashאם Docker כבר מותקן על השרת ואתם מעדיפים לראות כל שלב, בצעו את הפעולות באופן ידני.
sudo -s
git clone https://github.com/discourse/discourse_docker.git /var/discourse
cd /var/discourse
./discourse-setupהריצו את הפקודה כ-root. אם תפעילו אותה כמשתמש רגיל, discourse-setup תיעצר מיד עם This script must be run as root. Please sudo or log in as root first.. ללא Docker מותקן על השרת, התהליך ייעצר עם Docker is not installed. Please install Docker first., כיוון ששכפול ידני אינו מתקין עבורכם דבר.
מה שואל אשף ההתקנה, ומה הוא כותב
נכון לאוגוסט 2026, discourse-setup הוא מעטפת (wrapper) דקה. הוא מריץ את discourse/setup-wizard:release כמכולה (container) עם גישה לרשת המארח ועם ה-Docker socket ממופה, כדי שהאשף יוכל לבחון את המכונה שהוא מגדיר. הוא מבקש את שם המארח (hostname) וכתובות הדוא"ל של מנהל המערכת, ולאחר מכן את פרטי ה-SMTP שלכם. הוא כותב את containers/app.yml, ולאחר מכן מבצע בנייה מחדש.
כדאי להכיר שני התנהגויות לפני שמתחילים. אם למכונה חסר זיכרון ואין בה swap, האשף יעצור ויציע ליצור אחד: המעטפת תיצור קובץ /swapfile בגודל 2 GB, תוסיף אותו ל-/etc/fstab, תגדיר את vm.swappiness = 10 בתוך /etc/sysctl.d/30-discourse-swap.conf, ותפעיל את האשף מחדש. כשהאשף מסיים, הוא מדפיס את Rebuilding app in 5 seconds (Ctrl+C to cancel)... ומריץ את ./launcher rebuild app על המארח. בנייה זו אורכת מספר דקות ב-VPS קטן, והבנייה הראשונה היא האיטית ביותר כיוון שכל הנכסים עוברים הידור (compile) מאפס.
./discourse-setup --help מפרט את הדגלים (flags) החשובים כאשר משהו משתבש. --skip-rebuild כותב את קובץ התצורה ללא ביצוע בנייה, ו---skip-connection-test מדלג על בדיקות ה-DNS והפורטים. השתמשו ב---skip-connection-test רק כאשר אתם כבר יודעים מדוע הבדיקה נכשלת, למשל כאשר המארח נמצא מאחורי חומת אש רשתית שאתם מנהלים.
קראו את app.yml לפני ה-rebuild הראשון
האשף יוצר קובץ שמעתה והלאה נמצא באחריותכם. פתחו אותו באמצעות sudo nano /var/discourse/containers/app.yml. החלקים הבאים הם אלו שקובעים כמעט הכל.
templates:
- "templates/postgres.template.yml"
- "templates/redis.template.yml"
- "templates/web.template.yml"
- "templates/web.ratelimited.template.yml"
## Uncomment these two lines if you wish to add Lets Encrypt (https)
#- "templates/web.ssl.template.yml"
#- "templates/web.letsencrypt.ssl.template.yml"
expose:
- "80:80" # http
- "443:443" # https
env:
DISCOURSE_HOSTNAME: "forum.example.com"
DISCOURSE_DEVELOPER_EMAILS: "you@example.com"
DISCOURSE_SMTP_ADDRESS: smtp.example.com
DISCOURSE_SMTP_PORT: 587
DISCOURSE_SMTP_USER_NAME: user@example.com
DISCOURSE_SMTP_PASSWORD: "your-smtp-password"DISCOURSE_HOSTNAME הוא הכתובת שבה האתר מגיב, ו-Discourse בונה את הקישורים שלו על פיה; ערך שגוי יגרום לאתר להיטען פעם אחת ואז להפנות אתכם למקום אחר. DISCOURSE_DEVELOPER_EMAILS הוא רשימה מופרדת בפסיקים, וכתובות אלו מקבלות הרשאות מנהל (admin) באופן אוטומטי בעת ההרשמה הראשונה. הזינו את הכתובת שלכם שם והירשמו איתה, שכן כך נוצר חשבון המנהל הראשון.
הקובץ שומר את סיסמת ה-SMTP שלכם בטקסט גלוי, לכן הגבילו את הגישה לתיקייה באמצעות sudo chmod 700 /var/discourse/containers. מדובר בקובץ YAML, מה שאומר שרווחים הם חלק מההגדרה: מפתח שאינו מיושר כראוי יגרום לכשל ב-build עם שגיאת ניתוח (parse error) וישאיר אתכם ללא אתר. מלכודת אחת מתועדת בתוך קובץ הדוגמה עצמו. תו # בתוך סיסמה שאינה במירכאות מתחיל הערה, לכן הקפידו להוסיף מירכאות לכל סיסמה המכילה תו כזה.
דואר אלקטרוני הוא השלב שבו רוב ההתקנות נתקלות בקשיים
נכון לאוגוסט 2026, אשף ההתקנה מאפשר לדלג על הגדרות SMTP ולהשתמש במקום זאת בהתחברות באמצעות Discourse ID, והפקודה app.yml כוללת את ה-flag התואם DISCOURSE_SKIP_EMAIL_SETUP, המתואר שם כדלוג על אימות הגדרות הדואר. דילוג על שלב זה סביר עבור התרשמות ראשונית מהתוכנה. זוהי בחירה גרועה עבור קהילה פעילה, שכן ללא דואר יוצא, אף משתמש לא יוכל להפעיל חשבון או לאפס סיסמה.
הבעיה המעשית היא שרוב ספקי ה-VPS חוסמים את פורט 25 לתעבורה יוצאת, ולכן שרת דואר פשוט על השרת לא יצליח לשלוח הודעות. השתמשו ב-relay מאומת בפורט 587, או בפורט 465 עם TLS (אבטחת שכבת תעבורה) מובנה. עבור פורט 465, הגדירו את DISCOURSE_SMTP_FORCE_TLS: true, כפי שמומלץ בקובץ התצורה לדוגמה עבור פורט זה. בדקו את הקישוריות מהשרת לפני ביצוע rebuild.
nc -vz smtp.example.com 587תוצאה תקינה היא שורה בודדת שמסתיימת ב-succeeded!. פקודה שנתקעת ומסתיימת ב-timeout מעידה על כך שהפורט חסום בנתיב היציאה מה-VPS שלכם, ושום הגדרה ב-Discourse לא תפתור זאת. עברו לפורט שהספק שלכם מאפשר, או בקשו מהספק לפתוח את הפורט.
ברגע שהאתר פעיל, שלחו הודעת בדיקה מדף ה-Email בלוח הניהול (Admin), ולאחר מכן קראו את הלשוניות Skipped ו-Bounced באותו דף. בלשוניות אלו Discourse מתעד הודעות שסירב לשלוח והודעות שה-relay דחה, והן מציינות את סיבת הכשל, מה שמהיר יותר מקריאת לוגים.
TLS: אפשרו למכולה להנפיק לעצמה תעודה
אם Discourse מאזין לפורטים 80 ו-443, השתמשו במנגנון ההנפקה המובנה שלו. בטלו את ההערה בשורות ה-template של ה-SSL המוצגות לעיל, ולאחר מכן בצעו rebuild. ה-template מפעיל את acme.sh, שומר תעודות בנפח המשותף תחת /shared/ssl, מחדש אותן לפי לוח זמנים בתוך המכולה, ומגדיר את Discourse לכפות HTTPS.
פורט 80 חייב להישאר נגיש מהאינטרנט כדי שתהליך זה יצליח, שכן אתגר ה-HTTP נענה שם. Firewall שמאפשר רק את פורט 443 יגרום לבנייה להסתיים בהצלחה, אך התעודה לעולם לא תונפק. בדקו את התוצאה באמצעות ./launcher logs app מיד לאחר ה-rebuild.
האם כדאי להציב Nginx או Caddy בחזית?
אם Discourse הוא שירות האינטרנט היחיד בשרת ה-VPS, אין לעשות זאת. המכולה כבר מריצה Nginx מכוונן, ו-proxy נוסף מוסיף דילוג (hop), תעודה נוספת לחידוש ומקור חדש לתקלות ב-headers.
הציבו proxy בחזית כאשר ה-VPS משרת אתרים נוספים. הוסיפו את templates/web.socketed.template.yml לרשימת ה-templates, בצעו comment לשתי השורות של expose, והשאירו את שני ה-templates של ה-SSL במצב comment. המכולה תאזין כעת ל-unix socket בכתובת /var/discourse/shared/standalone/nginx.http.sock ולא תחזיק בפורטים כלל, מה שיפנה את פורטים 80 ו-443 עבור ה-proxy שלכם.
server {
listen 443 ssl;
server_name forum.example.com;
location / {
proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
}
}הנקודתיים בסוף .sock הן חלק מתחביר ה-unix socket של Nginx, ו-sudo nginx -t תדחה את התצורה בלעדיהן. גם X-Forwarded-Proto אינו אופציונלי. Discourse כותב קישורים מוחלטים, לכן ללא ה-header הזה הוא יפיק קישורי http:// בדף HTTPS, ודפדפנים יחסמו אותם כתוכן מעורב (mixed content). כאשר המכולה עובדת מול socket, ה-TLS הופך לאחריותכם, לכן הנפיקו את התעודה במארח (host) בעזרת Certbot ב-Ubuntu 24.04 ו-Nginx. אם טרם החלטתם על proxy, השוואת Nginx, Caddy ו-Traefik מפרטת את השיקולים שעליכם לקחת בחשבון.
בנייה מחדש, שדרוגים והפקודות שתשתמשו בהן בפועל
cd /var/discourse
./launcher rebuild appהפקודה rebuild משמידה את המכולה הרצה, מאתחלת מכולה חדשה מתוך app.yml ומפעילה אותה. האתר אינו זמין במהלך כל תהליך הבנייה, לכן יש להתייחס לכל שינוי בתצורה כאל השבתה מתוכננת של מספר דקות.
שינוי ערכים תחת env: בלבד אינו דורש זאת. הפקודה ./launcher destroy app && ./launcher start app יוצרת מחדש את המכולה מהאימג' שכבר בניתם, פעולה שנמשכת שניות ספורות. כל שינוי תחת templates: או hooks: משנה את האימג' עצמו, ולכן מחייב בנייה מלאה מחדש.
שדרוגים מגיעים בשתי דרכים. שחרורי נקודה (point releases) מוחלים דרך ממשק האינטרנט בכתובת /admin/upgrade, המסופק על ידי התוסף docker_manager ש-app.yml משכפל (clone) במהלך הבנייה. שינויים באימג' הבסיס או בתבניות מגיעים מ-git.
cd /var/discourse
git pull
./launcher rebuild appבנייה מחדש היא השלב שבו שרתים קטנים נוטים להיכשל, כיוון שקימפול הנכסים (assets) הוא שיא צריכת הזיכרון של המערכת כולה. בנייה שנעצרת באמצע, כאשר dmesg מציג שורה כמו Out of memory: Killed process המציינת תהליך ruby, מעידה על מחסור בזיכרון במהלך הבנייה, גם אם האתר עצמו פעל היטב לפני כן. הוסיפו swap והריצו את הבנייה מחדש.
./launcher logs app
./launcher enter app
./launcher cleanupהפקודה logs מדפיסה את הפלט של המכולה, enter פותחת shell בתוכה, ו-cleanup מסירה מכולות שנעצרו לפני יותר מ-24 שעות. הריצו את cleanup מדי פעם, כיוון שכל בנייה מחדש מותירה מאחוריה מכולה ישנה, והדיסק בשרת VPS קטן עלול להתמלא בשקט.
גיבויים, והקובץ שהגיבוי אינו מכיל
בצעו גיבויים מדף ה-Backups ב-Admin. הארכיון נשמר על המארח ב-/var/discourse/shared/standalone/backups/default/. אותה פעולה ניתנת לביצוע גם מתוך ה-shell.
cd /var/discourse
./launcher enter app
discourse backupdiscourse restore <filename> מבצע את הפעולה ההפוכה, ושחזורים נדחים עד להרצת discourse enable_restore. מנגנון הגנה זה קיים כדי למנוע פקודה שגויה מלהחליף פורום פעיל.
ישנם שני פערים שעליכם לסגור בעצמכם. הארכיון מכיל את מסד הנתונים, והוא מכיל קבצים שהועלו רק כאשר הגדרת הגיבוי הכוללת העלאות מופעלת; לכן, בדקו הגדרה זו לפני שתסתמכו עליה. הארכיון לעולם אינו מכיל את app.yml, לכן שחזור על גבי VPS חדש עדיין דורש את שם המארח (hostname) ובלוק ה-SMTP שלכם, מה שאומר שיש להעתיק גם קובץ זה אל מחוץ לשרת.
בנוסף, הארכיון נשמר על אותו דיסק של האתר אותו הוא מגבה, וזה אינו נחשב לגיבוי. העבירו אותו למקום אחר לפי לוח זמנים קבוע.
rsync -avz root@forum.example.com:/var/discourse/shared/standalone/backups/default/ ~/discourse-backups/העלות ב-RAM של פורום פעיל
ה-bootstrap מגדיר את UNICORN_WORKERS ואת db_shared_buffers על סמך הזיכרון וה-CPU שהוא מזהה, וקובץ התצורה לדוגמה מגביל את ה-shared buffers לרבע מסך הזיכרון. כל worker של unicorn הוא תהליך Ruby מלא, ו-Sidekiq מריץ משימות רקע לצדם, לכן צריכת הזיכרון נגזרת ממספר הבקשות בו-זמנית ולא ממספר המשתמשים הרשומים. פורום שקט עם כמה מאות משתמשים אינו מהווה עומס כבד. לרוב, מה שמשתף את השרת חשוב יותר; אם מדובר בספריית תמונות, רצפות ה-RAM שנמדדו ב-השוואה בין PhotoPrism ל-Immich יבהירו לכם אם נותר ל-Discourse מספיק מרווח פעולה כדי לסיים תהליך rebuild.
אל תקבעו את גודל השרת לפי מספר שמופיע במאמר, כולל מאמר זה. מדדו את הנתונים שלכם בעצמכם.
free -m
docker stats --no-streamשימוש קבוע ב-swap יחד עם דפים איטיים מעיד על מחסור ב-RAM. זיכרון יציב לצד דפים איטיים מעיד בדרך כלל על בעיה אחרת, לכן קראו את ./launcher logs app לפני שאתם רוכשים תוכנית גדולה יותר. הוסיפו בדיקה חיצונית לשרת, כיוון שפורום שנגמר לו הזיכרון ב-3 לפנות בוקר קורס בשקט: צג סטטוס Uptime Kuma בניהול עצמי על מארח נפרד יתריע בפניכם לפני שהמשתמשים שלכם ידווחו על כך.
מתי Discourse אינו הבחירה הנכונה
Discourse הוא יישום גדול בעל תהליך התקנה כבד ומחזור בנייה מחדש (rebuild) עבור כל הגדרה השמורה בתוך app.yml. עלות זו מקנה כלי ניהול תוכן אמיתיים ומנוע חיפוש שמתפקד היטב גם כאשר הארכיון גדול. עבור קבוצה של שלושים איש המעוניינים במקום לנהל בו שיחות, מדובר במערכת כבדה מדי ביחס לצרכי התקשורת. קראו תחילה את השוואת תוכנות הפורומים לאירוח עצמי, ובחרו ב־Discourse רק אם אתם זקוקים ליכולות הספציפיות שלו, ולא רק משום שזהו השם המוכר לכם.
FAQ
האם ניתן להתקין Discourse על שרת VPS ללא שם מתחם?
לא. התצורה שמגיעה עם התוכנה קובעת ש־Discourse לא תעבוד עם כתובת IP בלבד, ונדרש DISCOURSE_HOSTNAME. התוכנה בונה קישורים מוחלטים על בסיס שם המארח, לכן שימוש בכתובת IP ישבור קישורים וימנע הנפקת תעודות. צרו רשומת A לפני תחילת העבודה, ואמתו באמצעות dig +short forum.example.com שהיא מצביעה על כתובת השרת שלכם.
האם חובה להגדיר SMTP כדי לסיים את ההתקנה?
נכון לאוגוסט 2026, ניתן לדלג על כך. אשף ההתקנה מציע כניסה באמצעות Discourse ID במקום, ו־app.yml כולל דגל המדלג על אימות הגדרות הדואר. לכל שימוש מעבר להתרשמות ראשונית, יש להגדיר SMTP, כיוון שאימות חשבונות ואיפוס סיסמאות מתבצעים באמצעות דואר אלקטרוני. השתמשו ב־relay מאומת בפורט 587 או 465, שכן רוב ספקי ה־VPS חוסמים תעבורה יוצאת בפורט 25.
מדוע תהליך ה-rebuild של Discourse נכשל באמצע?
הסיבה הנפוצה היא מחסור בזיכרון. הידור הנכסים (assets) במהלך הבנייה דורש יותר זיכרון מאשר הפעלת האתר עצמו, לכן שרת שמריץ את הפורום היטב עלול להיכשל בביצוע rebuild. אם dmesg מציג Out of memory: Killed process המצביע על תהליך ruby, הוסיפו swap (קובץ ה-swap של האשף הוא בגודל 2 GB) והריצו את ./launcher rebuild app שוב. בנייה שנעצרת בשל שגיאת YAML מעידה על טעות בהזחה (indentation) בתוך app.yml.
האם Discourse צריכה לשבת מאחורי Nginx או Caddy משלי?
רק אם ה־VPS מארח אתרים נוספים. אם השרת מוקדש ל־Discourse בלבד, תנו למכולה להחזיק בפורטים 80 ו-443 ולהנפיק לעצמה תעודות; כך יש פחות רכיבים שעלולים להשתבש. כדי לשתף את המכונה, הוסיפו templates/web.socketed.template.yml, הגיבו (comment out) את שורות ה-expose, ובצעו proxy ל-unix socket בכתובת /var/discourse/shared/standalone/nginx.http.sock. העבירו את X-Forwarded-Proto, אחרת Discourse תפיק קישורי http:// בתוך דף HTTPS.
כיצד מגבים התקנת Discourse עצמאית?
השתמשו בדף הגיבויים (Backups) בממשק הניהול, או הריצו את discourse backup לאחר ./launcher enter app. הארכיונים נשמרים במארח בנתיב /var/discourse/shared/standalone/backups/default/. ודאו שההגדרה שכוללת העלאות (uploads) פעילה, העתיקו את /var/discourse/containers/app.yml יחד עם הארכיון, והעבירו את שניהם למכונה אחרת; גיבוי שנמצא על אותו דיסק של האתר לא יגן עליכם במקרה של כשל בדיסק.