SSD Nodes Learn
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-07-24

מדריך Docker Compose ב-Ubuntu 24.04

למדו להתקין Docker Engine ו-Compose v2 ב-Ubuntu 24.04, כתיבת קובץ compose.yml עם שני שירותים, פתרון בעיות ufw וגיבוי volumes בצורה נכונה.

מה אתם בונים

Docker Compose הוא התשתית עבור כמעט כל שירות אחר באתר זה. Nextcloud, Vaultwarden, n8n, Immich, Rocket.Chat — כל אחד מהמדריכים הללו נפתח בהנחיה "כתבו קובץ compose זה", ועמוד זה מסביר מה הקובץ הזה באמת אומר. תתקינו את Docker Engine ואת התוסף Compose v2 מתוך ה-apt repository הרשמי של Docker על Ubuntu 24.04, ולאחר מכן תקימו סטאק אמיתי בעל שני שירותים — Miniflux, קורא RSS קטן, בתוספת PostgreSQL — מכיוון שצמד זה מיישם כל תבנית שמשמשת את האפליקציות הגדולות יותר: דיוק תמונות (pinned images), מסד נתונים עם healthcheck, volume בשם (named volume), secrets בקובץ .env, ופורט שפורסם ל-localhost בלבד.

ההתקנה אורכת חמש דקות. שאר המדריך עוסק בחלקים שיוציאו לכם את העיניים מאוחר יותר: קבוצת docker שהיא root בשם אחר, פורטים שפורסמו ועוקפים ישירות את חוקי ה-ufw שלכם, ודגל אחד ב-docker compose down שממחק את מסד הנתונים שלכם ללא בקשת אישור.

דרישות קדם: שרת Ubuntu 24.04 KVM VPS חדש, משתמש עם הרשאות sudo, ו-1 GB של RAM או יותר. גם התקנת Docker קיימת תקינה — הסעיף הראשון מסביר מה יש להסיר.

התקנה ממאגר Docker, לא ממאגר Ubuntu

יש להימנע משתי טעויות נפוצות לפני הרצת הפקודה הראשונה. חבילת ה-docker.io של Ubuntu עובדת, אך היא מתעדכנת באיחור ביחס לגרסאות של Docker ואינה כוללת את מבנה ה-plugin הנדרש. בנוסף, הקובץ הבינארי ה-docker-compose (זה עם המקף) הוא Compose v1: מבוסס Python, הגיע לסוף חייו (end-of-life) בשנת 2023, והוא הסיבה לכך מדריכים ישנים אינם עובדים. Compose הנוכחי הוא docker compose (עם רווח), הוא plugin של ה-CLI, ומתקינים אותו מאותו מאגר של ה-engine.

אם אחד הרכיבים כבר מותקן במערכת, יש להסיר אותו תחילה — כולל את docker-compose-v2 (חבילת ה-plugin של Ubuntu), כדי שכל הרכיבים יגיעו מאותו מאגר:

sudo apt remove -y docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc

Package 'docker.io' is not installed, so not removed היא הפלט הרגיל ב-VPS חדש. לאחר מכן, הוסיפו את המאגר של Docker והתקינו:

sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

בדקו את שלושת השכבות:

docker --version
docker compose version
sudo docker run --rm hello-world

שתי הפקודות הראשונות מציגות מחרוזות גרסה — Docker Compose version v2.x.x מאשר שיש לכם את ה-plugin ולא את הקובץ הבינארי הישן v1. הפקודה hello-world אמורה להסתיים ב-Hello from Docker!. החבילה מאפשרת את השירות בעת עליית המערכת; systemctl is-enabled docker מציג את enabled.

קבוצת docker היא root — החלט בזהירות

כרגע כל פקודת docker דורשת הרשאות sudo, מכיוון שה-socket של ה-daemon ב-/var/run/docker.sock שייך ל-root ולקבוצה docker. ללא חברות בקבוצה, תקבל את שגיאת ה-Docker הנפוצה ביותר:

permission denied while trying to connect to the Docker daemon socket at
unix:///var/run/docker.sock

הפתרון הסטנדרטי:

sudo usermod -aG docker $USER

חברות בקבוצה נכנסת לתוקף בעת ההתחברות (login), לכן השגיאה תופיע גם ב-shell הנוכחי. הרץ את newgrp docker עבור הסשן הנוכחי, או תתנתק ותתחבר מחדש; לאחר מכן id אמור להציג את docker ברשימת הקבוצות שלך.

כעת החלק הכישיר: חברות בקבוצת docker היא root על ה-host. לא "דומה ל-root", לא "מורחבת" — אלא root. כל מי שנמצא בקבוצה זו יכול להריץ docker run --rm -it -v /:/host alpine chroot /host ולשלוט בכל מערכת הקבצים, ללא צורך בסיסמה. הקבוצה קיימת לצורך נוחות, לא לצורך בידוד (containment).

מצב rootless של Docker הוא החלופה האמיתית — ה-daemon עצמו רץ כמשתמש ללא הרשאות. המחיר לכך הוא: פורטים מתחת ל-1024 דורשים הגדרה נוספת, הרשת פועלת דרך shim במרחב המשתמש (userspace) עם תקורה (overhead) ניכרת, וחלק מה-images מתנהגים בצורה לא תקינה ללא root אמיתי. ב-VPS עם מנהל יחיד שבו המשתמש המתחבר מחזיק כבר sudo, השינוי בקבוצה אינו משנה בפועל, וזה מה שכל מדריך כאן מניח — רק אל תשתמש בקבוצה הזו כאילו היא פחות מ-sudo.

Anatomy of a compose file

הקצה לכל stack את התיקייה הייעודית שלו — שם התיקייה הופך לשם הפרויקט, המשמש כקידומת עבור ה-containers, ה-networks וה-volumes:

sudo mkdir -p /opt/miniflux && sudo chown $USER /opt/miniflux && cd /opt/miniflux

צור את compose.yml (השם המודרני; docker-compose.yml עדיין עובד). דלג על מפתח version: הישן — הוא מיושן ו-Compose יציג אזהרה אם הוא יזהה אותו.

services:
  miniflux:
    image: miniflux/miniflux:2.2.9
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      - DATABASE_URL=postgres://miniflux:${POSTGRES_PASSWORD}@db/miniflux?sslmode=disable
      - RUN_MIGRATIONS=1
      - CREATE_ADMIN=1
      - ADMIN_USERNAME=admin
      - ADMIN_PASSWORD=${ADMIN_PASSWORD}
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      - POSTGRES_USER=miniflux
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=miniflux
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "miniflux", "-d", "miniflux"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  db-data:

כל שורה לעיל היא החלטה. קבל אותן אחת אחת.

Pin image versions — :latest plus a pull is an unattended upgrade

השתמש ב-postgres:16-alpine, לא ב-postgres:latest. Tag אינו קבוע: :latest מתעדכן לגרסה האחרונה שהמשתמשת (maintainer) דחפה בכל פעם שאתה מבצע pull. שילוב זה עם הרגיית השדרוג השגרתית שאתה עומד ללמוד — docker compose pull && docker compose up -d — אומר ש-:latest גורם לקפיצות גרסאות ראשיות (major-version) לקרות ברגע שהן משוחררות במקור, ולא כשאתה בוחר. ב-PostgreSQL זה אינו תיאורטי: קפיצה מפתיעה מ-16 ל-17 תשאיר את ה-container בלופ של קריסות (crash-looping) בגלל ספריית נתונים לא תואמת, מכיוון ששדרוגים ראשיים של Postgres דורשים dump ו-restore, ולא רק restart.

קבע לפחות את הגרסה הראשית (postgres:16-alpine עוקב אחרי גרסאות ה-patch של 16.x), וקבע אפליקציות לגרסה מדויקת כמו miniflux/miniflux:2.2.9 — בדוק את דף ה-releases של הפרויקט והשתמש בגרסה העדכנית ביותר בזמן כתיבת הקובץ. שדרוג יהפוך אז לעריכה של שורה אחת שביצעת בכוונה, שתהיה גלויה ב-git diff.

Publish to 127.0.0.1, because Docker walks around ufw

"127.0.0.1:8080:8080" — כתובת המארח (host), פורט המארח, פורט ה-container. רוב המדריכים כותבים "8080:8080", שהוא קיצור ל-0.0.0.0:8080:8080: האזנה לכל ה-interfaces, כולל הציבורי.

להלן המלכודת, והיא תפגע כמעט בכל אחד פעם אחת. Docker מפרסם פורט על ידי כתיבת כלל DNAT שמשכת את היעד של ה-packet ל-IP הפנימי של ה-container לפני הסינון, לכן ה-packet עובר בנתיב FORWARD ולא נוגע ב-INPUT, שם נמצאים חוקי ה-ufw שלך. sudo ufw deny 8080 ידווח על הצלחה, ufw status יראה שהפורט נחסם, והשירות עדיין יענה לכל האינטרנט. ה-firewall שלך לא מקולקל; הוא פשוט עוקף בתכנון. Why Docker bypasses ufw, and how to filter container traffic for real מסביר את המנגנון ואת הפתרון של DOCKER-USER עבור פורטים שחייבים להישאר ציבוריים.

ההרגל שגורם לכל הבעיה להיעלם: קשרו (bind) פורטים מפורסמים ל-127.0.0.1 אלא אם יש לכם סיבה ספציפית שלא, והציבו reverse proxy לפני כל דבר שצריך לפעול מול העולם. זה בדיוק מה ש-Traefik reverse proxy guide בונה כשלב הבא לאחר דף זה — container אחד שבבעלותו פורטים 80 ו-443 ומנתב לכל השאר לפי hostname, עם TLS. (מגיעים מ-Traefik v2 ישן? Traefik v2 to v3 migration guide מכסה את שינויי השמות והכללים.)

וודאו את הקישור (bind) לאחר הפעלת ה-stack: sudo ss -tlnp | grep 8080 אמור להציג את 127.0.0.1:8080, לא את 0.0.0.0:8080 או *:8080.

Named volumes vs bind mounts

db-data:/var/lib/postgresql/data הוא named volume: Docker יוצר ומנהל תיקייה תחת /var/lib/docker/volumes/ ומקשר (mount) אותה לתוך ה-container. החלופה היא bind mount, ./data:/var/lib/postgresql/data, הממפה נתיב שבחרת ב-host.

החלוקה שעובדת בפועל: named volumes עבור containers שנוגעים בנתונים בלבד — מסדי נתונים מעל הכל, מכיוון ש-Docker מאתחל את ה-volume עם הבעלות (ownership) שה-image מצפה לה ומרשימי הקבצים (file permissions) עובדים בצורה תקינה. bind mounts עבור קבצים שאתם נוגעים בהם מה-host — קבצי הגדרה שאתם עורכים בעורך טקסט, ספריית מדיה שאתם מעליםים באמצעות rsync, כל דבר שהנתיב שלו צריך להיות גלוי. הכישלון הקלאסי של bind-mount הוא בעלות: ה-container רץ כ-UID 999, תיקיית ה-host שלך בבעלות UID 1000, והאפליקציה קורסת בהפעלה עם permission denied בלוגים. named volumes גורמים לסוג זה של באג להיעלם כמעט לחלוטין, במחיר של אחסון הנתונים בנתיב המנוהל על ידי Docker — מפורט להלן.

environment and .env — keep secrets out of git

${POSTGRES_PASSWORD} אינו נקרא מה-shell שלך; Compose מפרש אותו מקובץ בשם .env שנמצא לצד compose.yml. צרו אותו:

cat > .env <<'EOF'
POSTGRES_PASSWORD=change-me-to-something-long
ADMIN_PASSWORD=change-me-too
EOF
chmod 600 .env
echo ".env" >> .gitignore

יצרו ערכים אמיתיים עם openssl rand -hex 24. Hex, ולא base64, בכוונה: הסיסמה הזו תופיע בתוך מחרוזת החיבור של DATABASE_URL, והתווים /, + ו-= ש-base64 מייצר ישברו את ניתוח ה-URL — כשל שמופיע כשגיאת אימות (authentication error) ולא כשגיאת תחביר (syntax error), ומבזבז ערב שלם. שורת .gitignore צריכה להופיע לפני ה-commit הראשון: קובץ ה-compose בטוח לפרסום ולניהול גרסאות, קובץ ה-.env לעולם לא בטוח, וסוד שנגע בהיסטוריית git הוא סוד שחייבים להחליף (rotate). אם תפעילו את ה-stack עם משתנה חסר, Compose יציג אזהרה חריפה וימשיך עם מחרוזת ריקה — מה שמצביע על פריסה שבורה עבור סיסמת Postgres:

WARN[0000] The "POSTGRES_PASSWORD" variable is not set. Defaulting to a blank string.

docker compose config מדפיס את הקובץ לאחר כל ה-interpolation — הדרך המהירה ביותר לבדוק מה ה-containers יקבלו בפועל; זכרו שהפלט כולל את הסודות שלכם.

depends_on waits for nothing — unless you add a healthcheck

depends_on: [db] פשוט שולט רק בסדר ההפעלה: Compose מפעיל את Postgres ראשון ואת האפליקציה רגע לאחר מכן, בזמן ש-Postgres עדיין נמצא שניות ספורות מרגע קבלת חיבורים. האפליקציה פונה לבסיס הנתונים, נכשלת, וקורסת או מנסה שוב בהתאם לאיכות הכתיבה שלה.

הגרסה האמינה היא זו שהקובץ לעיל משתמש בה: ה-service ב-db מגדיר healthcheck (Postgres מספק את pg_isready בדיוק למטרה זו), והאפליקציה מכריזה על depends_on עם condition: service_healthy. Compose מפעיל את בסיס הנתונים, בודק את ה-check כל 10 שניות, ומפעיל את Miniflux רק לאחר שהבדיקה עוברת. אם בסיס הנתונים לא הופך ל-healthy — סיסמה שגויה, volume פגום — האפליקציה לעולם לא תעלה ו-Compose יגיד לכם איזו תלות (dependency) נכשלה:

dependency failed to start: container miniflux-db-1 is unhealthy

ההודעה הזו מפנה אתכם אל docker compose logs db, שם נמצאת השגיאה האמיתית.

restart: unless-stopped

restart: unless-stopped בשני ה-services אומר שה-containers יחזרו לאחר קריסה ולאחר ריסטארט של ה-VPS, אך יישארו כבויים אם הרצתם בכוונה את docker compose stop. החלופה always מחייה את ה-containers גם לאחר עצירה ידנית — מה שרק לעיתים רחוקות הוא מה שרציתם. ללא מדיניות restart, ריסטארט של עדכון kernel ב-4 לפנות בוקר יפיל את השירותים שלכם בשקט עד שתשימו לב.

הפעולות היומיומיות

כל הפעולות היומיומיות מורכבות מחמש פקודות, המורצות מתוך ספריית הפרויקט.

docker compose up -d        # create and start; idempotent, recreates only what changed
docker compose ps           # status, ports, and health of this project's containers
docker compose logs -f miniflux   # follow one service's logs; --tail 100 for recent history
docker compose pull && docker compose up -d   # upgrade to the pinned tags
docker compose down         # stop and remove containers and the network

ניתן להריץ את up -d שוב ושוב ללא חשש — הפקודה משווה את הקובץ למצב בפועל ומעדכנת רק שירותים שהגדרת או ה-image שלהם השתנו. זוג פקודות ה-upgrade מוריד את מה שה-tags הקבועים שלך מצביעים עליהם כעת: גרסאות patch תחת postgres:16-alpine, ולא יתבצע עדכון עבור pin מדויק עד שתערוך אותו — וזה המטרה. images ישנים מצטברים לאחר שדרוגים; השתמש ב-docker image prune -f כדי לפנות שטח דיסק.

כעת הפעולה ההרסנית, אזהרה: docker compose down היא בטוחה — ה-containers והרשת הם disposable, והנתונים שלך נמצאים ב-volume. docker compose down -v מוחקת גם את ה-named volumes. זהו מסד הנתונים שלך, הוא יימחק באופן מיידי, ללא בקשת אישור וללא אפשרות ביטול. דגל -v קיים לצורך פירוק ניסויים; על stack המכיל נתונים אמיתיים, התייחס אליו בדיוק כפי שמתייחסים ל-rm -rf. אין סל מחזור תחת /var/lib/docker/volumes/.

לגישה ל-shell חד-פעמי בתוך container פעיל: docker compose exec db psql -U miniflux מכניסה אותך למסד הנתונים, ו-docker compose exec miniflux sh מעניקה לך shell בתוך האפליקציה.

היכן הנתונים שלך מאוחסנים בפועל

volumes עם שם מקבלים את הקידומת של הפרויקט, לכן db-data בתוך ספרייה בשם miniflux יהפוך ל-miniflux_db-data:

docker volume ls
docker volume inspect miniflux_db-data

פלט ה-inspect כולל את השורה הרלוונטית:

"Mountpoint": "/var/lib/docker/volumes/miniflux_db-data/_data"

הספרייה הזו היא מסד הנתונים — היא שייכת למשתמש root, נמצאת במערכת הקבצים של המארח (host), והיא נשמרת גם לאחר down, שדרוגים ובנייה מחדש של ה-container. זהו בדיוק המידע שגיבויים שלך חייבים לכלול.

גיבוי volume בשם

השיטה הסטנדרטית היא שימוש ב-container זמני שמmount ל-volume במצב read-only לצד ספרייה ב-host, ולאחר מכן ביצוע tar:

docker run --rm \
  -v miniflux_db-data:/data:ro \
  -v "$PWD":/backup \
  alpine:3.22 tar czf /backup/miniflux-db-$(date +%F).tar.gz -C /data .

אין צורך בהתקנה, שום דבר לא נשאר פעיל, והשחזור הוא הפוך בדיוק — tar xzf לתוך volume חדש וריק עם אותם mounts הפוכים.

הערה לגבי בסיסי נתונים: ביצוע tar לספריית הנתונים של Postgres בזמן שהיא פועלת עלול לשמור מצב של כתיבה באמצע התהליך, מה שימנע עלייה תקינה. יש להשתמש ב-docker compose stop למשך השניות שבהן ה-tar מתבצע, או — עדיף — לבצע logical dump, שהוא עקבי מעצם מבנהו:

docker compose exec -T db pg_dump -U miniflux miniflux | gzip > miniflux-$(date +%F).sql.gz

ה--T מבטל את ה-pseudo-terminal ש-Compose מקצה כברירת מחדל — העברת פלט dump דרך TTY עלולה להفسר אותו. יש להגדיר את אחת האפשרויות הללו ב-cron ולהעתיק את התוצאה מחוץ ל-VPS; גיבוי שנשמר על אותו דיסק של הנתונים שהוא מגן עליהם הוא עותק (copy), לא גיבוי (backup). ה-מדריך Nextcloud בונה שגרת עבודה מתוזמנת המבוססת בדיוק על שתי השיטות הללו.

Failure modes, with the strings you will see

permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock — אינך חבר בקבוצת docker עדיין, או שאתה חבר בה אך הסשן הנוכחי נוצר לפני הצטרפותך. id מציג את הקבוצות הפעילות שלך; newgrp docker מתקן את ה-shell הנוכחי; יציאה מהמערכת וכניסה מחדש תתקן את כולן.

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? — בעיה שונה: ה-daemon עצמו אינו פועל. sudo systemctl status docker ו-sudo journalctl -u docker -n 50 יציינו את הסיבה. ב-VPS הסיבה הנפוצה היא דיסק מלא — בדוק את df -h /var/lib/docker תחילה.

Bind for 127.0.0.1:8080 failed: port is already allocated — קונטיינר אחר כבר תפס את ה-host port הזה. docker ps מציג איזה קונטיינר; בדרך כלל מדובר בקונטיינר ישן מ-docker run לפני שבועות. אם docker ps נקי, תהליך שאינו Docker מחזיק בפורט: sudo ss -tlnp | grep 8080 יציין את שמו.

yaml: line 14: did not find expected key — שגיאת הזחה (indentation) בשורה המצוינת או מעליה. קובצי Compose הם בפורמט YAML: הזחה של שני רווחים, שימוש ברווחים בלבד, וכל תו tab יגרום לשגיאה קריטית. docker compose config מאמת את הקובץ ללא הפעלת שום דבר; מומלץ להריץ אותו לאחר כל עריכה.

The ufw surprise אינו מדפיס שגיאה כלל, וזה מה שהופך אותו למסוכן: הפריסה עובדת, ufw status נראה תקין, וסריקת פורטים מבחוץ תמצא את מסד הנתונים שלך בכל זאת. קרא שוב את סעיף הפורטים לעיל, בדוק כל רשומה ב-ports: כדי לוודא שחסר קידומת 127.0.0.1:, וודא את המצב ממכונה אחרת באמצעות curl http://your-vps-ip:8080 — התשובה הרצויה היא connection refused.

מכאן, ה מדריך Traefik הופך את ה-stack הבודד הזה לכמה אפליקציות מאחורי נקודת כניסה אחת ב-HTTPS, ו-מה כדאי לארח בעצמך ב-2026 הוא רשימת המשימות להרצה דרכו.

שרת משחק כגון שרת Minecraft ב-VPS הוא פרויקט Compose ראשון ונוח לתרגול.

FAQ

מדוע אני מקבל "permission denied while trying to connect to the Docker daemon socket"?

המשתמש שלך אינו חבר בקבוצת docker, או שהוא נוסף לאחר תחילת הסשן הנוכחי — חברות בקבוצה נכנסת לתוקף רק בעת ההתחברות (login). הרץ את sudo usermod -aG docker $USER, ולאחר מכן את newgrp docker או התנתק והתחבר מחדש, וודא את השינוי באמצעות id. הקבוצה מעניקה הרשאות ברמת root למארח (host), לכן הוסף רק משתמשים שאתה מעוניין לתת להם sudo.

האם docker compose down מוחק את הנתונים שלי?

פקודת docker compose down רגילה אינה מוחקת אותם — היא מסירה את ה-containers ואת רשת הפרויקט; volumes עם שם נשארים, והפקודה up -d הבאה תחבר אותם מחדש. docker compose down -v היא הפקודה ההרסנית: היא מוחקת את ה-volumes עם השם, מה שאומר שה-database שלך יימחק ללא אישור וללא אפשרות ביטול. לעולם אל תריץ -v על stack עם נתונים אמיתיים אלא אם יש לך גיבוי מאומת.

מה ההבדל בין docker-compose לבין docker compose?

docker-compose (עם מקף) הוא Compose v1, קובץ binary עצמאי בשפת Python שהגיע לסוף חייו (end of life) בשנת 2023 ולא ישתמש בשרתים חדשים. docker compose (עם רווח) הוא Compose v2, תוסף Go עבור ה-Docker CLI, המותקן כ-docker-compose-plugin מתוך ה-apt repository של Docker. הפקודות וקובצי ה-YAML תואמים כמעט לחלוטין, לכן כאשר מדריך ישן מציין את docker-compose up, הקלד docker compose up.

מדוע אני יכול להגיע ל-Docker container שלי מהאינטרנט למרות ש-ufw חוסם את הפורט?

מכיוון ש-Docker מפרסם פורטים באמצעות כללי DNAT בשרשרת PREROUTING של iptables, והחבילות המשוכנות עוברות בנתיב FORWARD דרך השרשראות של Docker עצמו — הן לעולם לא מגיעות לשרשרת INPUT שבה חלים הכללים של ufw. לכן, ufw deny 8080 אינו משפיע על פורט של container שפורסם. תקן זאת במקור: פרסם ל-127.0.0.1: והשתמש ב-reverse proxy כדי לחשוף שירותים.

האם כדאי להשתמש ב-named volume או ב-bind mount?

השתמש ב-named volumes עבור נתונים שה-container בלבד נוגע בהם — במיוחד ב-databases, מכיוון ש-Docker מגדיר את הבעלות (ownership) שה-image מצפה לה וההרשאות פועלות כראוי. השתמש ב-bind mounts עבור קבצים שאתה גם מנהל מהמארח (host): קונפיגורציות שאתה עורך, מדיה שאתה מעלה, או כל דבר שהנתיב שלו צריך להיות גלוי. אם container נכשל בעת ההפעלה עם permission denied ב-bind mount, בדוק תחילה חוסר התאמה ב-UID בין המארח לבין ה-container.