تثبيت Mealie على VPS باستخدام Docker Compose
شغّل Mealie على VPS تملكه عبر Docker Compose. ألصق رابط وصفة لاستخراج المكونات والخطوات، وأنشئ خطط وجبات وقوائم تسوق مع nginx وTLS والنسخ الاحتياطية.
ما يفعله مدير الوصفات المستضاف ذاتياً
يحتفظ مدير الوصفات المستضاف ذاتياً بوصفاتك في قاعدة بيانات على خادم تملكه، ويُعد Mealie الخيار الذي تستقر عليه معظم الأسر. تلصق عنوان صفحة وصفة، فيقرأ Mealie المكونات والخطوات وكمية الناتج ومدة الطهي منها، ثم يتجاهل القصة والإعلانات. وما يُضاف إلى مجموعتك هو الوصفة نفسها.
بقية التطبيق بسيطة. توجد خطة أسبوعية للوجبات تسحب الوصفات إليها، وقائمة تسوق تُنشأ من هذه الخطة. يحصل كل شخص يطبخ على حساب تسجيل دخول خاص به. يعمل التطبيق كله داخل حاوية واحدة، ويبقى خاملاً بين الطلبات، لذلك يستطيع VPS متواضع تشغيله دون أن تلاحظ حملاً يُذكر.
يستخدم هذا الدليل Docker Compose. إذا كان المصطلحان services: وvolumes: جديدين عليك، فاقرأ أولاً كيفية إعداد ملفات Docker Compose، لأن كل ما يلي يتكون من ملف compose واحد وأربعة أوامر.
تثبيت Mealie باستخدام Docker Compose
تنشر Mealie صورها في سجل الحاويات الخاص بـGitHub. اعتباراً من July 2026، تكون الوسمة المستقرة الحالية هي v3.22.0. ثبّت إصداراً محدداً بدلاً من استخدام latest، لأن استخدام latest قد ينقلك في يوم غير متوقع إلى ترحيل لقاعدة البيانات لم تكن مستعداً له، وهو docker compose pull.
sudo mkdir -p /srv/mealie
cd /srv/mealie
sudo nano docker-compose.ymlservices:
mealie:
image: ghcr.io/mealie-recipes/mealie:v3.22.0
container_name: mealie
restart: always
ports:
- "127.0.0.1:9925:9000"
deploy:
resources:
limits:
memory: 1000M
volumes:
- mealie-data:/app/data/
environment:
ALLOW_SIGNUP: "false"
PUID: 1000
PGID: 1000
TZ: Europe/Amsterdam
BASE_URL: https://recipes.example.com
volumes:
mealie-data:يستحق سطران المراجعة قبل تشغيله.
كُتب المنفذ بصيغة 127.0.0.1:9925:9000 وليس بصيغة 9925:9000. تستمع الحاوية على المنفذ 9000 داخلياً، ويربط المضيف المنفذ 9925 به. يعني ربط هذا التعيين بعنوان loopback أن nginx يستطيع الوصول إلى Mealie، بينما لا يستطيع الإنترنت ذلك. يضيف Docker قواعده الخاصة إلى مرشح الحزم، لذلك يمكن الوصول إلى 9925:9000 من الخارج حتى عندما يشير جدارك الناري إلى أن المنفذ مغلق. من المهم فهم هذه المفاجأة مرة واحدة: راجع سبب تجاهل منافذ Docker المنشورة لـufw.
يجب أن يكون BASE_URL هو العنوان العام الدقيق الذي ستستخدمه، مع scheme ومن دون شرطة مائلة في النهاية. ينشئ Mealie روابط إعادة تعيين كلمات المرور وروابط الدعوات انطلاقاً منه. إذا ضبطته على http://localhost:9925، فستتضمن الدعوة التي ترسلها إلى شريكك رابطاً لا يعمل إلا على الخادم نفسه.
شغّلها وراقب الإقلاع الأول.
sudo docker compose up -d
sudo docker compose logs -f mealieينشئ التشغيل الأول قاعدة بيانات SQLite ويشغّل عمليات الترحيل، ويستغرق ذلك بضع ثوانٍ. عندما تستقر السجلات وتتوقف عن طباعة أسطر الترحيل، تحقّق من التطبيق محلياً.
curl -I http://127.0.0.1:9925تعني 200 OK أن التطبيق يعمل. وتعني Connection refused أن الحاوية لا تعمل: شغّل sudo docker compose ps واقرأ رمز الخروج. إذا توقفت حاوية برمز 137، فهذا يعني أنها أُوقفت بسبب تجاوز حد الذاكرة البالغ 1000M، ويحدث ذلك في الخطط الأصغر.
تسجيل الدخول الأول وتعطيل التسجيل المفتوح
الحساب الافتراضي هو changeme@example.com وكلمة المرور هي MyPassword. سجّل الدخول باستخدامهما، ثم غيّرهما فوراً، لأن هذا الزوج مذكور في الوثائق، ولذلك يوجد في كل أداة فحص.
وجود ALLOW_SIGNUP: "false" في ملف compose مقصود. عند فتح التسجيل، يستطيع أي شخص يعثر على العنوان إنشاء حساب في صندوق وصفاتك. عند إغلاقه، تضيف المستخدمين من منطقة الإدارة، التي تنشئ رابط دعوة ترسله إليهم بنفسك. يُبنى هذا الرابط من BASE_URL، ولذلك تهم هذه القيمة. إذا انتهى بك الأمر إلى تشغيل عدة تطبيقات على الخادم نفسه وأردت استخدام كلمة مرور واحدة لها جميعاً، يستطيع Mealie تمرير تسجيل الدخول إلى موفّر هوية خارجي، مثل مثيل Authentik مستضاف ذاتياً.
يجمع Mealie المستخدمين في household. يشترك جميع أفراد household واحد في مجموعة الوصفات وخطة الوجبات وقائمة التسوق، وهذا ما تحتاج إليه العائلة. أما households المنفصلة على الخادم نفسه، فتحافظ على مجموعات منفصلة، وهذا ما تحتاج إليه الشقة المشتركة عندما لا يتفق أحد على الأنشوجة.
المستورد، وهو سبب تشغيل هذه الخدمة
افتح مجموعة الوصفات، واختر إنشاء وصفة من عنوان URL، ثم الصق رابطاً. يجلب Mealie الصفحة ويبحث عن بيانات وصفات منظَّمة، وهي كتلة قابلة للقراءة آلياً تضمّنها معظم مواقع الوصفات لمحركات البحث. عندما تكون هذه الكتلة موجودة، تتم عملية الاستيراد بسرعة وبلا مشكلات.
يمكنك أيضاً الاستيراد من صورة أو من نص عادي تلصقه، بما في ذلك صورة لصفحة من كتاب طبخ. تسلك هذه الخيارات مساراً أبطأ، وتحتاج إلى المراجعة بعد ذلك، لأن قراءة كسر مكتوب بخط اليد قد تكون غير دقيقة بسهولة.
تُجرى عمليات الاستيراد الجماعي من الشاشة نفسها: الصق قائمة بالعناوين، عنواناً واحداً في كل سطر، وسيعالجها Mealie في الخلفية. يمكنك نقل مجموعة تضم مئتي إشارة مرجعية في جلسة واحدة.
خطط الوجبات وقائمة التسوق
مخطط الوجبات عبارة عن تقويم. اسحب وصفة إلى يوم ليتم تخطيطها. تجمع قائمة التسوق بعد ذلك مكونات الوصفات المخططة في قائمة واحدة، وتدمج العناصر المكررة، لذلك تظهر الوصفتان اللتان تحتاجان إلى البصل في سطر واحد بدلاً من سطرين.
تظهر القائمة كصفحة مباشرة على هاتفك أثناء وجودك في المتجر. وبما أنّ خادمك الخاص يحتفظ بها، يرى جميع أفراد المنزل القائمة نفسها في الوقت نفسه، وعندما يضع أحدهم علامة على الحليب، يختفي من شاشة الشخص الآخر أيضاً.
ضع nginx وTLS أمام التطبيق
يتعامل Mealie مع HTTP العادي، ولا يدير الشهادات بنفسه. أنهِ أمان طبقة النقل (TLS) في nginx الموضوع أمامه. وجّه سجل DNS من النوع A إلى خادمك أولاً، لأن خطوة إصدار الشهادة تتحقق من هذا الاسم.
sudo apt update && sudo apt install -y nginx
sudo nano /etc/nginx/sites-available/mealieserver {
listen 80;
server_name recipes.example.com;
client_max_body_size 64M;
location / {
proxy_pass http://127.0.0.1:9925;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}sudo ln -s /etc/nginx/sites-available/mealie /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginxيُعد عرض nginx -t وsyntax is ok وtest is successful شرط السماح بالمتابعة. لا تُعد التحميل إلا بعد نجاحه، لأن إعادة تحميل إعداد معطوب تُبقي الإعداد القديم قيد التشغيل، وتخفي الخطأ حتى إعادة التشغيل التالية.
وجود client_max_body_size 64M ضروري لأن الإعداد الافتراضي في nginx هو 1 MB. يؤدي رفع صورة وصفة أو استعادة نسخة احتياطية عبر المتصفح إلى إرسال محتوى أكبر من ذلك. من دون هذا السطر، تحصل على 413 Request Entity Too Large من nginx، وليس من Mealie، ولذلك لا يظهر أي شيء في سجل التطبيق.
بعد ذلك، أصدر الشهادة. تشرح إصدار شهادة Let's Encrypt لـ nginx باستخدام certbot هذه الخطوة ومؤقت التجديد الخاص بها.
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d recipes.example.comيعيد Certbot كتابة كتلة الخادم للاستماع على 443، ويضيف إعادة توجيه من المنفذ 80. افتح الموقع عبر https://، وتأكد من أن المتصفح يقبل الشهادة. إذا حمّل Mealie، لكن روابطه الداخلية توجّهك إلى http://، فهذا يعني أن BASE_URL لا يزال مضبوطاً على http. صححه، ثم نفّذ sudo docker compose up -d لإعادة إنشاء الحاوية بالقيمة الجديدة.
لا يعمل تقديم Mealie ضمن مسار فرعي مثل example.com/recipes، لأن الواجهة الأمامية لا يمكن تقديمها من مسار فرعي. استخدم نطاقاً فرعياً.
النسخ الاحتياطية، وما الذي تنفّذه عملية الاستعادة فعلياً
توجد كل البيانات التي يديرها Mealie داخل /app/data/ في الحاوية، وهو المجلد mealie-data. انسخ هذا المجلد، وستنسخ الوصفات والصور وقاعدة البيانات معاً.
sudo docker volume ls
sudo docker compose stop mealie
sudo docker run --rm -v mealie_mealie-data:/data -v "$PWD":/backup \
alpine tar czf /backup/mealie-data.tgz -C /data .
sudo docker compose start mealieيحتوي اسم المجلد على اسم المشروع كبادئة، واسم المشروع هو اسم الدليل الذي يحتوي على ملف compose. من /srv/mealie، يكون المجلد mealie_mealie-data، ولذلك يكون الأمر الأول هو docker volume ls: استخدم الاسم الذي يعرضه الأمر، وليس الاسم الوارد في هذا الدليل. من المهم إيقاف الحاوية أولاً، لأن SQLite تكون في وضع الكتابة أثناء التشغيل بشكل متكرر بما يكفي لجعل النسخة الحية غير قابلة للقراءة عند استعادتها.
تحتوي Mealie أيضاً على صفحة نسخ احتياطي خاصة بها في منطقة الإدارة. تنشئ هذه الصفحة أرشيفاً قابلاً للنقل يحتوي على قاعدة البيانات بتنسيق JSON إلى جانب الصور. استخدمها عند النقل بين الخوادم، لأنها تظل صالحة بعد تغيير الإصدار، وهو أمر قد لا ينطبق على النسخ المباشر للملفات. استعادة الأرشيف مدمّرة عمداً: فهي تحذف قاعدة البيانات الحالية قبل تحميل الأرشيف، ولا يمكن التراجع عنها. سيتم تسجيل خروجك عند اكتمالها.
لا تُعدّ أي من النسختين نسخة احتياطية ما دامت موجودة على الخادم نفسه. ادفع الأرشيف إلى موقع آخر وفق جدول زمني. وهذا هو الغرض من النسخ الاحتياطية المشفّرة خارج الخادم باستخدام restic.
تحديث Mealie
cd /srv/mealie
sudo nano docker-compose.yml
sudo docker compose pull
sudo docker compose up -d
sudo docker compose logs -f mealieارفع الإصدار المثبّت في الملف، ثم اسحب الصورة وأعد إنشاء الحاوية. تُنفَّذ عمليات الترحيل عند التشغيل الأول للصورة الجديدة. أنشئ نسخة من وحدة التخزين قبل تغيير الإصدار الرئيسي، لأن فشل عملية ترحيل في منتصفها يترك قاعدة بيانات لن تتمكن الصورة السابقة من فتحها. اقرأ ملاحظات الإصدار لكل الإصدارات الواقعة بين إصدارك والإصدار الجديد.
عندما يفشل الاستيراد
لا تنشر بعض المواقع أي بيانات منظمة للوصفات، ولذلك يستورد Mealie العنوان مع قائمة مكونات فارغة. لا يمكن معالجة ذلك من خلال الإعدادات. ألصق نص الوصفة يدوياً بدلاً من ذلك.
تنتج حالات فشل أخرى عن حماية الروبوتات أمام موقع الوصفات، إذ يرسل الموقع إلى Mealie صفحة تحقق بدلاً من الوصفة. يحاكي Mealie المتصفح بالفعل ويبدّل User-Agent لتقليل هذه المشكلة. إذا استمر الموقع في الرفض، فالخيارات الموثقة هي تمرير أداة الاستخراج عبر proxy ذي سمعة أفضل للعنوان، أو تشغيل مثيل FlareSolverr يحل التحدي في متصفح فعلي. كلا الخيارين اختياري، ويُضبط كلاهما من خلال متغيرات البيئة في الحاوية.
أما فشل الاستيراد لأن خادمك لا يستطيع الوصول إلى الموقع إطلاقاً، فهذه مشكلة مختلفة. اختبر الاتصال من الخادم باستخدام curl -I https://the-site.example/recipe، واقرأ سطر الحالة قبل إلقاء اللوم على أداة الاستخراج.
موضعه
يُعد Mealie تطبيقاً ذاتي الاستضافة مناسباً للبدء في المنزل، لأن الأشخاص الذين يعيشون معك سيستخدمونه دون أن تطلب منهم ذلك. وهو يؤدي وظيفة مشابهة لوظيفة مكتبة الصور الخاصة بك مع Immich، لكنه أخف بكثير، ويندرج ضمن القائمة الأوسع لـالأشياء التي تستحق الاستضافة الذاتية هذا العام. ويمكن لخادم صغير واحد تشغيل التطبيقين معاً. ولا يُعد Immich الخيار الوحيد للوظيفة الثانية. وإذا كنت لا تزال تقرر، فإن الحد الأدنى للذاكرة وأوامر النسخ الاحتياطي في PhotoPrism وImmich يختلف بما يكفي لقراءته قبل أن تستهلك بقية مساحة القرص. إذا كانت الأسرة تحتفظ بخططها وملاحظاتها في مكان ما، إضافة إلى وصفات العشاء، فإن مساحة عمل AFFiNE ذاتية الاستضافة هي أيضاً تمرين على ملف compose نفسه، لكنها تحتاج إلى أربع حاويات وذاكرة أكبر بكثير مما يحتاجه Mealie. لذلك تحقق أولاً من الموارد المتبقية على الخادم. وإذا أرادت الأسرة تتبع تدريباتها إضافة إلى وجبات العشاء، فإن openGym يحتفظ ببيانات التمارين ويطلب الوسم المثبت وملف compose والشهادة نفسها التي أعددتها للتو. وللمساء بعد العشاء نسخته الخاصة من ذلك، إذ إن Halcyon يعيد بناء مكتبة Jellyfin الموجودة على هيئة متجر تأجير من تسعينيات القرن الماضي تتجول فيه، وهو حاوية صغيرة إضافية أمام شيء تشغّله بالفعل، وليس قاعدة بيانات أخرى تحتاج إلى نسخ احتياطي. ولا تنتمي كل التطبيقات في هذه المجموعة إلى تطبيقات منزلية. وإذا احتاجت العادة نفسها مستقبلاً إلى تشغيل شيء للعمل، فإن مكتب دعم Chatwoot ذاتي الاستضافة يستخدم الوسم المثبت والشهادة نفسيهما، مع Postgres وRedis وبريد صادر يعمل خلفه. وهذا مستأجر أثقل بكثير من صندوق وصفات، ويستحق خادماً مستقلاً.
FAQ
لماذا يفشل استيراد عنوان URL لوصفة؟
هناك سببان شائعان. إما أن الصفحة لا تنشر بيانات منظمة للوصفة، لذلك لا يعثر scraper على شيء وتحصل على عنوان بلا مكونات، أو أن طبقة حماية من الروبوتات أمام الموقع تعيد صفحة تحدٍّ بدلاً من الوصفة. في الحالة الثانية، يمكنك توجيه Mealie إلى proxy يتمتع بسمعة أفضل للعنوان، أو إلى مثيل FlareSolverr مستضاف ذاتياً يحل التحدي في متصفح فعلي. تأكد من أن خادمك يستطيع الوصول إلى الصفحة أصلاً باستخدام curl -I قبل تغيير أي شيء.
هل أحتاج إلى PostgreSQL، أم تكفي SQLite؟
تكفي SQLite للاستخدام المنزلي، وهي الإعداد الافتراضي. انتقل إلى PostgreSQL عندما يكون دليل البيانات على وحدة تخزين متصلة بالشبكة، لأن SQLite عبر نظام ملفات شبكي تنتج أخطاء قاعدة بيانات مقفلة وقد تتسبب في تلف الملف. تتطلب عمليات الاستعادة باستخدام PostgreSQL أن يكون مستخدم قاعدة البيانات superuser، لأن الاستعادة تحذف كل شيء قبل تحميل الأرشيف.
هل يمكنني تشغيل Mealie من دون اسم نطاق؟
نعم، على شبكتك الخاصة. اضبط BASE_URL على العنوان الذي ستكتبه فعلياً، مثل http://192.168.1.20:9925، وتجاوز nginx. تُنشأ روابط الدعوات وإعادة تعيين كلمة المرور من BASE_URL، لذلك تؤدي القيمة الخاطئة إلى إنشاء روابط لا يستطيع أي شخص آخر فتحها. لا تعرّضه للإنترنت عبر HTTP غير المشفّر، لأن بيانات تسجيل الدخول تُرسل عندئذٍ بنص واضح.
كيف أمنح أفراد عائلتي حسابات تسجيل دخول خاصة بهم؟
اترك ALLOW_SIGNUP مضبوطاً على "false" وأضف الأشخاص من منطقة الإدارة، حيث يؤدي ذلك إلى إنشاء رابط دعوة ترسله إليهم. ضع جميع من يتشاركون المطبخ في household واحد حتى يتشاركوا الوصفات وخطة الوجبات وقائمة التسوق. وتبقى مجموعات household المنفصلة على الخادم نفسه مستقلة.
ماذا يحدث لو توقفت عن تشغيل Mealie؟
يمكنك الاحتفاظ بها. تنشئ النسخة الاحتياطية من منطقة الإدارة بياناتك بصيغة JSON، ويمكن لـMealie أيضاً تصدير الوصفات كملفات markdown نصية عادية، وتظل هذه الملفات قابلة للقراءة في أي محرر نصوص من دون الحاجة إلى أي برنامج. نفّذ عملية تصدير واحدة قبل أن تحتاج إليها، وتحقق من أنك تستطيع فتح الملف.