SSD Nodes Learn Hosting plans →
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-10-21

התקנת Paperless-ngx על שרת VPS בעזרת Docker Compose

מדריך מעשי להקמת Paperless-ngx על שרת VPS. למדו איך להגדיר את Postgres, להגדיר את PAPERLESS_URL, לנהל את תיקיית ה-consume, להוסיף שפות OCR ולבצע גיבויים מאובטחים.

מה אתם בונים

התקנת Paperless-ngx על גבי VPS הופכת תיקיית מסמכים סרוקים לארכיון שניתן לבצע בו חיפוש. אתם מניחים קובץ PDF בתיקייה ייעודית, והשרת מריץ עליו OCR (זיהוי תווים אופטי), מחלץ את הטקסט, מנחש את התאריך ואת הגורם השולח, ומייעד את הקובץ למקומו. ההתקנה מבוססת על קובץ Docker Compose אחד עם ארבעה שירותים. כל מה שבא לאחר מכן הוא תצורה, ומדריך זה מקדיש לכך את רוב אורכו, שכן שם מתרחשות רוב התקלות בהתקנות. המערכת אינה ספריית תמונות: OCR וניחוש גורמים אינם מועילים לתיקיית תמונות חופשה בפורמט JPEG, לכן כדאי להעביר אותן ל-שרת תמונות ייעודי ולהשאיר את Paperless למסמכים. אותו קו מפריד חל גם על וידאו: מדף סרטים שהועתקו שייך לשרת מדיה, שבו משהו כמו ממשק Jellyfin המעוצב כחנות השכרת סרטים משנות ה-90 הופך את הגלישה לעיקר במקום החיפוש.

Paperless-ngx הוא ה-fork הקהילתי המתוחזק של פרויקט Paperless המקורי. הוא חופשי, מיועד לאירוח עצמי, ומאחסן את המסמכים שלכם כקבצים רגילים על הדיסק, כך שלעולם לא תיחסם הגישה שלכם לארכיון שלכם. הרצתו על גבי VPS במקום על שרת ביתי אומרת שהסריקות שלכם נגישות מכל מקום ללא צורך בפתיחת פורט בנתב הביתי, והוא משתלב היטב עם מופע Nextcloud פרטי עבור קבצים שאינם מסמכים. אותו היגיון תקף גם למחשב השולחני שאליו מחובר הסורק שלכם, שכן ממסר RustDesk משלכם על אותו ה-VPS מאפשר לכם לשלוט באותו מחשב מרחוק מבלי לפתוח פרצה בנתב.

מה ה-stack מריץ בפועל

קובץ ה-compose הרשמי מפעיל ארבע מכולות, והבנה של תפקיד כל אחת מהן הופכת את הלוגים לקריאים.

  • webserver: ה-image של paperless-ngx עצמו. הוא מריץ את ממשק ה-web, את ה-API, את ה-consumer שעוקב אחר תיקיית הקלט שלך, ואת ה-Celery task workers שמבצעים OCR.
  • db: PostgreSQL. הוא מאחסן מטא-דאטה, תגיות, אנשי קשר וטבלאות אינדקס לחיפוש טקסט מלא. הוא אינו מאחסן את קובצי ה-PDF שלך.
  • broker: Valkey, מאגר key-value תואם Redis. הוא משמש כתור משימות בין תהליך ה-web לבין ה-workers.
  • gotenberg ו-tika: אופציונליים, קיימים רק בגרסאות ה--tika של ה-compose. הם ממירים מסמכי Office (.docx, .xlsx, .odt) ל-PDF כדי ש-paperless יוכל לאנדקס אותם.

נכון לאוקטובר 2026, קובץ ה-postgres compose נועל את docker.io/library/postgres:18 ו-docker.io/valkey/valkey:9-alpine, ומושך את היישום מ-ghcr.io/paperless-ngx/paperless-ngx:latest.

דרישות קדם

  • שרת VPS מסוג KVM המריץ Ubuntu 24.04 עם הרשאות sudo, ועם Docker ופלאגין Compose מותקנים. אם נושא זה חדש עבורך, התחל ב-יסודות Docker Compose עבור VPS וחזור לכאן.
  • שם מתחם (domain name) עם רשומת A המצביעה על ה-VPS. ‏Paperless לא יאפשר התחברות ב-HTTPS לשם מארח שלא הוגדר עבורו, לכן נושא זה חשוב מוקדם משציפית.
  • זיכרון הוא המגבלה הממשית. PostgreSQL, ‏Valkey, שרת האינטרנט Granian ועובד OCR מסוג Tesseract כולם פועלים בו-זמנית בתוך 2 GB לשימוש קל. הקצה 4 GB אם בכוונתך לייבא ארכיון של מאות סריקות, כיוון שביצוע OCR על קובץ PDF גדול מרובה עמודים יוצר זינוק בזיכרון שעלול לגרום ל-kernel להרוג את התהליך (out-of-memory killer).
  • דיסק: הארכיון שלך נשמר פעמיים – הקובץ המקורי וקובץ PDF שעבר OCR – לכן תכנן נפח אחסון כפול בערך מגודל הסריקות שלך.

קבלת קובצי ה-compose הרשמיים

קיים מתקין אינטראקטיבי:

bash -c "$(curl --location --silent --show-error https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)"

הוא מציג שאלות וכותב עבורך את הקבצים. ביצוע הפעולה ידנית מסתכם בארבע פקודות ומבטיח שתדע היכן נמצא כל רכיב, וזהו המצב הרצוי בשרת שאתה מתחזק.

mkdir -p ~/paperless && cd ~/paperless
curl -fsSL -o docker-compose.yml https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/docker-compose.postgres.yml
curl -fsSL -o docker-compose.env https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/docker-compose.env
curl -fsSL -o .env https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/.env

הגרסאות השונות נמצאות באותה ספרייה: docker-compose.sqlite.yml, docker-compose.mariadb.yml, וגרסת -tika לכל אחת מהן. בחר ב-postgres עבור התקנה חדשה. SQLite מתאים לכמה מאות מסמכים, אך אינדקס החיפוש בטקסט מלא הופך לאיטי הרבה לפני ש-PostgreSQL מגיע למגבלותיו.

הקובץ .env מכיל שורה אחת, COMPOSE_PROJECT_NAME=paperless. שם זה הופך לקידומת של כל מכולה (container) וכל נפח אחסון (volume), לכן אל תמחק אותו ואז תתהה מדוע docker compose down -v אינו מוצא את הנתונים שלך.

הגדרת docker-compose.env לפני ההפעלה הראשונה

שתי הגדרות אינן אופציונליות. צרו את מפתח ה-secret באמצעות הפקודה המתועדת בפרויקט:

python3 -c "import secrets; print(secrets.token_urlsafe(64))"

לאחר מכן ערכו את docker-compose.env:

PAPERLESS_SECRET_KEY=<the long string you just generated>
PAPERLESS_URL=https://paperless.example.com
PAPERLESS_TIME_ZONE=Europe/Berlin
PAPERLESS_OCR_LANGUAGE=deu+eng
USERMAP_UID=1000
USERMAP_GID=1000

PAPERLESS_SECRET_KEY מגיע עם הערך המילולי change-me. הוא חותם על אסימוני (tokens) הפעלה, וגרסאות עדכניות מתייחסות למציין מיקום זה כלא מוגדר: paperless מסרב לעלות כאשר המפתח חסר, ריק או עדיין change-me, לכן ה-stack לא יעלה עד שתחליפו אותו. הגדירו אותו לפני ההפעלה הראשונה, שכן שינויו לאחר מכן ינתק את כל המשתמשים מהמערכת.

PAPERLESS_URL הוא ההגדרה שתחסוך לכם שעה של עבודה. Paperless הוא יישום Django, ו-Django בודק גם את ה-header מסוג Host וגם, בטופס ההתחברות, את ה-origin שהדפדפן מדווח עליו. הגדירו את PAPERLESS_URL והוא יוסיף את הכתובת שלכם ל-ALLOWED_HOSTS, ל-CORS_ALLOWED_HOSTS ול-CSRF_TRUSTED_ORIGINS באופן אוטומטי. אם תותירו אותו ריק ותפנו דומיין לשרת, דף ההתחברות עדיין ייטען, כיוון ש-PAPERLESS_ALLOWED_HOSTS מוגדר כברירת מחדל ל-*, אך שליחת הטופס ב-HTTPS תיכשל עם CSRF verification failed. Request aborted. כיוון שהדומיין שלכם אינו נחשב ל-origin מהימן. רשמו את הכתובת ללא לוכסן (slash) בסופה וללא נתיב.

USERMAP_UID ו-USERMAP_GID מגדירים את המשתמש שתחתיו המכולה (container) רצה. התאימו אותם לחשבון שלכם, כפי שניתן לבדוק באמצעות id -u ו-id -g. אם הם אינם תואמים, קבצים שתעתיקו לתיקיית ה-consume לא יהיו קריאים על ידי ה-consumer, והלוג יציג שגיאת הרשאות במקום לבצע ייבוא.

הפעלת ה-stack ויצירת המשתמש הראשון

docker compose pull
docker compose up -d
docker compose run --rm webserver createsuperuser
docker compose logs -f webserver

createsuperuser מבקש שם משתמש, כתובת דוא"ל וסיסמה. אין פרטי התחברות כברירת מחדל. אם תדלג על שלב זה, ממשק האינטרנט יבקש מכל מי שיפתח אותו ראשון ליצור את חשבון ה-superuser. מכיוון שפורט 8000 עדיין פתוח לאינטרנט, ייתכן שזה לא תהיה אתה, לכן צור את החשבון מה-shell באופן מיידי. המתן לשורת הלוג המציינת שהשרת מאזין בפורט 8000 לפני שתנסה לגשת דרך הדפדפן. ההפעלה הראשונה מבצעת גם הגירות (migrations) של מסד הנתונים, תהליך שנמשך דקה או שתיים.

בדוק את התקינות באופן מקומי לפני שאתה משלב שם מתחם:

curl -I http://127.0.0.1:8000

302 המפנה ל-/accounts/login/ מעיד על כך שה-stack תקין.

הגדרת HTTPS לפני השירות

קובץ ה-compose המקורי מפרסם את 8000:8000, שמתחבר לכל ממשקי הרשת. בשרת VPS ציבורי, הדבר חושף את כל ארכיון המסמכים שלכם ב-HTTP גלוי לכל מי שימצא את הכתובת. שנו את שורת הפורט כך שתתחבר ל-loopback בלבד:

    ports:
      - "127.0.0.1:8000:8000"

לאחר מכן, בצעו TLS termination ב-reverse proxy והעבירו את התעבורה ל-127.0.0.1:8000. אם זהו היישום היחיד בשרת, כל proxy עם לקוח ACME יתאים. אם אתם מריצים כמה מכולות מאחורי הגדרת תעודה אחת, עקבו אחר תבנית ה-reverse proxy של Traefik עבור יישומי Docker Compose מרובים וחברו את שירות ה-webserver לרשת ה-proxy ללא פרסום פורט כלל.

בכל proxy שתבחרו, בדיקת ה-origin של טופס ההתחברות היא המקום שבו הגדרות HTTPS נוטות להיכשל. Paperless מתעלם מ-X-Forwarded-Proto אלא אם תגדירו את PAPERLESS_PROXY_SSL_HEADER, שמושבת כברירת מחדל; לכן Django מתייחס לכל בקשה שעוברת דרך ה-proxy כ-HTTP רגיל, וה-origin של ה-https:// שהדפדפן שולח יעבור רק אם הוא מופיע ברשימת המהימנים. הגדרת PAPERLESS_URL לכתובת ה-https:// המדויקת שאתם מקלידים בדפדפן היא זו שמוסיפה אותו לרשימה זו. ללא הגדרה זו, תקבלו CSRF verification failed. Request aborted. בדף שנראה תקין.

בנוסף, העלו את מגבלת גודל ההעלאה ב-proxy. סריקה של 40 MB שעוברת דרך proxy המגביל גופים ל-1 MB תידחה עוד לפני ש-Paperless יראה אותה, והדפדפן ידווח על כשל העלאה כללי.

כיצד פועלת ספריית ה-consume

קובץ ה-compose מבצע bind-mount ל-./consume מתוך ספריית ה-compose אל תוך המכולה. כל קובץ שתניחו שם יעבור ייבוא ולאחר מכן יימחק מהתיקייה, כיוון שהקובץ נמצא כעת בתוך ה-volume של ה-media תחת הניהול של paperless.

cp ~/scan-2026-07-14.pdf ~/paperless/consume/
docker compose logs -f webserver

אתם אמורים לראות את ה-consumer מזהה את שם הקובץ, מריץ OCR, ומסיים עם שורה המדווחת שהמסמך נוסף. המחזור כולו אורך שניות בודדות עבור סריקה של עמוד אחד, ויכול להימשך דקה או יותר עבור מסמך ארוך.

שתי הגדרות משנות את האופן שבו קבצים נמצאים. PAPERLESS_CONSUMER_RECURSIVE=true גורמת ל-paperless לחפש בתיקיות משנה, ו-PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=true הופכת כל שם של תיקיית משנה לתגית (tag), כך שהנחת קובץ ב-consume/invoices/2026/ מתייגת אותו כ-invoices ו-2026. זוהי מערכת התיוק הזולה ביותר שתוכלו לבנות אי פעם.

זיהוי הוא החצי השני של התהליך. כברירת מחדל, PAPERLESS_CONSUMER_POLLING_INTERVAL מוגדר כ-0, מה שאומר ש-paperless משתמשת בהתראות מערכת קבצים מקוריות, שמופעלות באופן מיידי. התראות אלו אינן אמינות במערכת קבצים מרושתת. אם תיקיית ה-consume שלכם היא שיתוף NFS או SMB כדי שסורק רשת יוכל לכתוב אליה, קבצים עלולים להישאר שם ללא זיהוי. הפתרון הוא להגדיר את המרווח למספר חיובי של שניות, כך ש-paperless תסרוק את התיקייה במקום להסתמך על התראות.

שפות OCR ועלותן

PAPERLESS_OCR_LANGUAGE מקבל קוד Tesseract בן שלוש אותיות, כאשר ברירת המחדל היא eng. ניתן לשלב שפות באמצעות סימן פלוס, כפי שמופיע ב-deu+eng. במצב זה, Tesseract פועל עם כל השפות המפורטות על כל עמוד, כך שכל שפה נוספת מוסיפה זמן מעבד (CPU) לכל סריקה. בשרת VPS עם vCPU משותף, זהו ההבדל בין סריקה שמסתיימת תוך עשר שניות לבין כזו שנמשכת דקה שלמה. הגדירו רק את השפות שבהן המסמכים שלכם כתובים בפועל.

ה-image כולל את השפות אנגלית, גרמנית, איטלקית, ספרדית וצרפתית. עבור כל שפה אחרת, הוסיפו אותה ל-PAPERLESS_OCR_LANGUAGES כרשימה מופרדת ברווחים, לדוגמה PAPERLESS_OCR_LANGUAGES=tur ces, ובצעו הפעלה מחדש. המכולה מורידה את חבילות הנתונים של Tesseract בעת העלייה, לכן האתחול הראשון לאחר שינוי זה יהיה איטי יותר.

גיבוי מסד הנתונים והמדיה

העתקת Docker volumes בזמן ש־PostgreSQL רץ עלולה להניב גיבוי שלא ניתן לשחזור. Paperless כולל כלי ייצוא מובנה, הכותב מסמכים יחד עם קובץ JSON המכיל את כל המטא-דאטה לתוך ה-bind mount המוגדר ב-./export:

docker compose exec -T webserver document_exporter ../export --delete --no-progress-bar

הדגל --delete מסיר קבצים מיוצאים שאינם תואמים עוד למסמך קיים, כך שהתיקייה נשארת תמונת מצב עדכנית במקום לגדול ללא הגבלה. הדגל --no-progress-bar שומר על פלט נקי בעת הרצה מתוך cron, והדגל -T מונע מ-Compose לבקש מסוף (terminal) שאינו זמין בסביבת cron.

השחזור מתבצע באמצעות document_importer מול אותה תיקייה בשרת חדש, מה שאומר שתיקיית הייצוא היא הדבר היחיד שצריך לשמור עליו. העבירו אותה לאתר מרוחק לפי לוח זמנים בעזרת גיבויי restic מוצפנים ומבוססי דה-דופליקציה מה-VPS שלכם, והריצו את הייצוא לפני הגיבוי כדי ש-restic לעולם לא יתפוס ארכיון חלקי.

אמתו את הגיבוי על ידי בדיקה ש-export/manifest.json קיים ושהמספר הכולל של הקבצים תואם למספר המסמכים בממשק. גיבוי שמעולם לא בדקתם אינו גיבוי. ייצוא לילי שנכשל בשקט גרוע אף יותר, לכן הגדירו את משימת ה-cron כך שתשלח את סטטוס היציאה ל-שרת ntfy שבבעלותכם; כך תדעו על התקלה בשבוע שבו היא קרתה, ולא ביום שבו תזדקקו לשחזור.

FAQ

מדוע כל דף מחזיר שגיאת "Bad Request (400)" לאחר הפניית הדומיין שלי אליו?

עם קובצי ברירת המחדל זה לא אמור לקרות, כיוון ש-PAPERLESS_ALLOWED_HOSTS מוגדר כברירת מחדל ל-*. שגיאת 400 עם DisallowedHost בלוג של המכולה מעידה על כך ש-PAPERLESS_ALLOWED_HOSTS הוגדר לרשימה שאינה כוללת את הדומיין שלך. הגדירו את PAPERLESS_URL=https://paperless.example.com בתוך docker-compose.env, ללא לוכסן בסוף, ו-paperless תוסיף את שם המארח הזה לרשימה, או הסירו את השורה PAPERLESS_ALLOWED_HOSTS. לאחר מכן הריצו את docker compose up -d כדי ליצור מחדש את המכולה. עריכת קובץ ה-env בלבד אינה משנה דבר, כיוון שהמכולה הרצה שומרת על סביבת העבודה שבה הופעלה.

שמתי קובץ PDF בתיקיית ה-consume ולא קרה כלום. מה הבעיה?

בדקו תחילה את docker compose logs webserver. שגיאת הרשאות פירושה ש-USERMAP_UID ו-USERMAP_GID אינם תואמים לחשבון שבבעלותו הקובץ; תקנו זאת וצרו מחדש את המכולה. אם אין שורת לוג כלל, סימן שאירוע הקובץ מעולם לא הגיע, מה שקורה בכונני רשת כיוון שהתראות מערכת קבצים מקומיות אינן אמינות שם. הגדירו את PAPERLESS_CONSUMER_POLLING_INTERVAL לערך כמו 30 ו-paperless תסרוק את התיקייה בכל 30 שניות במקום זאת.

האם ניתן להריץ את paperless-ngx עם SQLite במקום PostgreSQL?

כן, docker-compose.sqlite.yml נתמך וצורך פחות זיכרון, מה שמתאים ל-VPS קטן. הפשרה מורגשת ככל שהארכיון גדל: חיפוש טקסט מלא ועריכת תגיות מרובות הופכים לאיטיים משמעותית באלפי מסמכים. הגירה מאוחרת יותר דורשת ייצוא וייבוא, לכן בחרו ב-PostgreSQL כבר עכשיו אם אתם צופים שהארכיון ימשיך לגדול.

כמה שטח דיסק דורש ארכיון של סריקות בפועל?

בערך פי שניים מגודל קובצי המקור שלכם. Paperless שומרת על המקור ללא שינוי ומאחסנת קובץ PDF שני שעבר OCR עם שכבת טקסט לחיפוש, בתוספת תמונות ממוזערות קטנות. סריקה של 200 KB המכילה טקסט בלבד נשארת קטנה. סריקה צבעונית של 30 MB של חוזה ארוך תתפוס כ-60 MB. הוסיפו את ספריית הייצוא אם אתם שומרים אותה על אותו דיסק, והארכיון כולו נמצא על הדיסק שלוש פעמים.

האם אני צריך את המכולות Tika ו-Gotenberg?

רק אם אתם רוצים שקבצי Word, Excel או OpenDocument יאונדקסו לצד קובצי ה-PDF שלכם. הן ממירות פורמטים אלו ל-PDF כדי ש-paperless תוכל לבצע להם OCR ולחפש בהם. הן גם מוסיפות שתי מכולות רצות נוספות וכמה מאות מגה-בייטים של זיכרון, לכן דלגו עליהן במכונה קטנה אם כל מה שאתם מתייקים הוא כבר PDF או תמונה.

האם המאמר הזה היה מועיל?

#paperless-ngx#documents#self-hosting#docker#ocr