پیغام could not be opened in append mode کنار عبارت Permission denied برای فایل storage/logs/laravel.log از اولین پیغام‌هایی است که بعد از استقرار لاراول روی سرور در لاگ می‌بینید. روی لپ‌تاپ، php artisan serve با کاربر خودتان اجرا می‌شود و هشت مورد زیر را پنهان می‌کند.

  • ✅ ۱. نسخه PHP و افزونه‌های پروژه؛ اگر نباشد: Composer متوقف می‌شود.
  • ✅ ۲. وابستگی‌ها و build فرانت؛ اگر نباشد: خطای Vite manifest.
  • ✅ ۳. فایل .env ویرایش‌شده با کلید؛ اگر نباشد: SQLite و حالت debug.
  • ✅ ۴. بلوک Nginx با ریشه public و سوکت درست؛ اگر نباشد: خطای 403 یا 502.
  • ✅ ۵. پوشه storage کامل و قابل نوشتن؛ اگر نباشد: خطای 500 فوری.
  • ✅ ۶. پردازشگر صف زیر نظر Supervisor؛ اگر نباشد: Jobها در صف می‌مانند.
  • ✅ ۷. یک خط کرون برای schedule:run؛ اگر نباشد: زمان‌بندی اجرا نمی‌شود.
  • ✅ ۸. کش تازه و ریستارت صف؛ اگر نباشد: اجرای تنظیم یا کد کهنه.

💡 PHP 8.3 و یک پیش‌شرط شبکه

برای Laravel 13 دست‌کم PHP 8.3 لازم است.
مورد ۲ تنها بازرسی‌ای است که به بیرون از سرور گره خورده: Packagist و رجیستری npm. روی سرور داخل ایران این مورد را با راهنمای تحریم npm کنار هم تیک بزنید.

اگر همین حالا متن خطایی جلوی چشمتان است، بازرسی را از آخر شروع کنید: متن را در فهرست معکوس خطاها انتهای بخش کش بیابید تا شماره مورد معلوم شود.

استقرار لاراول روی سرور

سرور پیش از لاراول؛ نسخه PHP، افزونه‌ها و Composer

طبق مستندات Laravel 13، استقرار لاراول روی سرور دست‌کم به PHP 8.3 نیاز دارد، به‌همراه افزونه‌های Ctype، cURL، DOM، Fileinfo، Filter، Hash، Mbstring، OpenSSL، PCRE، PDO، Session، Tokenizer و XML. در Laravel 12 حداقل 8.2 است. Nginx، PHP-FPM و دیتابیس را آماده فرض کرده‌ایم؛ انتقال فایل و دیتابیس از هاست اشتراکی در راهنمای انتقال سایت به سرور مجازی آمده است.

بررسی افزونه‌ها از روی composer.lock (مورد ۱)

دستور check-platform-reqs PHP و افزونه‌های واقعی سرور را با نیاز پکیج‌ها مقایسه می‌کند و با --lock پیش از نصب هم جواب می‌دهد. هر ردیف missing یک افزونه نصب‌نشده است.

composer check-platform-reqs --lock --no-dev

وابستگی‌ها و build فرانت (مورد ۲)

در مستندات Composer، --no-dev پکیج‌های require-dev را کنار می‌گذارد و --optimize-autoloader، که برای Production توصیه شده، PSR-4 را به classmap تبدیل می‌کند. اگر پروژه Vite دارد، بدون npm run build صفحه با Vite manifest not found می‌ایستد.

composer install --no-dev --optimize-autoloader
npm ci && npm run build

فایل محیط (.env) و کلید برنامه (مورد ۳)

نمونه .env.example در Laravel 13 با APP_ENV=local، APP_DEBUG=true و DB_CONNECTION=sqlite می‌آید. بدون ویرایش، migrate --force بی‌صدا فایل SQLite می‌سازد و debug روشن به گفته مستندات ممکن است تنظیمات حساس را نشان دهد. APP_KEY خالی هم پیغام No application encryption key has been specified. می‌دهد.

cp .env.example .env        # فقط در استقرار اول
nano .env
# APP_ENV=production  APP_DEBUG=false  APP_URL=https://example.com
# DB_CONNECTION=mysql  DB_HOST  DB_DATABASE  DB_USERNAME  DB_PASSWORD
php artisan key:generate    # فقط وقتی APP_KEY خالی است

کلید برنامه‌ای را که کاربر دارد عوض نکنید؛ نشست‌ها بسته می‌شوند و داده رمزشده قبلی باز نمی‌شود. migrate در مورد ۸ اجرا می‌شود.

سرور پیش از لاراول؛ نسخه PHP، افزونه‌ها و Composer

پوشه public، مجوز storage و بلوک Nginx را درست بچینید

وب‌سرور Nginx فقط باید پوشه public را ببیند و PHP-FPM باید در storage و bootstrap/cache بنویسد؛ این دو شرط در استقرار لاراول روی سرور جلوی بیشتر خطاهای 403 و 500 را می‌گیرند. مستندات لاراول می‌گوید index.php را به ریشه پروژه نبرید، وگرنه فایل‌های حساس پیکربندی باز می‌شوند.

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

خط‌های حیاتی بلوک Nginx (مورد ۴)

بلوک کامل، با هدرهای امنیتی و بافر FastCGI، در مستندات لاراول است؛ کد زیر بخش پرخطای آن است. بدون index index.php صفحه اصلی 403 می‌دهد و fastcgi_pass باید همان سوکت خط listen استخر PHP-FPM باشد. دو بلوک آخر فایل‌های PHP دیگر و فایل‌های نقطه‌دار مثل .env را می‌بندند؛ بعد از هر تغییر sudo nginx -t بزنید.

# بخشی از بلوک server
root /srv/example.com/public;
index index.php;

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

location ~ ^/index\.php(/|$) {
    fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
    include fastcgi_params;
}

location ~ \.php$ {
    return 404;
}

location ~ /\.(?!well-known).* {
    deny all;
}

مالک کد و مالک storage (مورد ۵)

با PHP-FPM، نویسنده storage کاربر خط user فایل pool است که مستندات PHP-FPM آن را «کاربر یونیکس پروسه‌های FPM» می‌نامد. دستور اول فقط ردیف‌های pool را نشان می‌دهد؛ در مثال www-data فرض شده.

بقیه کد مال یک کاربر استقرار (مثلاً deploy) عضو گروه www-data باشد. git و composer را با همین کاربر و artisan را با sudo -u www-data اجرا کنید تا فایلی با مالک root ساخته نشود.

ps -eo user,args | grep "[p]ool"
sudo usermod -aG www-data deploy
mkdir -p storage/framework/{cache,sessions,views}
sudo chown -R www-data:www-data storage bootstrap/cache
sudo chmod -R ug+rwX storage bootstrap/cache

⚠️ سراغ chmod 777 نروید

عدد 777 خطا را برطرف می‌کند، ولی به هر پروسه روی سرور اجازه نوشتن می‌دهد. اسکریپت آلوده‌ای روی همان سرور می‌تواند در ویوهای کامپایل‌شده شما کد بنویسد.

مورداگر جا بیفتدنشانه در لاگ
۴: خط indexصفحه اصلی 403پیغام directory index of … is forbidden
۴: سوکت fastcgi_passهمه صفحه‌ها 502پیغام connect() to unix:… failed
۵: مالکیت storageخطای 500پیغام could not be opened in append mode
۵: نبودن storage/frameworkویوها کامپایل نمی‌شوند؛ پوشه را بسازیدپیغام Please provide a valid cache path.

صف و زمان‌بندی؛ اگر Supervisor و کرون نباشند چه چیزی از کار می‌افتد

هر Job تا پردازش با queue:work در صف می‌ماند. مستندات صف لاراول اتصال پیش‌فرض صف را database گذاشته است؛ اگر بعد از استقرار لاراول روی سرور ایمیل‌ها را با صف می‌فرستید، بدون پردازشگر فقط جدول jobs پر می‌شود.

پردازشگر صف زیر نظر Supervisor (مورد ۶)

پروسه queue:work با تمام شدن --max-time یا با queue:restart متوقف می‌شود و Supervisor دوباره اجرایش می‌کند. نصب روی Ubuntu با sudo apt-get install supervisor است. نمونه زیر از مستندات لاراول است؛ آن را با پسوند .conf در /etc/supervisor/conf.d ذخیره کنید.

; /etc/supervisor/conf.d/laravel-worker.conf
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /srv/example.com/artisan queue:work --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
numprocs=2
redirect_stderr=true
stdout_logfile=/srv/example.com/storage/logs/worker.log
stopwaitsecs=3600

هر پروسه‌ای که numprocs می‌سازد یک PHP کامل در حافظه است. stopwaitsecs باید از طولانی‌ترین Job بیشتر باشد، وگرنه Supervisor ممکن است کار را نیمه‌کاره متوقف کند. سپس:

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start "laravel-worker:*"

یک خط کرون برای زمان‌بندی (مورد ۷)

دستور schedule:run، به گفته مستندات زمان‌بندی لاراول، هر دقیقه کارهای موعددار را اجرا می‌کند. خط زیر را با sudo crontab -u www-data -e اضافه کنید و با php artisan schedule:list وارسی کنید.

* * * * * cd /srv/example.com && php artisan schedule:run >> /dev/null 2>&1
مورداگر جا بیفتدنشانه در لاگ
۶: Supervisorایمیل صف‌شده نمی‌رسدفایل worker.log خالی یا ساخته‌نشده
۶: پسوند .confپیغام no such groupپردازشگر هرگز اجرا نشده
۷: کرونکار زمان‌بندی‌شده اجرا نمی‌شودلاگی نیست، چون چیزی اجرا نشده

صف و زمان‌بندی؛ اگر Supervisor و کرون نباشند چه چیزی از کار می‌افتد

کش پیکربندی در Production کمک است یا دردسر؟

حکم کوتاه است: کش کمک است، اگر بعد از هر تغییر .env دوباره ساخته شود. php artisan optimize کش پیکربندی، رویدادها، مسیرها و ویوها را می‌سازد و مستندات آن را بخشی از هر بار استقرار لاراول روی سرور می‌داند.

🔸 چرا تغییر فایل محیط (.env) بعد از config:cache دیده نمی‌شود

بعد از config:cache، لاراول .env را بار نمی‌کند و env() برای متغیرهایش null برمی‌گرداند. env() را فقط در فایل‌های config بنویسید و در بقیه کد config() را به کار ببرید.

ترتیب دستورها در پایان هر استقرار (مورد ۸)

# در پوشه پروژه، با کاربر deploy
sudo -u www-data php artisan down
git pull
composer install --no-dev --optimize-autoloader
npm ci && npm run build
# پیش از migrate از دیتابیس بکاپ بگیرید
sudo -u www-data php artisan migrate --force
sudo -u www-data php artisan optimize
sudo -u www-data php artisan queue:restart
sudo -u www-data php artisan up

⚠️ پردازشگر صف کد قدیمی را نگه می‌دارد

پروسه‌های queue:work تا ریستارت نشوند کد تازه را نمی‌بینند. queue:restart آن‌ها را بعد از Job فعلی خارج می‌کند و Supervisor با کد جدید اجرایشان می‌کند؛ این سیگنال در کش ذخیره می‌شود.

🔶 تمرین استقرار روی سیستم‌عامل تازه

چک‌لیست را پیش از بردن دامنه روی سرور خالی تمرین کنید؛ نصب مجدد سیستم‌عامل از پنل سرور مجازی وب‌داده هر دور را از صفر شروع می‌کند.

فهرست معکوس؛ از متن خطا به شماره مورد

  • ایراد Composer به نسخه PHP یا افزونه ext- ← مورد ۱
  • پیغام Vite manifest not found ← مورد ۲
  • پیغام No application encryption key has been specified. یا فایل SQLite ناخواسته ← مورد ۳
  • خطای 403، 502 یا متن File not found. ← مورد ۴
  • پیغام could not be opened in append mode یا Please provide a valid cache path. (پوشه نیست) ← مورد ۵
  • پر شدن جدول jobs یا no such group ← مورد ۶
  • اجرا نشدن کارهای زمان‌بندی‌شده ← مورد ۷
  • مقدار null از env() یا Job با کد کهنه ← مورد ۸

سایت بالاست، اما ایمیلی نرسیده یا تنظیمی اثر نکرده است؛ این‌ها گرفتاری‌های هفته اول بعد از راه‌اندازی‌اند.

بعد از ویرایش فایل محیط (.env) چه دستوری باید بزنم؟

اگر کش پیکربندی دارید، php artisan optimize را دوباره اجرا کنید و صف را ریستارت کنید؛ تا آن موقع مقدار کش قبلی خوانده می‌شود.

فایلی که آن دستور ساخته مالک root دارد و PHP-FPM در آن نمی‌نویسد. مالکیت storage را برگردانید و artisan را با sudo -u www-data اجرا کنید.

مسیر سلامت پیش‌فرض لاراول /up است؛ اگر برنامه بدون خطا بوت شود 200 و در غیر این صورت 500 برمی‌گرداند.

اگر فایل‌های آپلودی دیسک public باید از وب باز شوند، بله؛ این دستور public/storage را به storage/app/public پیوند می‌دهد.

هر Job ناموفق در جدول failed_jobs ثبت می‌شود. php artisan queue:failed شناسه‌ها را نشان می‌دهد و queue:retry با شناسه، Job را به صف برمی‌گرداند.

عدد ثابتی در کار نیست، هرچند همه دنبالش‌اند. با یک یا دو پروسه شروع کنید و با دیدن مصرف رم، numprocs را بالا ببرید.

اول ببینید خطا 403 است یا timeout؛ هر دو حالت در راهنمای کادر پایین آمده‌اند.

جمع‌بندی؛ استقرار لاراول روی سرور با هشت بازرسی خطاهای روز اول از چیزهایی می‌آیند که روی لپ‌تاپ نبودند. نسخه PHP را با check-platform-reqs بسنجید، وابستگی‌ها را بدون پکیج توسعه نصب کنید و فرانت را build کنید. فایل .env را پیش از migrate با APP_ENV=production، APP_DEBUG=false و اطلاعات دیتابیس ویرایش کنید. ریشه Nginx را روی public بگذارید، کد را به کاربر استقرار و storage را به کاربر PHP-FPM بسپارید. صف را به Supervisor و زمان‌بندی را به کرون بدهید. در پایان هر استقرار، کش را با optimize بسازید و صف را ریستارت کنید. خطای تازه را با فهرست معکوس بسنجید.

🚀 نصب پکیج روی سرور ایران متوقف شده؟

مورد ۲ به Packagist و npm وابسته است؛ فرق 403 با timeout روی سرور داخل ایران و تنظیم میرور در یک راهنما آمده‌اند.

اولین خطایی که بعد از بردن پروژه لاراول به سرور دیدید چه بود؟ متن دقیقش را در دیدگاه‌ها بگذارید تا فهرست معکوس کامل‌تر شود.

منابع

وب داده
وب داده

جدید ترین مطالب آموزشی و کاربردی را در اینجا بخوانید !
ما با بهره‌گیری از دانش روز و تجربه متخصصان حوزه فناوری، مجموعه‌ای از آموزش‌های کاربردی و مقالات تخصصی را گردآوری کرده‌ایم که هر یک، پاسخی دقیق به پرسش‌های شماست. ؛ از مفاهیم پایه تا پیچیده‌ترین تکنیک‌های حرفه‌ای. اینجا، دانش با زبانی ساده اما عمیق در اختیار شما قرار می‌گیرد.

مقاله‌ها: 261
پاسخی بگذارید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *