התקנת Evolution API על שרת עצמי: פרטיות, Docker וגיבוי
מדריך להתקנת Evolution API על שרת עצמי עם Docker: חיבור מספר WhatsApp, Webhook, צמצום שמירת תוכן, ניטור וגיבוי, והסבר ברור על הסיכון בחיבור לא רשמי.
מערכת אוטומציה · עודכן

מה יהיה לכם בסיום?
בסיום יהיה לקורא מערך Evolution API נעוץ בגרסה מוגדרת, מבודד מאחורי HTTPS, עם סביבת הדגמה לחיבור מספר, Webhook, בדיקות קבלה, תוכנית גיבוי והחלטות שמירה מתועדות.
למי זה מתאים: בעלי עסקים ומיישמי אוטומציה שמסוגלים לנהל שרת קטן ורוצים להבין גם את המחיר התפעולי, סיכוני החשבון ומשמעות הפרטיות לפני חיבור WhatsApp.
מה להכין לפני שמתחילים
- שרת VPS נקי עם גישת מנהל ויכולת להפעיל Docker Compose
- שם מתחם או תת מתחם שניתן להפנות אל השרת ולהגן באמצעות HTTPS
- מספר WhatsApp ייעודי להדגמה שהבעלים אישר לחבר כמכשיר מקושר
- יעד Webhook בסביבת בדיקה שאינו מכיל מידע של לקוחות
- הבנה שהחיבור אינו Cloud API רשמי ושקיים סיכון להגבלה או חסימה
האם Evolution API מתאים לכם בכלל
התקנת Evolution API על שרת עצמי מתאימה למספר אישי או לקו בוט שהבעלים שלו הסכימו לחבר, כשחשוב לכם לשלוט בשרת שמעבד את ההודעות. זה חיבור לא רשמי שפועל כמכשיר מקושר של WhatsApp, לא Cloud API של Meta, והוא חושף את החשבון לסיכון של הגבלה או חסימה. לשירות לקוחות בהיקף גדול ולשליחה יזומה עדיף המסלול הרשמי.
Evolution API הוא שער קוד פתוח שמבוסס על Baileys, ונרשם בחשבון ה־WhatsApp שלכם כמו דפדפן נוסף. בקובץ ההגדרות לדוגמה השרת מזדהה כ־Chrome עם שם הלקוח Evolution API, ו־WhatsApp מתירה לקשר עד ארבעה מכשירים לטלפון הראשי בו זמנית WhatsApp Help Center, linked devices, accessed October 2026 (נפתח בחלון חדש).
שרת בבעלותכם מסיר את התלות בספק צד שלישי שמחזיק את ההודעות, אבל הוא לא מצפין אותן מפני מי שמפעיל אותו. בתוצאת חיפוש אחת Evolution API מתואר במפורש כלקוח לא רשמי, בעוד שדפי אירוח מתארים בעיקר בעלות על תשתית www.zavu.dev, accessed October 2026 (נפתח בחלון חדש). הפרטיות כאן היא שאלה של מי מחזיק את השרת, לא של הצפנה מפני מי שמפעיל אותו.
ברירת המחדל גם שומרת הרבה: כל דגלי השמירה במסד מוגדרים true בקובץ לדוגמה EvolutionAPI/evolution-api .env.example, accessed October 2026 (נפתח בחלון חדש). בסכמת 2.3.7 קיימת בטבלת Message עמודת message מסוג jsonb, המיועדת לתוכן ההודעה. לא בדקנו כתיבה אליה בתעבורה אמיתית. בטייגרמדיה התקנו Evolution API v2 על שרת קיים בספטמבר 2026 ונעצנו אותו בגרסה 2.3.7. נכון ל־12 באוקטובר 2026 כל דגלי השמירה דולקים בהתקנה שלנו.
תנאי השימוש של WhatsApp אוסרים הודעות המוניות, הודעות אוטומטיות וחיוג אוטומטי לא מורשים, וגם הנדסה לאחור של השירות WhatsApp Terms of Service, accessed October 2026 (נפתח בחלון חדש). הנחיות ההודעות מונות כהתנהגות עוינת שימוש בלקוחות לא רשמיים, הודעות המוניות, הודעות אוטומטיות, חיוג אוטומטי או אוטומציה, כדי לפגוע ב־WhatsApp או במשתמשים שלה ("to harm WhatsApp or our users") WhatsApp Messaging Guidelines, accessed October 2026 (נפתח בחלון חדש). לפי קטע מתוצאות החיפוש של מרכז העזרה (גוף הדף לא נשלף), חשבון יכול להיחסם זמנית או לצמיתות, או להיות מוגבל, כולל הגבלה של היכולת לקשר מכשירים WhatsApp Help Center, About unofficial apps, accessed October 2026 (נפתח בחלון חדש).
למי החיבור יכול להתאים:
החיבור יכול להתאים לקו אישי שלכם, או לקו בוט ייעודי שהבעלים שלו אישרו לחבר ושהאנשים שמדברים איתו יודעים שהם מדברים עם מערכת. בטייגרמדיה אנחנו משתמשים במספר מקושר לקווים אישיים ולקווי בוט, ומשאירים תיבות שירות של לקוחות על Cloud API. החיבור מתאים רק למי שמוכנים לתחזק שרת: לעדכן, לגבות, לבדוק שחזור ולשים לב כשהקו מתנתק.
מתי עדיף לעצור ולבחור Cloud API:
עצרו אם אתם צריכים לפנות ללקוחות מחוץ לחלון השירות. בפלטפורמה העסקית הרשמית, לפי מדיניות ההודעות העסקיות, אוטומציה מותרת בתשובות בתוך חלון של 24 שעות עם מסלול העברה ברור לאדם, והודעה מחוץ לחלון דורשת תבנית מאושרת WhatsApp Business Messaging Policy, accessed October 2026 (נפתח בחלון חדש). Evolution אינו חלק מהפלטפורמה הזו ואין בו מנגנון כזה, ושליחה אוטומטית דרכו נופלת תחת הסיכון של לקוח לא רשמי ותחת האיסורים הכלליים של WhatsApp WhatsApp Terms of Service, accessed October 2026 (נפתח בחלון חדש).
עצרו גם אם מדובר בתיבת שירות עם כמה נציגים, בשליחה בהיקף גדול או במספר שאסור לכם לאבד, וקראו את המדריך להקמת WhatsApp Cloud API הרשמי, ואם המטרה היא בוט עם העברה לנציג, את המדריך לבוט WhatsApp לעסק.
מה באמת קורה להודעה בדרך
הודעה שמגיעה ל־Evolution עוברת ארבע תחנות, ובכל אחת שאלת פרטיות אחרת. ההבחנה ביניהן מונעת הבטחות כמו "אף אחד לא יכול לקרוא את ההודעות".
הראשונה היא התעבורה. לפי ההסבר של WhatsApp על הצפנה מקצה לקצה (נפתח בחלון חדש), ההצפנה מגינה על ההודעה בין הקצוות של השיחה. מכשיר מקושר הוא אחד הקצוות האלה, ולכן ההודעה מגיעה אליו כדי שיפענח אותה. זו מסקנה שלנו מתוך התיאור של WhatsApp, לא מדידה שערכנו.
התחנה השנייה היא שרת Evolution. כאן ההודעה גלויה לתהליך שרץ בקונטיינר ולכל מי שיש לו גישת מנהל לשרת. מבחינת WhatsApp השרת הוא מכשיר מקושר, והוא מופיע ברשימת המכשירים בטלפון WhatsApp Help Center, linked devices, accessed October 2026 (נפתח בחלון חדש).
התחנה השלישית היא מסד הנתונים. כברירת מחדל דגלי DATABASE_SAVE_* דולקים EvolutionAPI/evolution-api .env.example, accessed October 2026 (נפתח בחלון חדש), ובבדיקה שלנו בסביבת הדגמה הסכמה בגרסה 2.3.7 כללה טבלאות Message, MessageUpdate, Contact, Chat, Label, Media ו־Session. מה שנשמר שם יגיע גם לכל גיבוי של המסד.
התחנה הרביעית היא יעד ה־Webhook. כל אירוע שנשלח ליעד, למשל ל־n8n, יוצא מהשרת ונשמר לפי ההגדרות של היעד, ולכן גם כשהמסד של Evolution נקי, היסטוריית ההרצות של מערכת האוטומציה יכולה להחזיק את אותו תוכן. נכון ל־12 באוקטובר 2026 כל דגלי השמירה דולקים בהתקנה שלנו.
מה היינו משנים בטייגרמדיה לטובת פרטיות: מכבים את דגלי השמירה של הודעות, אנשי קשר ושיחות אם שום יכולת לא צריכה היסטוריה, מצמצמים גישת מעטפת ומסד, ושומרים גיבויים מוצפנים בלבד.
| תחנה | מה קורה להודעה | מי יכול לראות תוכן | איך מצמצמים |
|---|---|---|---|
| תעבורה בין הטלפון ל־WhatsApp | מוצפנת בדרך למכשירים המקושרים | לפי תיאור WhatsApp, הקצוות של השיחה | אין מה להגדיר בצד שלכם |
| שרת Evolution | מפוענחת ומעובדת בתהליך | התהליך ומי שיש לו גישת מנהל לשרת | מעט משתמשים, גישת מעטפת מוגבלת |
| מסד PostgreSQL | נשמרת אם דגלי השמירה דולקים | מי שיש לו גישה למסד או לגיבוי | דגלי DATABASE_SAVE_* כבויים, ובדיקה בספירה |
| יעד ה־Webhook | נשלחת כאירוע ליעד שהגדרתם | מפעיל היעד וההיסטוריה שלו | לשלוח רק אירועים נחוצים ולהגביל היסטוריה ביעד |
Evolution מול Cloud API הרשמי
ההחלטה תלויה בסוג המספר, בהסכמה של מי שמקבלים את ההודעות ובמה שהעסק צריך לשלוח. Evolution לא מחליף את Cloud API: הוא נותן שליטה בשרת, במחיר של מעמד לא רשמי, תחזוקה עצמית וסיכון חשבון.
מדיניות ההודעות העסקיות של WhatsApp לא מזכירה לקוחות לא רשמיים או של צד שלישי במפורש. היא כן קובעת ש־WhatsApp יכולה להגביל או להסיר גישה למי שמפעיל שירות שמשתמש ב־WhatsApp בניגוד לתנאים, למשל שליחה לאנשים בהיקף לא מורשה WhatsApp Business Messaging Policy, accessed October 2026 (נפתח בחלון חדש).
מספר אישי או קו בוט בהסכמה:
כאן Evolution יכול להיות סביר: מספר שאתם הבעלים שלו, היקף קטן ואנשים שבחרו לכתוב לקו, עם דרך להגיע לאדם. גם כך הסיכון לא נעלם: לפי קטע החיפוש של מרכז העזרה, שימוש באפליקציות לא רשמיות עלול להוביל לחסימה זמנית או קבועה WhatsApp Help Center, About unofficial apps, accessed October 2026 (נפתח בחלון חדש).
שירות לקוחות ושליחה בהיקף גדול:
כאן המסלול הרשמי מתאים יותר. במסלול הרשמי הודעה מחוץ לחלון של 24 שעות דורשת תבנית מאושרת WhatsApp Business Messaging Policy, accessed October 2026 (נפתח בחלון חדש). ב־Evolution אין מנגנון כזה, ושליחה יזומה או אוטומטית דרכו חשופה לסיכון של לקוח לא רשמי ולאיסורים הכלליים של WhatsApp. חסימה של מספר שירות פוגעת בעסק יותר מחסימה של קו ניסוי.
| שיקול | Evolution כמכשיר מקושר | Cloud API הרשמי |
|---|---|---|
| מעמד החיבור | לקוח לא רשמי שנרשם כמכשיר מקושר | פלטפורמה רשמית של Meta |
| שליחה מחוץ לחלון השירות | אין מנגנון תבניות, ושליחה אוטומטית חשופה לאיסורים הכלליים של WhatsApp | הודעה מחוץ לחלון דורשת תבנית מאושרת |
| סיכון לחשבון | הגבלה או חסימה, כולל הגבלה של היכולת לקשר מכשירים | כפוף למדיניות העסקית של WhatsApp |
| התאמה לשימוש | קו אישי או קו בוט בהסכמה | שירות לקוחות, נציגים ושליחה יזומה |
| מי מתחזק | אתם: שרת, גרסה, גיבוי, ניטור וחיבור מחדש | Meta מתחזקת את הפלטפורמה, אתם את היישום |
| עלות תפעולית | לפי הניסיון שלנו אין תשלום ל־Meta לכל שיחה, אבל גם אין אף אחת מההגנות של הפלטפורמה הרשמית; עלות השרת וגדילת המסד לא נמדדו | תמחור של Meta, לפי המדריך הרשמי |
| שליטה בתוכן | השרת שלכם מפענח ושומר לפי הדגלים | לפי התנאים של Meta, שהמדריך הזה לא בודק |
מה צריך להכין לפני ההתקנה
הכינו את כל החלקים לפני הפקודה הראשונה, כי כל אחד מהם משפיע על אבטחה. שרת שעלה בלי HTTPS יכול להישאר כך.
בטייגרמדיה נתנו ל־Evolution קונטיינרים משלו של Postgres ו־Redis, ולא שיתפנו את אלה של אפליקציה אחרת באותו שרת, כי בעל המערכת בחר בהפרדה מלאה. כל פורט מפורסם של קונטיינר קשור אצלנו לכתובת 127.0.0.1 מאחורי שרת הפוך עם HTTPS, כי Docker מפרסם פורטים שעוקפים את חומת האש UFW, ולכן קשירה ל־0.0.0.0 חושפת את השירות גם כשסטטוס חומת האש נראה נקי.
המפתח הגלובלי הוא הסוד המרכזי. לפי הקובץ לדוגמה של הפרויקט הוא נותן גישה לכל המופעים, וחייב להופיע בכותרת הבקשה כדי ליצור מופע EvolutionAPI/evolution-api .env.example, accessed October 2026 (נפתח בחלון חדש). החליטו מראש שרק הבעלים של המערכת מחזיקים בו.
החליטו גם מראש מה יהיה מספר ההדגמה ומי הבעלים שלו. אחרי כל חיבור מחדש, ולפני כל שליחה, בודקים שהמצב open ושמספר הבעלים של המופע הוא המספר הצפוי, כי מי שמחזיק קוד צימוד או גישה ל־QR יכול לצמד טלפון אחר. ותזכירו לבעלים שלפי קטע החיפוש של מרכז העזרה הגבלה יכולה לכלול גם הגבלה של היכולת לקשר מכשירים WhatsApp Help Center, About unofficial apps, accessed October 2026 (נפתח בחלון חדש).
- הכינו שרת VPS עם גישת מנהל, Docker ו־Docker Compose.
- בחרו תת דומיין שיופנה לכתובת הציבורית של השרת.
- התקינו שרת הפוך שמנפיק תעודת HTTPS, בדוגמה כאן Caddy על השרת עצמו.
- בחרו מספר WhatsApp ייעודי להדגמה, וקבלו מהבעלים שלו אישור לחבר אותו כמכשיר מקושר.
- הכינו יעד Webhook בסביבת בדיקה, מוגן ב־HTTPS ובכותרת הרשאה, בלי מידע של לקוחות.
- קבעו מי מחזיק את המפתח הגלובלי ומי מקבל רק טוקן של מופע.
- תכננו מקום לגיבוי מוצפן מחוץ לשרת, ומקום נפרד לסיסמת ההצפנה.
- כתבו אילו נתונים מותר לשמור במסד ולכמה זמן, לפני שמחברים מספר.
הארכיטקטורה והגרסאות שנבחרו
המערך במדריך כולל שירות API של Evolution, מסד PostgreSQL ו־Redis, כל אחד בקונטיינר משלו על רשת Docker ייעודית. רק ה־API מפורסם, ורק על הכתובת המקומית. בבדיקה שלנו בסביבת הדגמה כל המערך רץ על 127.0.0.1:8080 שמופנה לפורט 8080 בקונטיינר, עם SERVER_URL=https://evo.example.com, וכל הבקשות נשלחו ל־http://127.0.0.1:8080.
הפרויקט עבר כתובת: המאגר הנוכחי הוא evolution-foundation/evolution-api ב־GitHub (נפתח בחלון חדש), והתמונה ב־Docker Hub נקראת evoapicloud/evolution-api. ביום ההתקנה בדקו בדף ה־releases מה הגרסה היציבה האחרונה.
קובץ ה־Compose של הפרויקט לא מתאים להעתקה ישירה: הוא משתמש ב־evoapicloud/evolution-api:latest, ב־postgres:15 וב־redis:latest, מפרסם את ה־API על 127.0.0.1:8080:8080 אבל את ממשק ה־manager האופציונלי על "3000:80", כלומר על כל הממשקים, ודורש רשת חיצונית בשם dokploy-network EvolutionAPI/evolution-api docker-compose.yaml, accessed October 2026 (נפתח בחלון חדש).
בזיכרון יש לנו שתי מדידות נפרדות, ואין לחבר ביניהן. לפי ההפעלה שלנו, בהתקנת הייצור בספטמבר 2026 ובמנוחה, ה־API צרך כ־266 MiB, Postgres כ־70 MiB ו־Redis כ־9 MiB (נתון תפעולי שלא נמדד מחדש). בבדיקה שלנו בסביבת הדגמה באוקטובר, עם שני מופעים שלא קושרו וכ־30 שניות אחרי הפעלה מחדש, ה־API צרך 230.1 MiB, Postgres צרך 30.54 MiB ו־Redis צרך 3.316 MiB, כ־264 MiB בסך הכול. גודל התמונות היה 1.83 GB, 417 MB ו־57.8 MB, וכרך Postgres תפס 66.32 MB. צריכה עם מספרים מקושרים ופעילים, וגדילת המסד לכל הודעה או קובץ מדיה, לא נמדדו.
למה לא להשתמש בתג latest:
הגרסה היציבה האחרונה ב־GitHub היא 2.3.7, שפורסמה ב־2025-12-05. התגים החדשים יותר, 2.4.0-rc1 מ־2026-05-06 ו־2.4.0-rc2 מ־2026-05-17, מסומנים כגרסאות טרום הפצה EvolutionAPI/evolution-api GitHub releases, accessed October 2026 (נפתח בחלון חדש). ב־Docker Hub התג היציב v2.3.7 נושא קידומת v, ותגי המועמדים 2.4.0-rc1 ו־2.4.0-rc2 בלי קידומת Docker Hub evoapicloud/evolution-api tags, accessed October 2026 (נפתח בחלון חדש).
התג latest נדחף לאחרונה ב־2026-05-06, וה־digest שלו לא תאם לשלושת התגים שבדקנו: v2.3.7, 2.4.0-rc1 ו־2.4.0-rc2, ולכן לא זיהינו בוודאות איזו גרסה הוא מכיל Docker Hub evoapicloud/evolution-api tags, accessed October 2026 (נפתח בחלון חדש). הוא תג משתנה. התקנה מהתג הזה יכולה להביא קוד אחר בכל pull.
גם דוגמאות מוכנות מערבבות: הדוגמה של Senate נועצת את Evolution API ב־v2.2.1 ואת PostgreSQL ב־17, אבל משתמשת ב־redis:latest senate.sh, accessed October 2026 (נפתח בחלון חדש).
הכלל אצלנו בטייגרמדיה: נועצים תג ובודקים על המערכת החיה אחרי כל שדרוג. תגים קודמים זמינים, למשל v2.3.6 שנדחף ב־2025-10-21 ו־v2.3.5 שנדחף ב־2025-10-15.
מה מבודד ומה נשאר משותף:
מבודדים: PostgreSQL ו־Redis של Evolution, רשת Docker פנימית וכרכים קבועים נפרדים. מבחוץ מגיעים רק דרך השרת ההפוך. משותפים: מערכת ההפעלה, שירות Docker, הדיסק ומי שיש לו גישת מנהל. הפרדת הקונטיינרים לא מגינה מפני מנהל השרת או מפני תקלה בדיסק, ולכן הגיבוי המוצפן יוצא מהשרת.
# docker-compose.yml, image lines pinned by tag AND digest (replace the three image: lines)
image: evoapicloud/evolution-api:v2.3.7@sha256:1bd8afc4a6cf48822e6cf02469aeae7bd35a12a6b616eacd1291926307f4d339
image: postgres:15-alpine@sha256:f7d23353e1b15400d22ebe31189f4d314b87a4c129cc400c8c2d8d4ca127bf81
image: redis:7-alpine@sha256:858f009f9709ce576febc734aa78b8f6d624b82571f9ddb6bda4377c833b3499בניית מערך Docker Compose
קובץ ה־Compose כאן הוא המינימום שנבדק: שלושה שירותים, כרכים קבועים, רשת ייעודית וקשירה של ה־API לממשק המקומי בלבד. Postgres ו־Redis לא מפרסמים פורט, ונגישים ל־API רק ברשת הפנימית בשמות evo-postgres ו־evo-redis.
ההבדלים מהקובץ של הפרויקט מכוונים. אין רשת חיצונית dokploy-network, אין ממשק manager נפרד שמפורסם על "3000:80", והתמונות לא נשענות על latest EvolutionAPI/evolution-api docker-compose.yaml, accessed October 2026 (נפתח בחלון חדש). התג של Evolution מגיע מהמשתנה EVOLUTION_TAG בקובץ .env, וברירת המחדל שלו היא v2.3.7 Docker Hub evoapicloud/evolution-api tags, accessed October 2026 (נפתח בחלון חדש).
תג הוא שם משתנה, לא נעילה. postgres:15-alpine זז כשהמתחזקים מפרסמים בנייה חדשה, ולכן מי שרוצה לשחזר בדיוק את מה שנבדק נועץ גם לפי digest. בבדיקה שלנו בסביבת הדגמה קראנו את ה־digest של שלוש התמונות ב־2026-10-12, Compose קיבל את הצורה tag@digest, והמערך הנעוץ רץ. ה־digest הוא צילום מצב, והתגים יכולים לזוז. שורות ה־image הנעוצות מופיעות בפרק הקודם; קראו את ה־digest אצלכם אחרי docker pull לפני שאתם מעתיקים אותן.
אחרי ההפעלה, docker compose ps הוא ההוכחה הראשונה לבידוד. בבדיקה שלנו בסביבת הדגמה רק שורת ה־API הציגה 127.0.0.1:8080->8080/tcp, ו־Postgres ו־Redis הציגו רק פורטים פנימיים. אם אתם רואים 0.0.0.0 באחת השורות, עצרו ותקנו לפני שממשיכים.
- צרו תיקייה ייעודית למערך ושמרו בה את
docker-compose.ymlמהדוגמה. - צרו לצידו את קובץ
.envלפי הפרק הבא, ואל תפעילו לפני שהסודות בו חדשים. - בדקו את תקינות הקובץ עם
docker compose config -q. - הפעילו את המערך עם
docker compose up -d. - הריצו
docker compose psוודאו שרק ה־API מפורסם, ורק על 127.0.0.1:8080. - החליפו את שורות
imageבשורות tag@digest מהפרק הקודם אם אתם רוצים נעילה מדויקת, והריצו את המערך שוב.
name: evoguide3
services:
evo-api:
image: evoapicloud/evolution-api:${EVOLUTION_TAG:-v2.3.7}
container_name: evoguide3_api
restart: unless-stopped
depends_on: [evo-postgres, evo-redis]
ports: ["127.0.0.1:8080:8080"]
env_file: .env
volumes: [evo_instances:/evolution/instances]
networks: [evoguide3-net]
evo-postgres:
image: postgres:15-alpine
container_name: evoguide3_pg
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes: [evo_pg:/var/lib/postgresql/data]
networks: [evoguide3-net]
evo-redis:
image: redis:7-alpine
container_name: evoguide3_redis
restart: unless-stopped
command: redis-server --appendonly yes
volumes: [evo_redis:/data]
networks: [evoguide3-net]
volumes: {evo_instances: {}, evo_pg: {}, evo_redis: {}}
networks:
evoguide3-net: {name: evoguide3-net}
הגדרת סודות ושמירת מידע
קובץ .env מחזיק סודות, כתובות ודגלי שמירה. קראו אותו מול הקובץ לדוגמה של הפרויקט (נפתח בחלון חדש), שבו מופיעים כל המשתנים וברירות המחדל.
המפתח הגלובלי ב־AUTHENTICATION_API_KEY הוא הסוד החזק ביותר, כי הוא נותן גישה לכל המופעים, והוא שמור לבעלים בלבד. מי שמשלב מבחוץ מקבל רק את הטוקן של המופע שלו, וביעד ה־Webhook של אותו מופע שמים סוד חדש משלו.
סיסמת PostgreSQL מופיעה פעמיים: ב־POSTGRES_PASSWORD, שממנו הקונטיינר יוצר את המשתמש, ובתוך DATABASE_CONNECTION_URI. שני הערכים חייבים להיות זהים. Redis במערך שנבדק רץ בלי סיסמה, וזה סביר רק כל עוד הפורט שלו לא מפורסם ורק שירות ה־API נמצא איתו ברשת.
יצירת סודות חדשים:
צרו ערכים אקראיים חדשים למפתח ולסיסמת המסד, למשל עם openssl rand -hex, ולא מסרטון או מדוגמה. ערך הקסדצימלי לא דורש קידוד בתוך מחרוזת החיבור. אל תכניסו את הקובץ למאגר קוד.
מה ברירת המחדל שומרת:
בקובץ לדוגמה הדגלים DATABASE_SAVE_DATA_INSTANCE, DATABASE_SAVE_DATA_NEW_MESSAGE, DATABASE_SAVE_MESSAGE_UPDATE, DATABASE_SAVE_DATA_CONTACTS, DATABASE_SAVE_DATA_CHATS, DATABASE_SAVE_DATA_LABELS, DATABASE_SAVE_DATA_HISTORIC ו־DATABASE_SAVE_IS_ON_WHATSAPP מוגדרים כולם true, יחד עם DATABASE_SAVE_IS_ON_WHATSAPP_DAYS=7 ו־DATABASE_DELETE_MESSAGE=true. ההערה מעליהם אומרת לבחור אילו נתונים לשמור במסד EvolutionAPI/evolution-api .env.example, accessed October 2026 (נפתח בחלון חדש).
נכון ל־12 באוקטובר 2026 כל דגלי השמירה דולקים בהתקנה שלנו. בקובץ שבדוגמה כאן נשאר דולק רק DATABASE_SAVE_DATA_INSTANCE, שמתייחס לנתוני המופע, וכל דגלי ההודעות, אנשי הקשר, השיחות וההיסטוריה כבויים.
מה עדיין לא נבדק:
הגדרת הדגלים ל־false היא הגדרת צמצום, לא הוכחה שתוכן לא נשמר. בסביבת ההדגמה לא חובר מספר, ולכן לא נמדד מה הדגלים עושים בתעבורה אמיתית. את ההשפעה אתם בודקים בעצמכם בספירה לפני ואחרי, בפרק על צמצום שמירת המידע.
תוצאה שלילית שמדדנו: ברירת המחדל היא AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true EvolutionAPI/evolution-api .env.example, accessed October 2026 (נפתח בחלון חדש), ושינוי ל־false נראה כמו בקרת פרטיות. בבדיקה שלנו בסביבת הדגמה על גרסה 2.3.7 הוא לא הסיר את שדה הטוקן מתשובת fetchInstances, ובקוד שהופץ הדגל שולט רק בשדה apiKey בגוף ה־webhook. אל תסמכו עליו כדי להסתיר טוקנים.
- העתיקו את קובץ ה־
.envמהדוגמה לתיקיית המערך. - החליפו את
<API_KEY>ואת שני המופעים של<DB_PASSWORD>בערכים חדשים שיצרתם. - כתבו ב־
SERVER_URLאת הכתובת הציבורית שתשמש מאחורי ה־HTTPS שלכם. - החליטו אילו דגלי
DATABASE_SAVE_*נשארים דולקים, ותעדו ליד כל אחד למה הוא נחוץ. - הגבילו את הרשאות הקובץ עם
chmod 600 .env. - שמרו עותק של המפתח הגלובלי במקום מאובטח מחוץ לשרת.
SERVER_NAME=evolution
SERVER_TYPE=http
SERVER_PORT=8080
SERVER_URL=https://evo.example.com
DEL_INSTANCE=false
DATABASE_PROVIDER=postgresql
DATABASE_CONNECTION_URI=postgresql://evouser:<DB_PASSWORD>@evo-postgres:5432/evolution_db?schema=evolution_api
DATABASE_CONNECTION_CLIENT_NAME=evolution_guide
DATABASE_SAVE_DATA_INSTANCE=true
DATABASE_SAVE_DATA_NEW_MESSAGE=false
DATABASE_SAVE_MESSAGE_UPDATE=false
DATABASE_SAVE_DATA_CONTACTS=false
DATABASE_SAVE_DATA_CHATS=false
DATABASE_SAVE_DATA_LABELS=false
DATABASE_SAVE_DATA_HISTORIC=false
DATABASE_SAVE_IS_ON_WHATSAPP=false
DATABASE_DELETE_MESSAGE=true
CACHE_REDIS_ENABLED=true
CACHE_REDIS_URI=redis://evo-redis:6379/6
CACHE_REDIS_PREFIX_KEY=evolution
CACHE_REDIS_SAVE_INSTANCES=false
CACHE_LOCAL_ENABLED=false
AUTHENTICATION_API_KEY=<API_KEY>
LANGUAGE=en
POSTGRES_DB=evolution_db
POSTGRES_USER=evouser
POSTGRES_PASSWORD=<DB_PASSWORD>
# Optional: pin another image tag. Without this line the compose file uses v2.3.7.
# EVOLUTION_TAG=v2.3.7הפעלה ובדיקת גרסה
לפני שפותחים את השירות לאינטרנט, מוכיחים על הכתובת המקומית שהוא עלה בגרסה שבחרתם ושהוא דורש מפתח.
בבדיקה שלנו בסביבת הדגמה על גרסה 2.3.7 בקשת GET / בלי מפתח החזירה "status":200, את ההודעה Welcome to the Evolution API, it is working! ואת "version":"2.3.7". בקשה לא מאומתת ל־/instance/fetchInstances החזירה HTTP 401. הגרסה צריכה להתאים לגרסה היציבה שבחרתם, כאן 2.3.7 EvolutionAPI/evolution-api GitHub releases, accessed October 2026 (נפתח בחלון חדש).
פרט מבלבל: כתובת ה־manager בתשובה נבנית מהכתובת שפניתם אליה, ולכן בבדיקה המקומית היא הציגה 127.0.0.1:8080. לעומת זאת, השדה server_url בגוף ה־webhook נושא את הערך של SERVER_URL, כאן https://evo.example.com. זה לא סימן לתקלה בהגדרה.
- הריצו את בקשת הבדיקה מהשרת עצמו, על הכתובת המקומית.
- ודאו שהשדה
versionבתשובה זהה לתג שנעצתם. - שלחו בקשה ל־
/instance/fetchInstancesבלי מפתח, וודאו שמתקבלת שגיאת 401. - אם השירות לא עונה מיד, המתינו לסיום העלייה ובדקו את יומני הקונטיינר לפני שמשנים הגדרות.
- רשמו את הגרסה ואת התאריך במסמך התפעול של המערך.
curl -s http://127.0.0.1:8080/חשיפה בטוחה דרך HTTPS
ה־API קשור לכתובת המקומית, ולכן שרת הפוך מקבל את בקשות ה־HTTPS מבחוץ ומעביר אותן פנימה. בדוגמה Caddy רץ על השרת עצמו, לא בקונטיינר, ולכן היעד 127.0.0.1:8080 מגיע לפורט שפורסם. Caddy בתוך קונטיינר יצטרך במקום זה להצטרף לרשת של ה־Compose ולפנות לשם השירות.
התיעוד של Caddy להוראה reverse_proxy (נפתח בחלון חדש) מסביר את ההעברה, והתיעוד של Caddy על HTTPS אוטומטי (נפתח בחלון חדש) מסביר איך Caddy מנפיק תעודה. מה שבדקנו בפועל מוגבל: הקובץ שבדוגמה עבר בדיקת תחביר בלבד.
בדיקת הקשירה המקומית:
ודאו קודם שאין דרך אחרת פנימה. הפלט של docker compose ps צריך להציג את ה־API בלבד, עם 127.0.0.1:8080, וזה מה שראינו בבדיקה שלנו בסביבת הדגמה. אם העתקתם חלקים מהקובץ של הפרויקט, חפשו את מיפוי ה־manager "3000:80", שמפרסם את הפורט על כל הממשקים EvolutionAPI/evolution-api docker-compose.yaml, accessed October 2026 (נפתח בחלון חדש).
העברת HTTPS:
ה־Caddyfile כולל רק את שם המתחם ואת ההעברה לכתובת המקומית. בבדיקה שלנו בסביבת הדגמה caddy validate של Caddy v2.11.4 קיבל את הקובץ evo.example.com { reverse_proxy 127.0.0.1:8080 }. זו הייתה בדיקת תחביר בלבד, בלי תעודה חיה. הפניית DNS, הנפקת תעודה ובקשה שעוברת דרך הפרוקסי לא נבדקו על ידינו, ולכן הן בדיקות קבלה שלכם.
בדיקה שאין פורט ציבורי עוקף:
Docker מוסיף כללי סינון משלו לפורטים שמפורסמים, והם יכולים לעקוף את חומת האש של השרת, כפי שהתיעוד של Docker על חומות אש (נפתח בחלון חדש) מסביר, ולכן סטטוס נקי של UFW לא מוכיח דבר. ההוכחה היא בדיקה מבחוץ: ממחשב אחר, פנייה ישירה לכתובת הציבורית של השרת בפורט 8080 חייבת להיכשל, ופנייה דרך הדומיין ב־HTTPS חייבת לעבוד עם תעודה תקפה.
- הפנו את תת הדומיין לכתובת הציבורית של השרת אצל ספק ה־DNS שלכם.
- שמרו את ה־Caddyfile מהדוגמה עם שם המתחם שלכם במקום
evo.example.com. - הריצו
caddy validateעל הקובץ לפני טעינה. - טענו את ההגדרה מחדש ב־Caddy והמתינו להנפקת התעודה.
- ממחשב חיצוני, פנו לדומיין ב־HTTPS וודאו שהתעודה תקפה.
- ממחשב חיצוני, נסו להתחבר לכתובת הציבורית בפורט 8080, וודאו שהניסיון נכשל.
- דרך הדומיין, שלחו בקשה ל־
/instance/fetchInstancesבלי מפתח וודאו שמתקבלת 401.
evo.example.com {
reverse_proxy 127.0.0.1:8080
}יצירת מופע וסריקת QR
מופע הוא קו WhatsApp אחד בתוך Evolution. יוצרים אותו בבקשת POST /instance/create עם המפתח הגלובלי ועם "integration":"WHATSAPP-BAILEYS". בבדיקה שלנו בסביבת הדגמה הבקשה החזירה QR, כלומר מחרוזת קוד ותמונת PNG בקידוד base64, עם count של 1 ו־pairingCode ריק, בלי שחובר מספר.
תשובת היצירה רגישה: הטוקן של המופע נמצא בשדה hash, ויש בה גם את מטען ה־QR, ולכן אל תדביקו אותה בצ׳אט או ביומן משותף. שם המופע הוא מזהה קבוע ב־webhooks ובמסד, ולכן בוחרים אותו כמו slug.
את ה־QR סורקים מהקוד החי על מסך ה־Manager, ולא מתמונה שמורה. לפי ההפעלה שלנו, נתון תפעולי שלא נמדד מחדש, הקוד מתחלף בערך כל 20 עד 40 שניות, ו־QRCODE_LIMIT=30 החלפות מסיימות את הניסיון, כך שתמונה שמורה מתיישנת ומסתובבת במקומות שאסור לה להיות בהם. בקשת connect מחזירה QR חדש בכל קריאה. Evolution מציע גם מסלול של קוד צימוד במקום QR, שלא בדקנו.
בסביבת ההדגמה הוכחנו יצירת מופע וקבלת QR, אבל לא השלמנו קישור של מספר אמיתי. גם מצב מופע שלא קושר לא יציב: מופע חדש החזיר close בהרצה אחת ו־connecting בהרצה אחרת. המצב היחיד שמעיד על חיבור הוא open.
אחרי הסריקה בודקים שני דברים, ושניהם חובה לפני כל שליחה: שהמצב בנתיב /instance/connectionState/<name> הוא open, ושמספר הבעלים של המופע הוא המספר שתכננתם. מצב open לבדו לא אומר איזה טלפון התחבר. כתובת ה־Manager נבנית מהכתובת שפניתם אליה, ולכן פתחו אותו דרך הדומיין המאובטח.
- צרו את המופע עם המפתח הגלובלי ושם קבוע שבחרתם מראש.
- שמרו את הטוקן מהשדה
hashבמקום מאובטח, ומחקו את התשובה המלאה מהמסוף. - היכנסו ל־Manager דרך הדומיין המאובטח והתחברו עם כתובת השרת והמפתח.
- פתחו את חלון ה־QR של המופע כשהטלפון של הבעלים כבר בידיים שלהם.
- בטלפון, פתחו את מסך המכשירים המקושרים וסרקו את הקוד החי מהמסך.
- אם הקוד פג, בקשו קוד חדש מה־Manager.
- בדקו שהמצב
openושמספר הבעלים של המופע הוא המספר הצפוי, לפני כל שליחה.
# יצירת מופע
curl -s -X POST http://127.0.0.1:8080/instance/create \
-H "apikey: <API_KEY>" -H "Content-Type: application/json" \
-d '{"instanceName":"demo-line","integration":"WHATSAPP-BAILEYS","qrcode":true}'
# repeat with "demo-line-2" for the second line
# בדיקת מצב
curl -s http://127.0.0.1:8080/instance/connectionState/demo-line -H "apikey: <API_KEY>"
curl -s http://127.0.0.1:8080/instance/connect/demo-line -H "apikey: <API_KEY>"


חיבור Webhook לכל מופע
Webhook הוא הדרך של Evolution להודיע למערכת אחרת, למשל n8n שרץ על השרת שלכם, שקרה משהו. בטייגרמדיה אנחנו מגדירים webhook לכל מופע ונמנעים ממשתנה ה־webhook הגלובלי, כי הגלובלי שולח את האירועים של כל המופעים לכתובת אחת.
הבקשה ל־/webhook/set/<name> עטופה באובייקט webhook, וכותרת ההרשאה נכנסת לשדה headers. בבדיקה שלנו בסביבת הדגמה התקבל משלוח אמיתי של CONNECTION_UPDATE, שמוצג בחלק השני של הדוגמה, עם האירועים MESSAGES_UPSERT, CONNECTION_UPDATE ו־SEND_MESSAGE בלבד.
QRCODE_UPDATED הושמט בכוונה: אם הוא ברשימה, מטען ה־QR יוצא מהשרת ונשמר בהיסטוריה של היעד.
הממצא החשוב בפרק: גוף ה־webhook מכיל שדה apikey, ובמשלוח שנקלט הוא היה שווה לטוקן של המופע, לא למפתח הגלובלי. כל יעד webhook מחזיק בפועל את הטוקן של המופע. לכן היעד חייב להיות מוגן: HTTPS, בדיקה של כותרת ההרשאה לפני עיבוד, והיסטוריית הרצות מוגבלת.
מיקום היעד תלוי בטופולוגיה. בבדיקה שלנו בסביבת הדגמה מאזין על השרת המארח, גם על 127.0.0.1, לא היה נגיש מקונטיינר ה־API, ומאזין בקונטיינר על אותה רשת Compose קיבל את הבקשה. בדיון ב־GitHub הוצע להחליף את host.docker.internal בשם השירות של n8n ב־Compose ולוודא ששני הקונטיינרים חולקים רשת, אבל המדווח לא אישר שזה פתר את הבעיה github.com, accessed October 2026 (נפתח בחלון חדש). יעד ציבורי ב־HTTPS לא מושפע מזה.
מה לא נבדק: MESSAGES_UPSERT ו־SEND_MESSAGE דורשים מספר מקושר, ולכן לא ראינו אותם מגיעים. הדיון ב־GitHub נסגר כהושלם ב־2025-12-01, אחרי שהמדווח הפעיל webhook ושלח הודעה, אבל משתמש אחר דיווח על אותה התנהגות במופע אחד בלבד בלי webhook מוגדר github.com, accessed October 2026 (נפתח בחלון חדש). לכן בודקים כל אירוע בנפרד אחרי הקישור.
- צרו סוד חדש ליעד ה־webhook של המופע, נפרד מהמפתח הגלובלי ומהטוקן.
- הגדירו ביעד בדיקה של כותרת
Authorizationלפני כל עיבוד של הגוף. - שלחו את בקשת ה־set עם כתובת היעד, הכותרת ורשימת אירועים בלי
QRCODE_UPDATED. - קראו את ההגדרה בחזרה עם בקשת ה־find, וודאו שהערכים זהים.
- הפעילו מחדש את המופע וודאו שאירוע
CONNECTION_UPDATEהגיע ליעד. - הגבילו ביעד את שמירת היסטוריית ההרצות, כי הגוף כולל את הטוקן של המופע.
# הגדרת webhook
curl -s -X POST http://127.0.0.1:8080/webhook/set/demo-line \
-H "apikey: <API_KEY>" -H "Content-Type: application/json" \
-d '{"webhook":{"enabled":true,"url":"https://n8n.example.com/webhook/evolution",
"headers":{"Authorization":"Bearer <WEBHOOK_SECRET>"},
"byEvents":false,"base64":false,
"events":["MESSAGES_UPSERT","CONNECTION_UPDATE","SEND_MESSAGE"]}}'
curl -s http://127.0.0.1:8080/webhook/find/demo-line -H "apikey: <API_KEY>"
# בקשה שנקלטה בפועל (פלט, לא פקודה)
POST /hook
Content-Type: application/json
Authorization: Bearer <WEBHOOK_SECRET>
User-Agent: axios/1.13.2
{
"event": "connection.update",
"instance": "demo-line",
"data": {
"instance": "demo-line",
"state": "connecting",
"statusReason": 200
},
"destination": "http://evoguide3_hook:9000/hook",
"date_time": "2026-10-12T12:12:33.623Z",
"server_url": "https://evo.example.com",
"apikey": "<INSTANCE_TOKEN>"
}
בדיקות קבלה מקצה לקצה
בדיקות הקבלה רצות בסדר קבוע: קודם הטלפון הנכון, אחר כך הרשאות ועמידות, ורק בסוף שליחה. שליחה לפני בדיקת המספר יכולה לצאת ממספר שמישהו אחר צימד.
הבדיקה הראשונה, לפני כל שליחה: המצב open ומספר הבעלים של המופע הוא המספר הצפוי. השנייה היא היקף המפתחות. בבדיקה שלנו בסביבת הדגמה על 2.3.7 המפתח הגלובלי הציג ב־fetchInstances את 2 מתוך 2 המופעים, וטוקן של מופע הציג רק את המופע שלו. אותו טוקן קיבל 401 על connectionState ועל webhook/find של המופע האחר ועל POST /instance/create, ובקשה בלי מפתח קיבלה 401.
לכן מי שמשלב מבחוץ מקבל רק את הטוקן של המופע שלו, והמפתח הגלובלי, שנותן גישה לכל המופעים EvolutionAPI/evolution-api .env.example, accessed October 2026 (נפתח בחלון חדש), נשאר אצל הבעלים. בדקנו רק את הנתיבים שצוינו. נתיבי הודעות כמו sendText לא נבדקו, כי לא חובר מספר.
השלישית היא עמידות: בבדיקה שלנו בסביבת הדגמה, אחרי docker compose restart של כל המערך, fetchInstances עדיין הציג את שני המופעים כ־30 שניות אחר כך. בבדיקה הזו ספירות ההודעות היו ריקות כי לא חובר מספר ולא נשלחו הודעות, לא בגלל הדגלים. לפי הסכמה, המסד כולל טבלאות Message, Contact ו־Chat; כתיבה אליהן בתעבורה אמיתית לא נבדקה.
מה שלא הוכח, ואתם בודקים אחרי קישור מספר: הודעה נכנסת, הודעה יוצאת, הגעה של MESSAGES_UPSERT ל־webhook והגעה של SEND_MESSAGE ל־webhook. שליחת הבדיקה הולכת רק למספר שנתן הסכמה, ולא לרשימה.
- בדקו שהמצב
openושמספר הבעלים של המופע הוא המספר הצפוי, ועצרו אם לא. - הריצו את בדיקות היקף המפתחות מהדוגמה, וודאו שכל תוצאה תואמת לציפייה.
- הפעילו מחדש את המערך והריצו את רשימת המופעים שוב אחרי שהשירות עלה.
- שלחו הודעה מטלפון שהסכים לבדיקה לקו המחובר, וודאו ש־
MESSAGES_UPSERTהגיע ליעד. - שלחו תשובה אחת לאותו מספר בלבד, וודאו ש־
SEND_MESSAGEהגיע ליעד ושההודעה הופיעה בטלפון. - תעדו כל בדיקה עם תאריך ותוצאה, וסמנו כפתוחה כל בדיקה שלא עברה.
# היקף ההרשאות
# K = global key, T1 = token of demo-line (the "token" field of fetchInstances, also "hash" in the create response)
U=http://127.0.0.1:8080
curl -s -w '\nHTTP %{http_code}\n' $U/instance/fetchInstances -H "apikey: $K" # 1 global key
curl -s -w '\nHTTP %{http_code}\n' $U/instance/fetchInstances -H "apikey: $T1" # 2 instance token
curl -s -w '\nHTTP %{http_code}\n' $U/instance/connectionState/demo-line -H "apikey: $T1" # 3 own instance
curl -s -w '\nHTTP %{http_code}\n' $U/instance/connectionState/demo-line-2 -H "apikey: $T1" # 4 other instance
curl -s -w '\nHTTP %{http_code}\n' -X POST $U/instance/create -H "apikey: $T1" -H 'Content-Type: application/json' -d '{"instanceName":"should-fail"}' # 5
curl -s -w '\nHTTP %{http_code}\n' $U/instance/fetchInstances # 6 no key
curl -s -o /dev/null -w 'HTTP %{http_code}\n' $U/webhook/find/demo-line-2 -H "apikey: $T1" # 7 other instance
curl -s -o /dev/null -w 'HTTP %{http_code}\n' $U/webhook/find/demo-line -H "apikey: $T1" # 8 own instance
# רשימת המופעים
curl -s http://127.0.0.1:8080/instance/fetchInstances -H "apikey: <API_KEY>"
# הפעלה מחדש והישרדות
docker compose restart
sleep 30
curl -s http://127.0.0.1:8080/instance/fetchInstances -H "apikey: <API_KEY>"
צמצום שמירת מידע ובדיקת התוצאה
הפרק הופך את הגדרות השמירה מהבטחה לבדיקה במסד שלכם. הספירה כאן בודקת רק את טבלת Message, ולא מטמון, יומנים, מדיה, גיבויים או יעדי webhook.
הפרידו בין שלוש פעולות: כיבוי דגל עוצר לכל היותר כתיבה עתידית, מחיקה של מה שכבר נשמר היא פעולה נפרדת שדורשת גיבוי, ותקופת שמירה היא מדיניות של כמה זמן מותר למידע להישאר.
מה נשמר כברירת מחדל:
כברירת מחדל כל דגלי השמירה דולקים, כולל הודעות חדשות, עדכוני הודעות, אנשי קשר, שיחות, תוויות והיסטוריה EvolutionAPI/evolution-api .env.example, accessed October 2026 (נפתח בחלון חדש). בסכמת 2.3.7 קיימת בטבלת Message עמודת message מסוג jsonb, המיועדת לתוכן ההודעה. לא בדקנו כתיבה אליה בתעבורה אמיתית. לצידה יש בטבלה עמודות כמו key, pushName, messageType ו־messageTimestamp.
התצורה של Senate מפעילה כברירת מחדל שמירה של שיחות, אנשי קשר, היסטוריה, מופעים, תוויות, הודעות חדשות ועדכוני הודעות, ושומרת נתוני בדיקת מספרים ב־WhatsApp ל־30 יום senate.sh, accessed October 2026 (נפתח בחלון חדש). נכון ל־12 באוקטובר 2026 כל דגלי השמירה דולקים בהתקנה שלנו.
איך לבצע ניסוי מבוקר:
ניסוי מבוקר משנה דבר אחד בכל פעם: סופרים את השורות בטבלת Message לכל מופע, שולחים הודעת בדיקה ממספר שהסכים, וסופרים שוב. אחר כך מכבים את הדגל, מפעילים מחדש את ה־API, שולחים הודעה נוספת וסופרים פעם שלישית. אם הספירה עלתה אחרי הכיבוי, ההגדרה לא עשתה מה שציפיתם.
מה לא להסיק מתוצאה ריקה:
ספירה ריקה לא מוכיחה שאין תוכן. בסביבת ההדגמה הספירה הייתה ריקה כי לא חובר מספר, והשפעת הדגלים על מספר השורות לא נבדקה בתעבורה אמיתית. גם בקו פעיל, ספירה ריקה ב־Message לא אומרת דבר על טבלת Media, על המטמון ב־Redis, על יומנים, על גיבויים ישנים או על ההיסטוריה ביעד ה־webhook.
- גבו את המערך לפני כל שינוי בדגלים.
- הריצו את שאילתת הספירה ורשמו את התוצאה לכל מופע.
- שלחו הודעת בדיקה אחת ממספר שהסכים, והריצו את הספירה שוב.
- שנו את הדגל ב־
.envוהפעילו מחדש רק את שירות ה־API. - שלחו הודעת בדיקה נוספת והריצו את הספירה פעם שלישית.
- בדקו בנפרד את טבלת
Media, את יעד ה־webhook ואת הגיבויים, ותעדו מה מצאתם. - החליטו בנפרד אם למחוק הודעות שכבר נשמרו, ובצעו זאת רק אחרי גיבוי מוצפן.
docker compose exec -T evo-postgres psql -U evouser -d evolution_db -c \
'SELECT i.name, count(m.id) AS messages FROM evolution_api."Instance" i LEFT JOIN evolution_api."Message" m ON m."instanceId" = i.id GROUP BY i.name ORDER BY i.name;'תקלות בקוד QR, בחיבור וברשת
הטבלה בסוף הפרק מסדרת תקלות לפי תסמין, מה בודקים ומה מוכיח את הסיבה, ומפרידה בין מה שראינו בעצמנו לבין מה שאחרים דיווחו.
מה לבדוק לפני הפעלה מחדש:
בודקים קודם את מצב החיבור ואת סיבת הניתוק ביומן. ניתוק 401 עם device_removed אומר שהטלפון ניתק את המכשיר המקושר, ורק סריקת QR חדשה על ידי הבעלים מתקנת את זה. הפעלה מחדש של הקונטיינר לא עוזרת. ניתוק 440 מסוג replaced אומר שאותו מספר נפתח ב־WhatsApp Web אחר או בשרת API אחר: סוגרים את החיבור השני ומתחברים מחדש. בניתוקים עם הקודים 408 ו־515, ניתוק רשת או בקשת הפעלה מחדש, Evolution מנסה להתחבר מחדש בעצמו.
מתי נדרש QR חדש:
QR חדש נדרש כשהקוד הקודם פג, כשהטלפון ניתק את המכשיר, או כשהמופע עוד לא הגיע למצב open. אחרי שמספר נרשם במכשיר חדש, WhatsApp עלולה לסרב לקישור מכשירים חדשים לתקופה מסוימת, והטלפון מציג שלא ניתן לקשר מכשירים כרגע. שום דבר בצד השרת לא מקצר את ההמתנה הזו.
מתי התקלה היא ברשת Docker:
תקלה ברשת מופיעה כשהקו מחובר אבל משהו בין הקונטיינרים לא עובר. מפעיל YunoHost דיווח על יומנים מוצפים בהודעות ניתוק של Redis, והתצורה שהוצעה שם השתמשה ב־CACHE_REDIS_URI=redis://redis:6379 ולא במשתני מארח ופורט נפרדים community.n8n.io, accessed October 2026 (נפתח בחלון חדש). באותו דיון הועלתה השערה שטעינה מחדש של חומת האש מחקה את שרשראות iptables ש־Docker מנהל ושברה ניתוב בין קונטיינרים community.n8n.io, accessed October 2026 (נפתח בחלון חדש). הסיבה לא אומתה, והתיקון שהכותב ניסה היה פנייה לכתובת מקומית והפעלה מחדש של חומת האש ושל Docker. זה כיוון לבדיקה של מפעיל אחד, לא אבחון שלנו.
| תסמין | מה לבדוק קודם | מה מוכיח את הסיבה | מקור |
|---|---|---|---|
| ניתוק 401 עם device_removed | רשימת המכשירים המקושרים בטלפון | המכשיר לא מופיע עוד בטלפון | ניסיון שלנו |
| ניתוק 440 מסוג replaced | חיבור אחר של אותו מספר ב־Web או ב־API | הניתוק נפסק אחרי סגירת החיבור השני | ניסיון שלנו |
| הטלפון מסרב לקשר מכשיר חדש | אם המספר נרשם לאחרונה במכשיר חדש | ההודעה בטלפון על חסימת קישור זמנית | ניסיון שלנו |
| יומנים מוצפים בניתוקי Redis | אם חומת האש נטענה מחדש לפני הניתוקים | לא אומת, השערה מדיון אחד | דיווח של מפעיל YunoHost |
| ה־webhook מחזיר 404 או לא מגיע | הגרסה שרצה בפועל וכתובת היעד | בדיון הוצעו שם שירות ורשת משותפת, בלי אישור שזה פתר | דיון ב־GitHub שנסגר |
| רק מופע אחד מתנהג כך בלי webhook | הגדרות המופע מול מופע תקין | לא נמצא הסבר בדיון | דיון ב־GitHub שנסגר |
גיבוי ושחזור שאפשר להוכיח
גיבוי שלא שוחזר הוא הנחה. הגיבוי כאן כולל את כל מה שצריך כדי להחזיר את המערך: dump של PostgreSQL, ארכיון של כרך המופעים, קובץ ה־Compose וקובץ ה־.env, הכול בארכיון אחד שמוצפן ב־gpg עם AES256. ההצפנה לא אופציונלית: כשדגלי השמירה דולקים, ה־dump מכיל תוכן הודעות, ו־.env מכיל את המפתח הגלובלי ואת סיסמת המסד.
הסקריפט עוצר את evo-api בזמן ה־dump והעתקת הכרך, כדי ששני העותקים יתארו אותו רגע, ומפעיל אותו מחדש בסוף, גם אחרי שגיאה. הוא עובד בתיקייה פרטית זמנית שנמחקת ביציאה, עוצר בכל כשל, ובודק כל רכיב לפני ההצפנה. בבדיקה שלנו בסביבת הדגמה הארכיון נשמר בהרשאות 600, וכל ההרצה ארכה כ־2.4 שניות על מערך הדגמה כמעט ריק. בקשה ל־API 3 שניות אחרי ההפעלה עדיין נכשלה כי השירות עוד עלה. במסד גדול העצירה ארוכה יותר, ולכן מריצים בשעה שקטה.
בהרצה אחרת בבדיקה שלנו בסביבת הדגמה הארכיון המוצפן, עם ה־dump, ארכיון הכרך, קובץ ה־Compose וקובץ ה־.env, שקל 20,496 בתים, ושחזור שלו למסד בדיקה נתן ספירות תואמות. בהתקנת הייצור שלנו הגיבוי המוצפן עולה לאחסון אובייקטים, ואז יורד, מפוענח ונבדק לפני שסימן ההצלחה מתעדכן, ובדיקת שחזור טענה את ה־dump, 37 טבלאות, לקונטיינר זמני בלי רשת.
- צרו קובץ סיסמה להצפנה בהרשאות 600, ושמרו עותק שלו מחוץ לשרת.
- שמרו את הסקריפט בשם
backup.shבתיקיית המערך, לצדdocker-compose.ymlו־.env. - הריצו אותו בשעה שקטה, כי ה־API מושהה בזמן ההרצה.
- ודאו שהסקריפט הדפיס את רשימת הרכיבים ואת הקובץ המוצפן שנוצר.
- העתיקו את הקובץ המוצפן לאחסון מחוץ לשרת, בנפרד מהסיסמה.
#!/usr/bin/env bash
# Run from the folder that holds docker-compose.yml and .env
set -euo pipefail
umask 077
cd "$(dirname "$0")"
set -a; . ./.env; set +a
PASSFILE="${PASSFILE:-$HOME/.evolution-backup.pass}" # chmod 600, keep a copy OFF this server
OUTDIR="${OUTDIR:-$HOME/evolution-backups}"
STAMP="$(date +%Y%m%d-%H%M%S)"
mkdir -p "$OUTDIR"
WORK="$(mktemp -d)"
# on exit: delete the work folder and ALWAYS start the API again, also after an error
trap 'rm -rf "$WORK"; docker compose start evo-api >/dev/null' EXIT
# 1. stop the API so the dump and the volume copy describe the same moment
docker compose stop evo-api
# 2. database (custom format) and the instances volume (read through a throwaway alpine container)
docker compose exec -T evo-postgres pg_dump -U "$POSTGRES_USER" -Fc "$POSTGRES_DB" > "$WORK/db.dump"
docker run --rm --volumes-from "$(docker compose ps -aq evo-api)":ro -v "$WORK":/out alpine:3 \
tar czf /out/instances.tgz -C /evolution/instances .
cp docker-compose.yml .env "$WORK"/
# 3. check every piece before trusting it
for f in db.dump instances.tgz docker-compose.yml .env; do
[ -s "$WORK/$f" ] || { echo "MISSING OR EMPTY: $f" >&2; exit 1; }
done
tar tzf "$WORK/instances.tgz" >/dev/null
docker compose exec -T evo-postgres pg_restore -l < "$WORK/db.dump" >/dev/null
# 4. one tar, checked, then encrypted with AES-256 (written to a temp name, renamed only when complete)
tar cf "$WORK/bundle.tar" -C "$WORK" db.dump instances.tgz docker-compose.yml .env
tar tf "$WORK/bundle.tar" | sort | tr '\n' ' '; echo
gpg --symmetric --cipher-algo AES256 --batch --yes --pinentry-mode loopback \
--passphrase-file "$PASSFILE" -o "$OUTDIR/.partial-$STAMP" "$WORK/bundle.tar"
mv "$OUTDIR/.partial-$STAMP" "$OUTDIR/evolution-$STAMP.tar.gpg"
ls -l "$OUTDIR/evolution-$STAMP.tar.gpg"
# the trap now removes $WORK and starts the APIבדיקת שחזור למסד זמני
ההוכחה שהגיבוי עובד היא שחזור שלו, בלי לגעת במערכת החיה. הסקריפט מפענח את הארכיון לתיקייה פרטית חדשה, בודק שכל רכיב קיים ולא ריק ושה־tar וה־dump נקראים, משחזר למסד בדיקה בשם restore_test ומשווה ספירות מול המסד החי. ביציאה הוא מוחק את התיקייה המפוענחת ואת מסד הבדיקה. שימו לב: הסקריפט מוחק ויוצר מחדש מסד בשם restore_test, ולכן אם כבר יש אצלכם מסד בשם הזה, שנו את השם בסקריפט לפני ההרצה.
בבדיקה שלנו בסביבת הדגמה הספירות תאמו: Instance 2 מול 2, Webhook 1 מול 1, Setting 2 מול 2, ו־37 מול 37 טבלאות בסכמה evolution_api. המסד הזמני נמחק בסוף, וה־API החי לא נעצר. מכיוון שהמסד החי ממשיך לרוץ, ספירות יכולות להיות שונות אם נכתבו נתונים אחרי הגיבוי.
גבול ההוכחה ברור: זו סביבת הדגמה בלי מספר מקושר. שחזור מלא של מספר מקושר, כלומר שהקו חוזר ל־open בלי סריקה חדשה, לא נבדק.
- שמרו את הסקריפט בשם
restore-test.shבתיקיית המערך. - הריצו אותו עם הנתיב לקובץ הגיבוי המוצפן העדכני.
- ודאו שהופיעו שורות האישור עבור
instances.tgzועבורdb.dump. - השוו את ספירות Instance, Webhook, Setting והטבלאות בין המסד החי למסד הבדיקה.
- תעדו את התאריך ואת התוצאה, וחזרו על הבדיקה אחרי כל שינוי בסקריפט הגיבוי.
#!/usr/bin/env bash
# Non-destructive: restores a backup into a scratch database and compares row counts. Usage: ./restore-test.sh <backup.tar.gpg>
set -euo pipefail
umask 077
cd "$(dirname "$0")"
set -a; . ./.env; set +a
BK="${1:?usage: ./restore-test.sh <backup.tar.gpg>}"
PASSFILE="${PASSFILE:-$HOME/.evolution-backup.pass}"
PSQL="docker compose exec -T evo-postgres"
WORK="$(mktemp -d)"
# on exit: delete the decrypted copy and drop the scratch database (the live API is never touched)
trap 'rm -rf "$WORK"; $PSQL dropdb -U "$POSTGRES_USER" --if-exists restore_test >/dev/null 2>&1 || true' EXIT
# 1. decrypt into a NEW folder
mkdir "$WORK/restore"
gpg --batch --pinentry-mode loopback --passphrase-file "$PASSFILE" -d "$BK" | tar x -C "$WORK/restore"
# 2. check the pieces
for f in db.dump instances.tgz docker-compose.yml .env; do
[ -s "$WORK/restore/$f" ] || { echo "MISSING OR EMPTY: $f" >&2; exit 1; }
done
tar tzf "$WORK/restore/instances.tgz" >/dev/null && echo "instances.tgz lists OK"
$PSQL pg_restore -l < "$WORK/restore/db.dump" >/dev/null && echo "db.dump lists OK"
# 3. restore into a scratch database and compare
$PSQL dropdb -U "$POSTGRES_USER" --if-exists restore_test
$PSQL createdb -U "$POSTGRES_USER" restore_test
$PSQL pg_restore -U "$POSTGRES_USER" -d restore_test --no-owner < "$WORK/restore/db.dump"
for db in "$POSTGRES_DB" restore_test; do
for t in Instance Webhook Setting; do
echo -n "$db $t: "; $PSQL psql -U "$POSTGRES_USER" -d "$db" -Atc "SELECT count(*) FROM evolution_api.\"$t\""
done
echo -n "$db tables in schema evolution_api: "; $PSQL psql -U "$POSTGRES_USER" -d "$db" -Atc "SELECT count(*) FROM information_schema.tables WHERE table_schema='evolution_api'"
doneשחזור במקום: הצעד ההרסני
שחזור במקום מחליף את המסד החי, את כרך המופעים, את .env ואת docker-compose.yml בתוכן הגיבוי. כל מה שנכתב אחרי הגיבוי נמחק. מריצים אותו רק אחרי שבדיקת השחזור למסד זמני עברה על אותו קובץ, ורק כשבאמת צריך.
הסקריפט מסרב לרוץ בלי I_UNDERSTAND=yes. קודם הוא מפענח לתיקייה פרטית חדשה ובודק כל רכיב, ורק אחרי הבדיקות עוצר את evo-api, שומר עותק של הקבצים הנוכחיים, משחזר קבצים, מסד וכרך, ואז מפעיל את ה־API ומדפיס את הגרסה. אם שלב נכשל אחרי העצירה, ה־API נשאר כבוי בכוונה. הדפסת הגרסה בסוף לא מכשילה את הסקריפט אם ה־API לא חזר תוך שתי דקות, ולכן בדקו בעצמכם את הגרסה שהודפסה ואת רשימת המופעים לפני שאתם מחשיבים את השחזור כגמור.
בבדיקה שלנו בסביבת הדגמה, אחרי שחזור כזה מופע שנוצר אחרי הגיבוי נעלם: 3 מופעים הפכו ל־2, והטוקן של המופע עדיין עבד אחר כך. Redis רץ עם appendonly yes ואינו חלק מהגיבוי או מהשחזור, ולכן אחרי השחזור הוא יכול להחזיק רשומות מטמון חדשות יותר מהגיבוי. Evolution משתמש בו כמטמון. את ההשפעה של זה לא בדקנו, וניקוי מסד ה־Redis הייעודי הוא החלטה שלכם, לא צעד שהרצנו.
- הריצו את בדיקת השחזור למסד זמני על אותו קובץ גיבוי, וודאו שעברה.
- הריצו גיבוי טרי של המצב הנוכחי, למקרה שתצטרכו לחזור אליו.
- שמרו את הסקריפט בשם
restore.shבתיקיית המערך. - הריצו אותו עם
I_UNDERSTAND=yesועם הנתיב לקובץ הגיבוי. - בדקו את הגרסה בתשובת
GET /, את רשימת המופעים ואת הגדרת ה־webhook. - בדקו שהמצב
openושמספר הבעלים הוא המספר הצפוי לפני כל שליחה.
#!/usr/bin/env bash
# DESTRUCTIVE: replaces the live database, the instances volume, .env and docker-compose.yml with the backup.
# Everything created after the backup is lost. Usage: I_UNDERSTAND=yes ./restore.sh <backup.tar.gpg>
set -euo pipefail
umask 077
cd "$(dirname "$0")"
BK="${1:?usage: I_UNDERSTAND=yes ./restore.sh <backup.tar.gpg>}"
[ "${I_UNDERSTAND:-}" = yes ] || { echo "refusing: set I_UNDERSTAND=yes" >&2; exit 1; }
PASSFILE="${PASSFILE:-$HOME/.evolution-backup.pass}"
STAMP="$(date +%Y%m%d-%H%M%S)"
WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT # the decrypted copy never outlives the script
STOPPED=no
trap '[ "$STOPPED" = yes ] && echo "FAILED after the stop: the API was left STOPPED on purpose, fix the error first" >&2 || echo "FAILED before any change: nothing was touched, the API is still running" >&2' ERR
PSQL="docker compose exec -T evo-postgres"
# 1. decrypt into a NEW folder and check everything BEFORE touching the live system
mkdir "$WORK/restore"
gpg --batch --pinentry-mode loopback --passphrase-file "$PASSFILE" -d "$BK" | tar x -C "$WORK/restore"
for f in db.dump instances.tgz docker-compose.yml .env; do
[ -s "$WORK/restore/$f" ] || { echo "MISSING OR EMPTY: $f" >&2; exit 1; }
done
tar tzf "$WORK/restore/instances.tgz" >/dev/null
$PSQL pg_restore -l < "$WORK/restore/db.dump" >/dev/null
echo "backup checked, tag inside the backup: $(grep '^EVOLUTION_TAG=' "$WORK/restore/.env" || echo 'not set (compose default)')"
# 2. from here on it is destructive: keep the API stopped until the database and the instances volume are restored (Redis is not part of the backup)
docker compose stop evo-api; STOPPED=yes
cp .env ".env.before-restore-$STAMP"; cp docker-compose.yml "docker-compose.yml.before-restore-$STAMP"
cp "$WORK/restore/.env" .env; cp "$WORK/restore/docker-compose.yml" docker-compose.yml # tag + compose now match the backup
set -a; . ./.env; set +a
$PSQL dropdb -U "$POSTGRES_USER" --force --if-exists "$POSTGRES_DB"
$PSQL createdb -U "$POSTGRES_USER" "$POSTGRES_DB"
$PSQL pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" --no-owner < "$WORK/restore/db.dump"
docker run --rm --volumes-from "$(docker compose ps -aq evo-api)" -v "$WORK/restore":/in:ro alpine:3 \
sh -c 'find /evolution/instances -mindepth 1 -delete && tar xzf /in/instances.tgz -C /evolution/instances && echo volume_restored'
# 3. only now bring the API back (pulls the tag from the backup's .env if it is not on this server)
docker compose up -d evo-api
for i in $(seq 1 60); do curl -fs http://127.0.0.1:8080/ >/dev/null 2>&1 && break; sleep 2; done
echo "version: $(curl -s http://127.0.0.1:8080/ | grep -o '"version":"[^"]*"')"עדכון, חזרה לאחור וניטור
עדכון של Evolution משנה גם את המסד, ולכן הוא מתחיל בגיבוי, משנה רק את שירות ה־API ונגמר בבדיקת הגרסה ומספר המיגרציות. נועצים תג ובודקים על המערכת החיה אחרי כל שדרוג.
בבדיקה שלנו בסביבת הדגמה עדכנו מ־v2.3.6 ל־v2.3.7 עם pull ויצירה מחדש של evo-api בלבד. המופע נשמר, והופעלה מיגרציה חדשה אחת, 20251122003044_add_chat_instance_remotejid_unique, כך שמספר המיגרציות עלה מ־56 ל־57. לפני שאתם עורכים את התג, זכרו שהתג היציב v2.3.7 נכתב ב־Docker Hub עם קידומת v Docker Hub evoapicloud/evolution-api tags, accessed October 2026 (נפתח בחלון חדש).
חזרה לאחור היא שחזור מגיבוי, לא החלפת תג. בבדיקה שלנו בסביבת הדגמה, החלפת התג בלבד חזרה ל־v2.3.6 הצליחה לעלות במערך כמעט ריק, אבל אז v2.3.6 רץ על סכמה חדשה יותר משלו. הרצף שעובד: עוצרים את ה־API, מחזירים את התג ואת הקבצים מהגיבוי, משחזרים מסד וכרך, ורק אז מפעילים. בדוגמה למטה ./backup.sh הוא סקריפט הגיבוי שנשמר בפרק הגיבוי, ו־./restore.sh הוא סקריפט השחזור במקום שנשמר בפרק על הצעד ההרסני, והוא מבצע את הרצף הזה בדיוק. הרצף הזה החזיר את גרסה 2.3.6 ואת 56 המיגרציות, ומופע שנוצר אחרי העדכון נעלם.
מלכודת שעלתה בבדיקה שלנו בסביבת הדגמה: משתנה במעטפת גובר על קובץ .env ב־Compose. אחרי set -a; . ./.env במעטפת, EVOLUTION_TAG נשאר מיוצא כ־v2.3.7, ולכן בדיקה ראשונה שקבעה v2.3.6 בקובץ עדיין הפעילה v2.3.7, עם 57 מיגרציות. חזרנו על הבדיקה מסביבה נקייה. הריצו את Compose ממעטפת שלא טענה את הקובץ.
ניטור מונע מקו מנותק לשבת בשקט. אצלנו בדיקה מתוזמנת קוראת את רשימת המופעים, מתריעה בחומרה הגבוהה ביותר אחרי כמה בדיקות רצופות בלי open או מיד אחרי 401, חוזרת על ההתראה כל עוד הקו מנותק ושולחת הודעת התאוששות. הוספנו אותה אחרי שקו ישב מנותק ימים בלי שאיש שם לב. אחרי צימוד מחדש בודקים שוב open ומספר בעלים צפוי לפני ששולחים. עוד על התראות ותחזוקה במדריך ניטור אוטומציות.
- בדקו בדף ה־releases אם יש גרסה יציבה חדשה, והתעלמו מתגי RC.
- הריצו גיבוי מלא ושמרו את שם הקובץ שנוצר.
- הוסיפו את השורה
EVOLUTION_TAG=ל־.envאם היא חסרה (בקובץ מהדוגמה היא הערה בלבד), וקבעו בה את התג היציב החדש בכתיב המדויק שמופיע ב־Docker Hub. - משכו את התמונה והפעילו מחדש את שירות
evo-apiבלבד. - בדקו את הגרסה בתשובת
GET /ואת מספר המיגרציות במסד. - בדקו שהמצב של כל מופע
openושמספר הבעלים הוא המספר הצפוי. - אם משהו נשבר, חזרו לאחור בשחזור מהגיבוי ולא בהחלפת תג בלבד.
# Before: .env has EVOLUTION_TAG=v2.3.6 and the API is running
./backup.sh # 1. back up first (pauses the API briefly)
BK=$(ls -t ~/evolution-backups/*.tar.gpg | head -1) # remember this file
grep -q '^EVOLUTION_TAG=' .env || echo 'EVOLUTION_TAG=v2.3.7' >> .env # 2. make sure the line exists (C2 ships it commented out)
sed -i 's/^EVOLUTION_TAG=.*/EVOLUTION_TAG=v2.3.7/' .env # and change the tag
docker compose pull evo-api && docker compose up -d evo-api # 3. only the API service
curl -s http://127.0.0.1:8080/ # 4. version
docker compose exec -T evo-postgres sh -c 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Atc "select count(*) from evolution_api._prisma_migrations"' # 5. migrations
# ROLLBACK (destructive: later data is lost). restore.sh does these in this order and starts the API LAST:
# docker compose stop evo-api (API stays stopped from here)
# put the .env and docker-compose.yml from the backup back (previous tag v2.3.6)
# drop + recreate + pg_restore the database; restore the instances volume
# docker compose up -d evo-api (only now, tag and data match the backup)
I_UNDERSTAND=yes ./restore.sh "$BK"
curl -s http://127.0.0.1:8080/
docker compose exec -T evo-postgres sh -c 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Atc "select count(*) from evolution_api._prisma_migrations"' # same checks as steps 4 and 5
# Do not run `set -a; . ./.env` in your own shell before docker compose: an exported EVOLUTION_TAG overrides the .env file.רשימת הבדיקות לפני שימוש אמיתי
הרשימה נועדה למעבר ממספר הדגמה לקו שאנשים אמיתיים כותבים אליו. כל שורה צריכה ראיה: פלט, תאריך או שם של מי שאישר, ושורה בלי ראיה נשארת פתוחה. הקו לא עובר לשימוש אמיתי לפני שהמספר המקושר, הודעה נכנסת, מסירה לנמען שהסכים והגעת אירועי ההודעות ל־webhook נבדקו.
שתי שורות נשכחות בקלות. הראשונה היא שמירת המידע: כל דגלי השמירה דולקים כברירת מחדל EvolutionAPI/evolution-api .env.example, accessed October 2026 (נפתח בחלון חדש), ובסכמה יש עמודה המיועדת לתוכן ההודעה בטבלת Message. השנייה היא הסיכון לחשבון, שלא נעלם גם כשהכול עובד WhatsApp Help Center, About unofficial apps, accessed October 2026 (נפתח בחלון חדש).
אם אתם רוצים עזרה בהחלטה אם Evolution, Cloud API או שילוב שלהם מתאים לתהליך שלכם, ואיך לחבר אותו לשאר האוטומציות, אפשר לבקש תוכנית יישום AI ואוטומציה. צוות אוטומציה כותב אותה אחרי בדיקה מקצועית, והיא ניתנת ללא עלות.
- השימוש תועד כקו אישי או קו בוט בהסכמה, והבעלים אישרו בכתב בידיעת סיכון החסימה.
- רק ה־API מפורסם, ורק על 127.0.0.1, ופלט
docker compose psנשמר. - בדיקה ממחשב חיצוני הראתה שפורט 8080 בכתובת הציבורית סגור.
- הדומיין עונה ב־HTTPS עם תעודה תקפה, ובקשה בלי מפתח מקבלת 401.
- המפתח הגלובלי חדש ואצל הבעלים בלבד, ומשלבים מבחוץ קיבלו רק טוקן מופע.
- תג Evolution נעוץ לגרסה יציבה, והגרסה בתשובת
GET /תואמת אותו. - המצב
openומספר הבעלים של המופע הוא המספר הצפוי, לפני כל שליחה. - ה־webhook מוגדר לכל מופע, בלי
QRCODE_UPDATED, ויעד ה־webhook בודק כותרת הרשאה. - הודעה נכנסת, הודעה יוצאת,
MESSAGES_UPSERTו־SEND_MESSAGEנבדקו מול מספר שהסכים. - דגלי השמירה הוחלטו ותועדו, וניסוי הספירה לפני ואחרי הורץ על הקו הזה.
- גיבוי מוצפן יצא מהשרת, ושחזור למסד זמני הראה ספירות תואמות.
- יש נוהל חזרה לאחור בשחזור, ולא בהחלפת תג בלבד.
- יש ניטור שמתריע כשהמצב לא
open, ומישהו מוגדר שמקבל את ההתראה.
שאלות נפוצות לפני שמחליטים
האם Evolution API הוא API רשמי
לא. Evolution API הוא שער קוד פתוח שמבוסס על Baileys ונרשם בחשבון כמכשיר מקושר, לא חלק מהפלטפורמה העסקית של Meta. הנחיות ההודעות של WhatsApp מונות כהתנהגות עוינת שימוש בלקוחות לא רשמיים, הודעות המוניות, הודעות אוטומטיות, חיוג אוטומטי או אוטומציה, כדי לפגוע ב־WhatsApp או במשתמשים שלה WhatsApp Messaging Guidelines, accessed October 2026 (נפתח בחלון חדש). השאלה אם מותר לכם להשתמש בו נענית כאן רק לפי תנאי השימוש של WhatsApp, לא כייעוץ משפטי: התנאים אוסרים הודעות המוניות ואוטומטיות לא מורשות WhatsApp Terms of Service, accessed October 2026 (נפתח בחלון חדש).
האם מפעיל השרת יכול לקרוא הודעות
כן, אם ההודעות נשמרות במסד או עוברות דרך השרת בזמן שהמפעיל מנטר את השרת. השרת הוא מכשיר מקושר שמפענח את ההודעות כדי לעבד אותן, וכברירת מחדל דגלי השמירה במסד דולקים EvolutionAPI/evolution-api .env.example, accessed October 2026 (נפתח בחלון חדש). נכון ל־12 באוקטובר 2026 כל דגלי השמירה דולקים בהתקנה שלנו. לכן שאלת הפרטיות היא מי מפעיל את השרת ומי ניגש לגיבויים.
האם ביטול משתני השמירה מבטיח שאין תוכן במסד
לא, זה לא הוכח. כיבוי הדגלים הוא הגדרת צמצום, ובסביבת ההדגמה לא חובר מספר, ולכן לא נמדדה השפעתם על מספר השורות בתעבורה אמיתית. הדרך לדעת היא ניסוי הספירה לפני ואחרי על הקו שלכם, יחד עם בדיקה של טבלת המדיה, היומנים, הגיבויים ויעד ה־webhook.
מתי לבחור Cloud API
כשמדובר בשירות לקוחות, בכמה נציגים, בשליחה יזומה או בהיקף גדול. במסלול הרשמי הודעה מחוץ לחלון של 24 שעות דורשת תבנית מאושרת, ואוטומציה בתוך החלון דורשת מסלול העברה ברור לאדם WhatsApp Business Messaging Policy, accessed October 2026 (נפתח בחלון חדש). ב־Evolution אין מנגנון כזה. אצלנו בטייגרמדיה תיבות שירות של לקוחות נשארות על Cloud API, ומספר מקושר משמש לקווים אישיים ולקווי בוט בלבד.
מה נמדד במנוחה ומה עדיין לא ידוע בעומס
נמדדה צריכת זיכרון במנוחה בלבד, בשתי מדידות נפרדות. לפי ההפעלה שלנו בהתקנת הייצור בספטמבר 2026, נתון תפעולי שלא נמדד מחדש: כ־266 MiB ל־API, כ־70 MiB ל־Postgres וכ־9 MiB ל־Redis. בבדיקה שלנו בסביבת הדגמה באוקטובר, עם שני מופעים שלא קושרו: כ־264 MiB לשלושת הקונטיינרים יחד. צריכה בעומס, גדילת המסד לכל הודעה, וקיבולת, לא נמדדו.
קבצים ותבניות לעבודה
שמרו עותק והתאימו את הדוגמאות למערכות ולתהליך שלכם.
מקורות להמשך בדיקה
- evolution-api docker-compose.yaml (main) (נפתח בחלון חדש)
- evolution-api .env.example (main) (נפתח בחלון חדש)
- evolution-api GitHub releases (repo now at github.com/evolution-foundation/evolution-api) (נפתח בחלון חדש)
- Docker Hub evoapicloud/evolution-api tags (נפתח בחלון חדש)
- WhatsApp Terms of Service (נפתח בחלון חדש)
- WhatsApp Messaging Guidelines (נפתח בחלון חדש)
- WhatsApp Business Messaging Policy (business.whatsapp.com/policy 301-redirects here) (נפתח בחלון חדש)
- About unofficial apps | WhatsApp Help Center (נפתח בחלון חדש)
- How to link a device with phone number | WhatsApp Help Center (and search excerpts of the linked-devices pages) (נפתח בחלון חדש)
- About end-to-end encryption | WhatsApp Help Center (נפתח בחלון חדש)
- Search result and description were available, but the fetched page exposed no transcript or comments. (נפתח בחלון חדש)
- Detailed deployment and VPS sales page. (נפתח בחלון חדש)
- Includes a complete sample Docker Compose configuration. (נפתח בחלון חדש)
- User request for an official one-click installer. (נפתח בחלון חדש)
- Spanish-language VPS installation tutorial. The fetched page exposed no transcript or comments. (נפתח בחלון חדש)
- Current repository returned by search for the Evolution API project. (נפתח בחלון חדש)
- Discussion of replacing paid WhatsApp services with a self-hosted stack. (נפתח בחלון חדש)
- Positions Evolution API as an open-source alternative to Meta's official API. (נפתח בחלון חדש)
- Firsthand send-text, webhook, Docker networking and instance-specific failure report. (נפתח בחלון חדש)
- Firsthand Redis disconnect and Docker firewall conflict report on a self-hosted VPS. (נפתח בחלון חדש)
- Operator describes splitting an overloaded WhatsApp CRM webhook into API, worker, PostgreSQL jobs and Redis. (נפתח בחלון חדש)
- Video specifically titled around Evolution API failing to generate a QR code. (נפתח בחלון חדש)
- Troubleshooting result about QR generation; its related search text also foregrounds ban avoidance. (נפתח בחלון חדש)
- Explicitly describes Evolution API as an unofficial client. (נפתח בחלון חדש)
- Commercial competitor claiming frequent disconnections, complex setup and high resource use. Treat as a lead, not independent proof. (נפתח בחלון חדש)
- Caddy reverse_proxy directive (נפתח בחלון חדש)
- PostgreSQL 15 pg_dump (נפתח בחלון חדש)
- Docker packet filtering and firewalls (נפתח בחלון חדש)
- Connect WhatsApp to n8n Using Evolution API (Full Setup Tutorial) (נפתח בחלון חדש)
- Caddy automatic HTTPS (נפתח בחלון חדש)
הדוגמאות במדריך נועדו להמחשה. פרטי מוצר ותנאי שימוש יש לבדוק במקור בעת היישום.
כלים ומונחים מהמדריך
מה הצעד הבא?
- n8n בשרת שלכם: מתחילים ב־Hostinger בלחיצה אחת
- איך מתכננים בוט WhatsApp עסקי שאפשר להפעיל, למדוד ולהעביר לנציג
- WhatsApp Cloud API: הקמה רשמית מהחיבור ועד הוכחת המסירה
- איך לבנות נוהל ניטור לאוטומציות שמזהה תקלות לפני שהלקוחות מזהים אותן
- וובהוק: פירוש ודוגמאות
צריכים עזרה ביישום?
בחרו את סוג התהליך כדי להשוות ספקים, או שלחו בקשת פרויקט עם ההקשר מהעמוד הזה. תוכלו לערוך את הפרטים לפני השליחה.
- ספקים לבוטים ואוטומציה בוואטסאפ
לקליטת פניות, מענה והעברה לנציג.



