آموزش نصب LAMP stack در Ubuntu 24.04 با PHP-FPM
راهنمای گامبهگام نصب Apache، MariaDB و PHP 8.3 روی Ubuntu 24.04. یاد بگیرید چگونه مشکل نمایش سورسکد، خطای unix_socket و تنظیمات صحیح vhost را با دستورات دقیق حل کنید.
آنچه در حال ساخت آن هستید
یک LAMP stack شامل چهار بخش متحرک روی یک سرور Ubuntu 24.04 است: Linux در لایه زیرین، Apache برای پاسخدهی به درخواستهای HTTP، MariaDB برای نگهداری دادهها و PHP 8.3 برای اجرای کدها. در پایان این راهنما، شما یک virtual host مبتنی بر نام خواهید داشت که یک دایرکتوری برنامه واقعی را سرویسدهی میکند، یک دیتابیس با یک کاربر اختصاصی با حداقل سطح دسترسی، PHP که از طریق PHP-FPM به Apache متصل شده است و یک گواهی رایگان Let's Encrypt که روی همه اینها قرار گرفته است.
نصب اصلی تنها شامل چهار دستور apt است. تقریباً تمام مطالب این راهنما مربوط به نحوه اتصال این قطعات به یکدیگر و رفع اشتباهات کوچکی است که باعث میشوند یک stack تازه نصبشده، یک صفحه خالی نمایش دهد، سورسکد شما را به جای اجرا به عنوان فایل دانلودی به مرورگر بفرستد، یا اجازه ورود به دیتابیسی که همین الان نصب کردهاید را ندهد. هر یک از این مشکلات نشانهای دارند که میتوانید آن را شناسایی کنید و هر کدام در ادامه با متن دقیق خطایی که مشاهده خواهید کرد، نامگذاری شدهاند.
پیشنیازها و نکات مهم
فرض کنید یک VPS با سیستمعامل Ubuntu 24.04 و مجازیساز KVM در اختیار دارید که به یک کاربر با دسترسی sudo یا root و یک آدرس IPv4 عمومی مجهز است. یک پشته (stack) حداقلی با 1 گیگابایت رم اجرا میشود؛ اما پیش از اجرای یک برنامه واقعی که از دیتابیس استفاده میکند، آن را به 2 گیگابایت ارتقا دهید، زیرا بافرهای پیشفرض MariaDB به همراه تعدادی worker در PHP-FPM بهسرعت گیگابایت اول را اشغال میکنند.
پیش از آنکه در انتهای کار Certbot بهدرستی عمل کند، باید دو شرط برقرار باشد؛ پس از همین حالا آنها را آماده کنید. شما به یک نام دامنه نیاز دارید که رکورد A آن به آدرس IP عمومی VPS اشاره کند. Let's Encrypt اعتبار دامنه را از طریق HTTP بررسی میکند و یک آدرس IP خام هرگز نمیتواند گواهی دریافت کند. همچنین پورتهای 80 و 443 باید از طریق اینترنت در دسترس باشند؛ این یعنی در بسیاری از سرویسدهندهها، باید علاوه بر تنظیمات داخل سرور در ufw، این پورتها را در فایروال شبکه پنل کاربری نیز باز کنید. اعمال تغییرات DNS ممکن است تا یک ساعت زمان ببرد، بنابراین رکورد A را از ابتدا تنظیم کنید تا زمانی که به آن نیاز دارید، فعال شده باشد.
گام 1 - نصب Apache و تأیید صفحه پیشفرض
sudo apt update
sudo apt install -y apache2apt سرویس را برای شما اجرا و فعال میکند. وضعیت آن را بررسی کنید:
systemctl status apache2شما باید خطی را ببینید که active (running) را نشان میدهد. اکنون http://YOUR_SERVER_IP/ را در مرورگر باز کنید. مشاهده Apache2 Ubuntu Default Page با بنر بزرگ "It works!" نتیجه صحیح است؛ این نشان میدهد که Apache در حال سرویسدهی است و خطایی وجود ندارد. آن صفحه در /var/www/html/index.html قرار دارد و توسط virtual host پیشفرض یعنی 000-default.conf ارائه میشود. شما بعداً هر دو را غیرفعال خواهید کرد؛ اما در حال حاضر، مشاهده آنها دقیقاً همان چیزی است که نیاز دارید.
اگر صفحه اصلاً بارگذاری نمیشود اما systemctl میگوید که پردازش در حال اجراست، یک فایروال مانع کار است. این موضوع گام بعدی ماست.
گام 2 - باز کردن فایروال برای HTTP و HTTPS
بسته apache2 سه پروفایل برنامه ufw را ثبت میکند. آنها را لیست کنید:
sudo ufw app listشما Apache، Apache Full و Apache Secure را مشاهده خواهید کرد. Apache فقط برای پورت 80 است، Apache Secure فقط برای 443 است و Apache Full هر دو را شامل میشود؛ این همان گزینهای است که به آن نیاز دارید، زیرا در انتها TLS را اضافه میکنید.
sudo ufw allow OpenSSH
sudo ufw allow "Apache Full"
sudo ufw enableپیش از اجرای ufw enable، اجازه دسترسی OpenSSH را صادر کنید. ufw بهطور پیشفرض تمام ترافیک ورودی را مسدود میکند و فعالسازی آن بدون قانون SSH، بلافاصله پس از فعال شدن، اتصال شما را قطع میکند؛ در این حالت نشست فعلی حفظ میشود اما دیگر قادر به اتصال مجدد نخواهید بود. با sudo ufw status تأیید کنید؛ شما میخواهید OpenSSH، Apache Full و معادلهای v6 آنها همگی وضعیت ALLOW را نشان دهند.
گام 3 - نصب MariaDB و ایمنسازی آن
sudo apt install -y mariadb-server
systemctl status mariadbنسخه Ubuntu 24.04 شامل MariaDB 10.11 است که یک نسخه با پشتیبانی طولانیمدت (LTS) محسوب میشود، بنابراین نیازی به استفاده از مخازن خارجی ندارید. پس از اجرای سرویس، آن را مقاومسازی کنید:
sudo mysql_secure_installationتوصیه میشود به جای فشردن سریع کلید Enter، پرسشهای نمایشدادهشده را مطالعه کنید. هنگامی که از شما current root password خواسته میشود، کلید Enter را بزنید، زیرا هنوز رمزی تعیین نشده است. در پاسخ به "Switch to unix_socket authentication?"، پاسخ شما تغییری ایجاد نمیکند زیرا این قابلیت بهصورت پیشفرض در این بسته فعال است، پس n را وارد کنید. برای پرسش "Change the root password?"، گزینه n را انتخاب کنید (دلیل آن در پاراگراف بعدی آمده است)، سپس برای سایر موارد پاسخ Y را وارد کنید: حذف کاربران ناشناس، غیرفعال کردن ورود از راه دور کاربر root، حذف دیتابیس تست و بارگذاری مجدد جداول دسترسی.
این بخشی است که معمولاً باعث سردرگمی میشود. در نسخه MariaDB روی Ubuntu، حساب کاربری دیتابیس root از احراز هویت unix_socket استفاده میکند، نه رمز عبور. این یعنی دیتابیس به کاربری که در سیستمعامل با آن احراز هویت کردهاید، اعتماد میکند. بنابراین، دستور زیر از یک shell با دسترسی root کار میکند:
sudo mysql...و شما را بدون درخواست رمز عبور به محیط MariaDB [(none)]> وارد میکند. اجرای همین دستور توسط یک کاربر بدون دسترسیهای ویژه رد میشود، که دقیقاً هدف اصلی همین است: دسترسی به کاربر root دیتابیس به دسترسی sudo در سیستم گره خورده است و هیچ رمز عبوری برای سرقت، فیشینگ یا حملات brute-force وجود ندارد. این روش از رمز عبور امنتر است، پس آن را تغییر ندهید. قاعدهای که از این موضوع نتیجه میشود این است: هرگز یک برنامه را به حساب کاربری root متصل نکنید. برای هر برنامه یک کاربر اختصاصی ایجاد کنید (گام 7)، زیرا برنامهای که از طریق TCP و با نام کاربری و رمز عبور متصل میشود، به هر حال نمیتواند از احراز هویت socket استفاده کند و شما میخواهید هر برنامه تنها به دیتابیس خودش محدود باشد.
گام 4 - نصب PHP 8.3 به همراه PHP-FPM
نسخه پیشفرض PHP در Ubuntu 24.04 برابر با 8.3 است. مدیر پردازش FPM و افزونههایی که یک برنامه معمولی به آنها نیاز دارد را نصب کنید:
sudo apt install -y php8.3-fpm php8.3-mysql php8.3-cli \
php8.3-curl php8.3-xml php8.3-mbstring php8.3-zipدقت کنید چه چیزی در این لیست وجود ندارد: libapache2-mod-php. آن بسته قدیمی، یک مفسر PHP را درون هر پردازش Apache جاسازی میکند. این روش ساده است، اما هر worker یک کپی از PHP را با خود حمل میکند، چه در حال سرویسدهی به یک اسکریپت باشد و چه یک تصویر ثابت؛ علاوه بر این، هر دو چرخه حیات مشترکی دارند و فقط با prefork MPM در Apache کار میکند که ناکارآمدترین حالت است. در مقابل، PHP-FPM، زبان PHP را به عنوان مجموعهای از پردازشهای مستقل اجرا میکند که Apache از طریق یک socket با آنها ارتباط برقرار میکند. در این حالت، Apache میتواند از event MPM که مبتنی بر thread است برای فایلهای ثابت استفاده کند و فقط درخواستهای PHP را به FPM بفرستد. این pool بهطور مستقل از وبسرور تنظیم میشود و اگر بعداً بخواهید از nginx در لایه جلویی استفاده کنید، دقیقاً همین تنظیمات FPM کار خواهد کرد. این روش به دلایل موجه، استاندارد فعلی است.
Apache از طریق ماژول proxy_fcgi به FPM متصل میشود. آن را فعال کنید، پیکربندیای که بسته FPM اضافه کرده است را فعال نمایید و سرویس را restart کنید:
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.3-fpm
sudo systemctl restart apache2a2enconf php8.3-fpm دستور /etc/apache2/conf-available/php8.3-fpm.conf را فعال میکند که حاوی قوانینی برای هدایت فایلهای PHP به socket مربوط به FPM است. هسته اصلی این تنظیمات، هر فایل .php را شناسایی کرده و آن را به socket موجود در /run/php/php8.3-fpm.sock ارسال میکند:
<FilesMatch ".+\.ph(ar|p|tml)$">
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost"
</FilesMatch>نیازی به ویرایش این فایل نیست؛ تنظیمات پیشفرض آن صحیح است. اما دانستن مسیر socket به شما کمک میکند تا در آینده خطاهای «دانلود شدن فایل PHP به جای اجرا» و «Primary script unknown» را عیبیابی کنید؛ هر دوی این خطاها ناشی از عدم توافق Apache و FPM بر سر این socket یا فایل پشت آن هستند.
گام 5 - ایجاد یک virtual host مبتنی بر نام برای برنامه
میزبانی مجازی مبتنی بر نام (Name-based virtual hosting) به یک IP اجازه میدهد چندین سایت را میزبانی کند؛ Apache سایت مورد نظر را بر اساس هدر Host: در درخواست انتخاب میکند. یک دایرکتوری برای برنامه ایجاد کنید که خارج از مسیر پیشفرض /var/www/html باشد:
sudo mkdir -p /var/www/testapp
sudo chown -R www-data:www-data /var/www/testapp
sudo chmod -R 755 /var/www/testappمالکیت فایلها اهمیت دارد. در اوبونتو، Apache و PHP-FPM هر دو با کاربر www-data اجرا میشوند، بنابراین فایلهایی که وبسرور باید بخواند و دایرکتوریهایی که برنامه باید در آنها بنویسد (مانند پوشه uploads)، باید متعلق به www-data باشند. اگر قصد دارید فایلها را با کاربر لاگین خود ویرایش کنید، یک الگوی رایج این است که مالکیت فایلها را در اختیار خود بگیرید و کاربرتان را به گروه www-data اضافه کنید؛ برای یک استقرار ساده، www-data:www-data کمترین پیچیدگی را دارد.
فایل virtual host را در مسیر /etc/apache2/sites-available/testapp.conf ایجاد کنید:
<VirtualHost *:80>
ServerName app.example.com
DocumentRoot /var/www/testapp
<Directory /var/www/testapp>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/testapp-error.log
CustomLog ${APACHE_LOG_DIR}/testapp-access.log combined
</VirtualHost>مقدار ServerName را روی دامنه واقعی خود تنظیم کنید. Options -Indexes از نمایش لیست فایلهای دایرکتوری توسط Apache در صورت نبود فایل index جلوگیری میکند؛ در غیر این صورت، بازدیدکنندگان میتوانند ساختار فایلهای شما را مشاهده کنند. AllowOverride All اجازه میدهد فایل .htaccess کار کند، که اکثر برنامههای PHP برای داشتن URLهای زیبا به آن نیاز دارند؛ اگر برنامه شما به آن نیازی ندارد، برای افزایش جزئی سرعت، آن را روی None قرار دهید. این سایت را فعال کنید، سایت پیشفرض را غیرفعال کنید، پیکربندی را بررسی کرده و سرویس را reload کنید:
sudo a2ensite testapp
sudo a2dissite 000-default
sudo apache2ctl configtest
sudo systemctl reload apache2apache2ctl configtest باید عبارت Syntax OK را چاپ کند. خط a2dissite 000-default همان موردی است که معمولاً فراموش میشود و دلیل اصلی این است که صفحه پیشفرض همچنان نمایش داده میشود؛ برای رفع این مشکل به بخش خطاها مراجعه کنید.
گام 6 - اطمینان از اجرای PHP و سپس حذف فایل تست
یک فایل PHP تکخطی در ریشه برنامه ایجاد کنید:
echo "<?php phpinfo();" | sudo tee /var/www/testapp/info.phpبه http://app.example.com/info.php بروید. نتیجه صحیح، نمایش یک جدول طولانی بنفش و خاکستری با عنوان PHP Version 8.3.x است که ماژولهای بارگذاریشده شما را فهرست میکند؛ در این جدول، خط Server API باید مقدار FPM/FastCGI را نشان دهد. این خط تأیید میکند که درخواستها از طریق PHP-FPM پردازش میشوند، نه mod_php.
اکنون بلافاصله آن را حذف کنید:
sudo rm /var/www/testapp/info.phpphpinfo() نسخه دقیق PHP، تمامی افزونههای بارگذاریشده، مسیرهای فایل و جزئیات محیطی شما را فاش میکند؛ این اطلاعات برای هر کسی که در حال بررسی سرور برای یافتن حفرههای امنیتی شناختهشده است، یک هدیه محسوب میشود. این فایل صرفاً یک ابزار تست است، نه یک قابلیت. به محض مشاهده صفحه، آن را حذف کنید. اگر بهجای نمایش جدول، مرورگر شما پیشنهاد دانلود info.php را داد، به این معناست که PHP به درستی به Apache متصل نشده است؛ پیش از انجام هر کار دیگری، به بخش عیبیابی (failures) مراجعه کنید.
گام 7 - ایجاد پایگاه داده برنامه و یک کاربر با حداقل دسترسی
پایگاه داده را با کاربر root که از طریق سوکت احراز هویت میشود، باز کنید:
sudo mysqlسپس یک پایگاه داده و یک کاربر که دقیقاً به همان پایگاه داده محدود شده است، ایجاد کنید:
CREATE DATABASE appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;در اینجا سه انتخاب آگاهانه انجام شده است. utf8mb4 یک کدگذاری چهار بایتی واقعی UTF-8 است؛ نام مستعار قدیمی utf8 به صورت بیصدا ایموجیها و برخی کاراکترهای CJK را حذف میکند، بنابراین همیشه از utf8mb4 استفاده کنید. دسترسی (grant) روی appdb.* داده شده است، نه *.*: این کاربر فقط میتواند به پایگاه داده خود دسترسی داشته باشد و نه هیچ چیز دیگر؛ بنابراین یک حفره SQL-injection در برنامه نمیتواند جداول سایر سایتها را بخواند. و 'appuser'@'localhost' حساب کاربری را به اتصالاتی که از خودِ سرور منشاء میگیرند، محدود میکند.
آن را با همان کاربر تست کنید:
mysql -u appuser -p appdbاین دستور رمز عبور را میپرسد و شما را به یک پرامپت MariaDB [appdb]> هدایت میکند. توجه کنید که هیچ فلگ -h وجود ندارد؛ آن را حذف کنید تا کلاینت از طریق Unix socket محلی متصل شود، که دقیقاً همان چیزی است که MariaDB آن را localhost میشمارد. یک نکته مهم که باید بدانید: برای MySQL و MariaDB، عبارت localhost به معنای Unix socket و 127.0.0.1 به معنای اتصال TCP است. در یک نسخه پیشفرض MariaDB روی Ubuntu 24.04، سرور همچنان اتصال TCP از 127.0.0.1 را به localhost ترجمه میکند، بنابراین هر دو با حساب کاربری مطابقت دارند. اما در سرورهایی که skip-name-resolve فعال است (یک ترفند رایج برای بهبود عملکرد و استاندارد در بسیاری از ایمیجهای کانتینر)، این دو به عنوان میزبانهای متفاوت شناخته میشوند و برنامهای که به 127.0.0.1 متصل میشود، با خطای ERROR 1045 (28000): Access denied for user 'appuser'@'127.0.0.1' (using password: YES) مواجه خواهد شد، حتی اگر رمز عبور صحیح باشد.
بنابراین برنامه خود را به میزبان localhost، کاربر appuser و پایگاه داده appdb هدایت کنید و هرگز از root استفاده نکنید. در PHP، هر دو گزینه mysqli و PDO زمانی که میزبان رشته متنی localhost باشد، به استفاده از Unix socket تغییر وضعیت میدهند که با حسابی که تازه ایجاد کردید مطابقت دارد. اگر یک فریمورک اصرار بر استفاده از میزبان TCP عددی دارد، کاربر را مطابق با نحوه اتصال واقعی آن (یعنی 'appuser'@'127.0.0.1') ایجاد کنید، یا تنها در صورتی که نیاز است از ماشین دیگری به پایگاه داده دسترسی داشته باشد، از @'%' (همراه با یک قانون فایروال) استفاده کنید.
گام 8 - افزودن HTTPS با Certbot
ارسال فرم ورود از طریق HTTP ساده باعث میشود رمزهای عبور بهصورت متن آشکار (clear text) منتقل شوند و تمام مرورگرهای مدرن این صفحات را بهعنوان "Not secure" علامتگذاری میکنند. Certbot این مشکل را با یک دستور حل میکند. آن را به همراه پلاگین Apache نصب کنید:
sudo apt install -y certbot python3-certbot-apache
sudo certbot --apacheCertbot در اینجا از دو پلاگین استفاده میکند. apache authenticator با ارائهٔ موقت یک فایل چالش (challenge file) از طریق Apache در حال اجرا، ثابت میکند که شما دامنه را در اختیار دارید و apache installer سپس virtual host شما را بازنویسی میکند تا بلوک 443 را اضافه کند، آن را به گواهی جدید ارجاع دهد و بهطور پیشفرض تمام ترافیک HTTP را به HTTPS هدایت کند. از نسخه Certbot 2.0 به بعد، دیگر سوالی مبنی بر هدایت (redirect) پرسیده نمیشود؛ اگر نیاز دارید همچنان HTTP ساده را ارائه دهید، از پرچم --no-redirect استفاده کنید. از آنجا که در گام 5 یک ServerName واقعی تنظیم کردهاید، Certbot دامنه را بهطور خودکار شناسایی میکند. گواهیها 90 روز اعتبار دارند و این بسته یک systemd timer نصب میکند که آنها را تمدید میکند؛ تایمر را با sudo certbot renew --dry-run بررسی کنید که باید به Congratulations, all simulated renewals succeeded ختم شود.
برای مشاهدهٔ راهنمای کامل چالش، تایمر تمدید، و الزامات DNS و فایروال، به راهنمای مکمل در صدور گواهیهای رایگان Let's Encrypt TLS با Certbot روی Apache مراجعه کنید.
پشتیبانگیری، ارتقا و ایمنسازی
از دو موردی که وضعیت (state) شما را حفظ میکنند پشتیبان بگیرید: پایگاههای داده و دایرکتوری ریشه وب (web root). یک dump منطقی شبانه، سادهترین روش قابلاطمینان است، sudo sh -c 'mysqldump --all-databases --single-transaction | gzip > /root/db-$(date +%F).sql.gz'، که سپس از سرور به خارج منتقل میشود. قرار دادن کل این خط لوله در sudo sh -c اهمیت دارد: بدون آن، شل دستور redirect مربوط به > /root/... را با کاربر فعلی شما اجرا میکند و با خطای Permission denied مواجه میشود، زیرا فقط mysqldump دسترسی sudo را به ارث برده است. --single-transaction یک snapshot منسجم از جداول InnoDB بدون قفل کردن آنها ارائه میدهد. آن را با یک tar از /var/www و /etc/apache2/sites-available ترکیب کنید تا بتوانید کل پشته (stack) را روی یک VPS جدید از روی همان فایلها بازسازی کنید.
ارتقاها یک sudo apt update && sudo apt upgrade معمولی هستند. موردی که دردسرساز میشود، تغییر نسخه PHP است؛ زمانی که یک نسخه آینده Ubuntu پیشفرض را به PHP 8.4 تغییر میدهد، apt ممکن است php8.4-fpm را در کنار 8.3 نصب کند، سوکت به /run/php/php8.4-fpm.sock تغییر یابد و پیکربندی Apache شما همچنان به سوکت 8.3 اشاره کند. پیکربندی جدید را فعال (sudo a2enconf php8.4-fpm) و قدیمی را غیرفعال کنید، در غیر این صورت سایت شما پس از یک ارتقای معمول، خطای Primary script unknown برمیگرداند. از آنجا که انتشار نسخههای PHP سریعتر از توزیعهای LTS است، به جای ثابت نگه داشتن یک نسخه patch، یادداشتهای انتشار فعلی PHP را بررسی کنید.
دو گام ایمنسازی ارزش انجام در روز اول را دارند. نخست، نظارت Fail2Ban بر SSH را روی سرور فعال کنید؛ یک VPS عمومی در عرض چند دقیقه با تلاشهای خودکار ورود مواجه میشود و یک jail کوچک، هزاران تلاش را پیش از مسدودسازی به تعداد انگشتشماری کاهش میدهد. دوم، اگر ترجیح میدهید virtual hostهای Apache، پایگاههای داده MariaDB و کاربران را به جای ویرایش دستی فایلها از طریق مرورگر مدیریت کنید، پنل کنترل تحت وب Webmin روی همین پشته قرار میگیرد و همان فایلهای پیکربندی که نوشتید را مدیریت میکند. هیچکدام جایگزین درک اجزا نمیشوند، اما هر دو اصطکاک کارهای روزمره را کاهش میدهند.
حالتهای شکست و پیامهای مرتبط
صفحه پیشفرض حذف نمیشود. شما virtual host خود را ویرایش و reload کردهاید، اما مرورگر همچنان "Apache2 Ubuntu Default Page" و بنر "It works!" را نشان میدهد. Apache اولین virtual host منطبق را سرو میکند و وقتی هیچ ServerName با درخواست مطابقت ندارد، فایلی که از نظر الفبایی اول است برنده میشود؛ 000-default.conf پیش از testapp.conf قرار میگیرد. یا نام میزبان در درخواست با ServerName شما مطابقت ندارد، یا دستور sudo a2dissite 000-default را اجرا نکردهاید. فایل پیشفرض را با sudo systemctl reload apache2 غیرفعال کنید و با apache2ctl -S تأیید کنید؛ این دستور نقشه vhost را چاپ کرده و نشان میدهد کدام پیکربندی مالک صفحه پیشفرض است. کش مرورگر را نیز پاک کنید؛ یک پاسخ 200 کششده از صفحه قدیمی همچنان باقی میماند.
فایل .php به جای اجرا شدن، دانلود میشود. شما info.php را باز میکنید و مرورگر به جای اجرای کد، فایلی حاوی سورس <?php را دانلود میکند یا آن را به صورت متن ساده نمایش میدهد. Apache فایل را به عنوان یک دارایی ایستا (static asset) سرو میکند زیرا هندلر PHP متصل نشده است، شما sudo a2enmod proxy_fcgi یا sudo a2enconf php8.3-fpm را نادیده گرفتهاید، یا پس از آن Apache را restart نکردهاید. هر سه دستور (مرحله 4) را اجرا کرده و reload کنید. بارگذاری ماژول را با apache2ctl -M | grep fcgi تأیید کنید که باید proxy_fcgi_module را لیست کند. این یک نشت سورسکد است، نه یک خطای ظاهری؛ بنابراین پیش از قرار دادن هر محتوای واقعی روی سرور، آن را اصلاح کنید.
ERROR 1698 (28000): Access denied for user 'root'@'localhost'. شما mysql -u root یا mariadb -u root را بدون sudo اجرا کردهاید. حساب root از احراز هویت unix_socket استفاده میکند، بنابراین فقط زمانی شما را میپذیرد که کاربر سیستمعامل شما در واقع root باشد. راهحل استفاده از sudo mysql است، بدون -u root و بدون رمز عبور. این پیام رفتار مورد انتظار احراز هویت سوکتی است که به درستی کار میکند، نه یک نصب ناقص.
ERROR 1045 (28000): Access denied for user 'appuser'@'127.0.0.1' از سمت برنامه، با رمز عبور صحیح. حساب کاربری به عنوان 'appuser'@'localhost' وجود دارد، اما برنامه شما از طریق TCP به 127.0.0.1 روی سروری متصل میشود که در آن تفکیک نام میزبان غیرفعال است (skip-name-resolve)؛ بنابراین MariaDB این دو را به عنوان میزبانهای متفاوت در نظر میگیرد؛ localhost سوکت یونیکس است و 127.0.0.1 پروتکل TCP. برنامه را به میزبان localhost هدایت کنید تا از سوکت استفاده کرده و با حساب کاربری مطابقت پیدا کند، یا اگر فریمورک فقط با TCP کار میکند، یک حساب دوم به نام 'appuser'@'127.0.0.1' ایجاد کنید.
AH01071: Got error 'Primary script unknown' در /var/log/apache2/testapp-error.log، در حالی که مرورگر File not found. را نشان میدهد. Apache درخواست را به PHP-FPM تحویل داده، اما FPM نتوانسته اسکریپت را در مسیری که Apache داده پیدا کند. دو دلیل معمول وجود دارد: سوکت FPM در پیکربندی شما به نسخه PHP اشاره دارد که نصب نشده است (یک سوکت php8.4 پس از ارتقا در حالی که فقط 8.3 اجرا میشود)، یا فایل واقعاً در آنجا نیست زیرا DocumentRoot و دایرکتوری واقعی با هم اختلاف دارند. وجود سوکت را با ls -l /run/php/ بررسی کنید، تأیید کنید که DocumentRoot با محل قرارگیری فایل مطابقت دارد و هر دو سرویس php8.3-fpm و apache2 را restart کنید.
AH00558: apache2: Could not reliably determine the server's fully qualified domain name در هر بار restart. این یک هشدار بیخطر است، نه یک خطا؛ Apache به شما میگوید که هیچ ServerName سراسری تنظیم نشده است. با نوشتن ServerName your.domain در /etc/apache2/conf-available/servername.conf و اجرای sudo a2enconf servername، آن را بیصدا کنید.
(98)Address already in use: AH00072: make_sock: could not bind to address 0.0.0.0:80 هنگام شروع Apache. یک وبسرور دیگر قبلاً پورت 80 را اشغال کرده است، که اغلب یک nginx باقیمانده از آزمایشهای قبلی است. آن را با sudo ss -ltnp | grep :80 پیدا کنید، سپس پیش از شروع Apache، آن سرویس دیگر را متوقف و غیرفعال کنید.
FAQ
mod_php یا PHP-FPM - کدام را باید استفاده کنم؟
از PHP-FPM استفاده کنید. mod_php یک مفسر را در هر پردازش Apache جایگذاری میکند و شما را مجبور به استفاده از MPM کند و کندِ prefork میکند؛ بنابراین Apache حتی هنگام سرویسدهی به یک تصویر ثابت، سربار PHP را متحمل میشود. PHP-FPM، سرویس PHP را بهعنوان یک pool مجزا و با تنظیمات مستقل اجرا میکند که Apache از طریق یک socket به آن دسترسی دارد. این روش با MPM سریعتر و چندنخی (threaded) یعنی event سازگار است و بعداً بهراحتی به nginx منتقل میشود. این استاندارد مدرن است؛ mod_php تنها برای برنامههای قدیمی (legacy) که به رفتارهای خاص درونپردازشی وابسته هستند، منطقی است.
چرا مرورگر من بهجای اجرای فایل PHP، آن را دانلود میکند؟
Apache فایل .php را بهعنوان یک فایل دانلودی ثابت در نظر میگیرد، زیرا هیچ هندلر PHP به آن متصل نشده است. در Ubuntu 24.04 با استفاده از FPM، این یعنی شما یکی از دستورات sudo a2enmod proxy_fcgi، sudo a2enconf php8.3-fpm یا ریاستارت کردن Apache پس از آن را فراموش کردهاید. هر سه دستور را اجرا کنید و سرویس را reload کنید، سپس با apache2ctl -M | grep fcgi بررسی کنید که proxy_fcgi_module در لیست موجود باشد. تا زمانی که این مشکل را حل نکردهاید، سرور در حال نشت سورسکد است، پس آن را بهعنوان یک مورد فوری در نظر بگیرید.
چرا با وجود رمز عبور صحیح، دسترسی root در MariaDB رد میشود؟
به این دلیل که رمز عبوری وجود ندارد؛ MariaDB در Ubuntu حساب کاربری root را از طریق unix_socket احراز هویت میکند و آن را به کاربر root سیستمعامل گره میزند. دستور mysql -u root از یک shell معمولی، طبق طراحی، خطای ERROR 1698 (28000): Access denied for user 'root'@'localhost' را برمیگرداند. بهجای استفاده مجدد از root، با دستور sudo mysql متصل شوید و یک کاربر جداگانه با احراز هویت رمز عبور برای هر برنامه ایجاد کنید.
چگونه به سایت LAMP خود HTTPS اضافه کنم؟
ابتدا certbot و python3-certbot-apache را نصب کنید، رکورد A دامنه را به سرور اشاره دهید و سپس sudo certbot --apache را اجرا کنید. احراز هویتکننده Apache، کنترل دامنه را از طریق Apache در حال اجرا تأیید میکند و نصبکننده، virtual host را برای پورت 443 بازنویسی کرده و تمدید خودکار را تنظیم میکند. راهنمای کامل Certbot و Apache چالشها، زمانبندی تمدید و حالتهای رایج شکست در این فرآیند را پوشش میدهد.