ابزارهای Self-Hostedمهندسانسطح متوسط

کران Nextcloud در Docker: چرا جاب‌های پس‌زمینه اجرا نمی‌شوند

هشدار «Last background job execution ran...» در Nextcloud Docker اغلب از اجرا نشدن cron.php داخل کانتینر است. مسیر، کاربر و حالت cron را درست می‌کنیم.

تحریریه کلودیکپ ۷ دقیقه مطالعه
کران Nextcloud در Docker: چرا جاب‌های پس‌زمینه اجرا نمی‌شوند

اگر Nextcloud را در Docker بالا آورده‌اید و در صفحه Overview پنل ادمین این هشدار را می‌بینید: «Last background job execution ran 4 hours ago. Something seems wrong.» احتمالاً تا حالا چند بار crontab هاست را چک کرده‌اید و خط کران هم سر جایش هست. اما مشکل معمولاً از نبودن کران نیست؛ از این است که آن خط، cron.php را در جای اشتباهی اجرا می‌کند.

Nextcloud برای کارهایی مثل پاک‌سازی Trash، حذف نسخه‌های قدیمی فایل‌ها، تولید preview، پردازش اشتراک‌های فدرال و بسیاری کارهای پس‌زمینه به یک کران واقعی نیاز دارد که هر ۵ دقیقه اجرا شود. اگر این کران درست تنظیم نشود، خود Nextcloud بالا می‌آید و کاربران می‌توانند فایل آپلود کنند، ولی پشت صحنه کم‌کم به مشکل می‌خورد.

نشانه‌ها؛ چه چیزی واقعاً دیده می‌شود

  • در پنل ادمین، هشدار «Last background job execution ran ... Something seems wrong» دیده می‌شود.
  • پیش‌نمایش تصاویر و فایل‌های PDF دیر ساخته می‌شوند یا اصلاً ساخته نمی‌شوند.
  • فایل‌های حذف‌شده مدت زیادی در Trash می‌مانند و سیاست نگه‌داری اعمال نمی‌شود.
  • در محیط‌های شلوغ، صف کارهای پس‌زمینه طولانی می‌شود و occ background-job:list جاب‌هایی با زمان اجرای گذشته نشان می‌دهد.

اگر همان دستوری را که در crontab گذاشته‌اید، دستی روی هاست اجرا کنید، ممکن است خروجی زیر را ببینید:

Could not open input file: /var/www/html/cron.php

این خطا کل ماجرا را لو می‌دهد. مسیر /var/www/html/cron.php داخل کانتینر Nextcloud وجود دارد، نه روی فایل‌سیستم هاست. اگر خروجی کران را با >/dev/null 2>&1 خاموش کرده باشید، این خطا هیچ‌جا ثبت نمی‌شود و فقط هشدار ادمین باقی می‌ماند.

علت ریشه‌ای

سه لایه باعث این رفتار می‌شود:

  1. مرز کانتینر: کران روی هاست اجرا می‌شود، ولی فایل cron.php داخل ایمیج Nextcloud است. دستور php /var/www/html/cron.php روی هاست به فایلی اشاره می‌کند که وجود ندارد. باید از docker exec استفاده کنید تا دستور داخل کانتینر اجرا شود.
  2. کاربر اشتباه: حتی وقتی از docker exec استفاده می‌کنید، اگر -u www-data را نزنید، کران با کاربر root داخل کانتینر اجرا می‌شود. Nextcloud فایل‌هایی مثل لاگ‌ها، previewها و appdata را با مالک root می‌سازد و بعداً کاربر وب (www-data) نمی‌تواند آن‌ها را بنویسد. این وضعیت می‌تواند به خطاهای آپلود و «Cannot write to appdata» منجر شود.
  3. حالت AJAX یا webcron: Nextcloud چند حالت برای background job دارد. در حالت ajax، جاب‌ها فقط وقتی اجرا می‌شوند که کاربر صفحه‌ای باز کند. روی سروری که کم‌ترافیک است یا بیشتر با API و WebDAV کار می‌کند، این حالت قابل اتکا نیست. حالت webcron هم به یک سرویس بیرونی نیاز دارد که مرتب /cron.php را صدا بزند و در عمل کمتر درست پیکربندی می‌شود.

راه‌حل گام‌به‌گام

۱. نام کانتینر و حالت فعلی را ببینید

در دستورهای این مقاله نام کانتینر را nextcloud گذاشته‌ام. اگر نام دیگری دارید، همان را جایگزین کنید. اول ببینید کانتینر در حال اجراست و بعد حالت background job را بخوانید:

docker ps
docker exec -u www-data nextcloud php occ config:app:get core backgroundjobs_mode

اگر خروجی ajax یا webcron بود، همان مشکل اصلی است. اگر cron بود، یعنی حالت درست است ولی کران اجرا نمی‌شود یا خطا می‌دهد.

۲. حالت را روی cron بگذارید

docker exec -u www-data nextcloud php occ background:cron

بعد از اجرا دوباره دستور occ config:app:get core backgroundjobs_mode را بزنید و مطمئن شوید خروجی cron است. این تغییر فقط حالت را تنظیم می‌کند؛ هنوز باید کران واقعی روی هاست یا داخل کانتینر اجرا شود.

۳. قبل از تنظیم کران، دستی تست کنید

این مرحله مهم است. اگر دستور زیر بدون خروجی و با کد ۰ تمام شود، یعنی مسیر، کاربر و دسترسی‌ها درست است:

docker exec -u www-data nextcloud php -f /var/www/html/cron.php
echo $?

اگر خطای Could not open input file گرفتید، نام کانتینر یا مسیر فایل اشتباه است. اگر خطای Permission denied گرفتید، کاربر اجرا یا مالکیت فایل‌ها مشکل دارد. اگر قبلاً کران را با root اجرا کرده‌اید، مالکیت data directory را برگردانید؛ مسیر را با مسیر واقعی data خودتان عوض کنید:

docker exec -u root nextcloud chown -R www-data:www-data /var/www/html/data

۴. خط کران را روی هاست اضافه کنید

با کاربر root وارد crontab شوید:

sudo crontab -u root -e

این خط را اضافه کنید:

*/5 * * * * /usr/bin/docker exec -u www-data nextcloud php -f /var/www/html/cron.php >>/var/log/nextcloud-cron.log 2>&1

چند نکته:

  • مسیر /usr/bin/docker را با خروجی command -v docker روی هاست خودتان تطبیق دهید.
  • نام nextcloud را با نام واقعی کانتینر عوض کنید.
  • در کران از -it استفاده نکنید؛ کران TTY ندارد و docker exec -it ممکن است با خطای «the input device is not a TTY» شکست بخورد.
  • خروجی را به /dev/null نفرستید. همین کار باعث می‌شود خطاهایی مثل نبودن فایل یا Permission denied ماه‌ها مخفی بمانند.

اگر از Docker Compose استفاده می‌کنید، خط کران می‌تواند این شکل باشد. توجه کنید که -T برای غیرفعال کردن TTY لازم است و نام سرویس app را با نام سرویس خودتان عوض کنید:

*/5 * * * * cd /opt/nextcloud && /usr/bin/docker compose exec -T -u www-data app php -f /var/www/html/cron.php >>/var/log/nextcloud-cron.log 2>&1

۵. لاگ را بررسی کنید

بعد از چند دقیقه لاگ را ببینید:

sudo tail -n 20 /var/log/nextcloud-cron.log

اگر هیچ خطایی نبینید، خوب است؛ cron.php در حالت موفق معمولاً خروجی تولید نمی‌کند. اگر خطای Could not open input file یا Permission denied دیدید، به مرحله قبل برگردید. برای اطمینان بیشتر، همان دستور داخل کران را یک بار دستی در shell اجرا کنید و کد خروج را ببینید.

چطور مطمئن شویم مشکل واقعاً حل شده است

  • دستور دستی docker exec -u www-data nextcloud php -f /var/www/html/cron.php با کد خروج ۰ تمام می‌شود.
  • خروجی occ config:app:get core backgroundjobs_mode برابر cron است.
  • پس از ۵ تا ۱۰ دقیقه، هشدار «Last background job execution ran ...» در پنل ادمین پاک می‌شود یا زمان آن به‌روز می‌شود.
  • در خروجی docker exec -u www-data nextcloud php occ background-job:list، ستون آخرین اجرا (last run) برای جاب‌های دوره‌ای به‌روز شده است و جاب‌ها با next run در گذشته انبار نمی‌شوند.
  • لاگ /var/log/nextcloud-cron.log بعد از چند چرخه خطای جدیدی ندارد.

اگر هشدار باقی ماند، اول مطمئن شوید کران روی هاست واقعاً اجرا می‌شود. با crontab -l -u root خط را ببینید و یک بار همان دستور را بدون redirect اجرا کنید. سپس بررسی کنید کانتینر با همین نام در حال اجراست و بعد از ری‌استارت‌ها نامش عوض نشده است.

پیشگیری و بهترین روش‌ها

  • در محیط production همیشه حالت background job را cron بگذارید. AJAX برای نصب‌های کوچک و کم‌ترافیک است و برای سرور واقعی قابل اتکا نیست.
  • کران Nextcloud را با کاربر www-data اجرا کنید، نه root. این کار از مالکیت نادرست فایل‌ها و خطاهای بعدی جلوگیری می‌کند.
  • خروجی کران را ذخیره کنید. اگر نمی‌خواهید لاگ دائمی داشته باشید، حداقل از logger استفاده کنید تا خطا در syslog دیده شود.
  • از نام ثابت کانتینر یا نام سرویس Compose استفاده کنید. اگر کانتینر را با نام تصادفی بالا می‌آورید، کران بعد از هر بازسازی می‌شکند.
  • بعد از هر آپدیت Nextcloud یا تغییر ایمیج، اجرای دستی cron.php و وضعیت هشدار ادمین را دوباره چک کنید.
  • برای لاگ کران logrotate تنظیم کنید تا فایل لاگ در بلندمدت دیسک را پر نکند.
  • در Kubernetes به‌جای کران هاست، یک CronJob با ایمیج Nextcloud و همان volume داده بسازید و دستور php -f /var/www/html/cron.php را با کاربر www-data اجرا کنید.

جمع‌بندی ساده است: Nextcloud در Docker به کرانی نیاز دارد که داخل همان کانتینر و با همان کاربر وب اجرا شود. اگر خط کران را از روی مستندات کپی کرده‌اید ولی مسیر را روی هاست اجرا می‌کنید، فقط هشدار ادمین را جا گذاشته‌اید. با یک docker exec -u www-data و ثبت خروجی، هم مشکل را پیدا می‌کنید و هم از تکرارش جلوگیری می‌کنید.

اشتراک‌گذاری:

نویسنده

تحریریه کلودیکپ

تیم محتوای کلودیکپ

تیم فنی و محتوای کلودیکپ؛ مهندسانی که هر روز با DevOps، Kubernetes و زیرساخت ابری کار می‌کنند و تجربه‌هایشان را اینجا می‌نویسند.

سوالات متداول

سوالات متداول این مقاله

نه. اجرای cron.php با root باعث می‌شود فایل‌های appdata، لاگ‌ها و previewها با مالک root ساخته شوند و بعداً www-data نتواند آن‌ها را بنویسد. همیشه از -u www-data استفاده کنید.

معمولاً خروجی کران را به /dev/null فرستاده‌اید و خطایی مثل Could not open input file یا Permission denied دیده نمی‌شود. نام کانتینر، مسیر cron.php، کاربر اجرا و حالت background:cron را دوباره بررسی کنید.

برای نصب‌های کوچک و کم‌ترافیک ممکن است کار کند، ولی قابل اتکا نیست. جاب‌های پس‌زمینه فقط با باز شدن صفحه اجرا می‌شوند و روی سرورهای production یا محیط‌هایی که بیشتر با API کار می‌کنند، صف جاب‌ها عقب می‌افتد.

ادامه مطالعه

مقالات مرتبط

رفع خطای no SASL authentication mechanisms در Postfix
ابزارهای Self-Hostedمتوسط

رفع خطای no SASL authentication mechanisms در Postfix

وقتی smtpd پورت ۵۸۷ با خطای «no SASL authentication mechanisms» بالا نمی‌آید، ریشه معمولاً سوکت Dovecot است که داخل chroot پست‌فیکس ساخته نشده. این مقاله علت و راه‌حل کامل را قدم‌به‌قدم بررسی می‌کند.

تحریریه کلودیکپ ۶ دقیقه مطالعه
رفع dkim=none در Postfix با راه‌اندازی OpenDKIM
ابزارهای Self-Hostedمتوسط

رفع dkim=none در Postfix با راه‌اندازی OpenDKIM

اگر ایمیل‌های سرور Postfix شما در Gmail به اسپم می‌روند و هدر پیام dkim=none نشان می‌دهد، یعنی هیچ امضای DKIM روی پیام‌ها درج نمی‌شود. در این مقاله OpenDKIM را نصب، پیکربندی و به Postfix وصل می‌کنیم و رکورد DNS را منتشر می‌کنیم.

تحریریه کلودیکپ ۶ دقیقه مطالعه

در پیاده‌سازی به کمک نیاز دارید؟

تیم کلودیکپ همین کار را هر روز برای تیم‌های دیگر انجام می‌دهد. اگر جایی گیر کرده‌اید، با ما صحبت کنید.