بهینه‌سازی Apache برای وردپرس یعنی پیکربندی ماژول‌ها، فایل .htaccess و لایه اجرای PHP به‌شکلی که سرور هم زیر بار همزمان پایدار بماند و هم هزینه پردازش هر درخواست را کاهش دهد.

Apache (Apache HTTP Server) قدیمی‌ترین وب‌سرور پرکاربرد جهان است و بیشتر میزبان‌های اشتراکی همچنان روی آن کار می‌کنند.

نقطه تمایز Apache در انعطاف فایل .htaccess و ماژول‌های آماده است؛ همین ویژگی، هم بزرگ‌ترین مزیت و هم بزرگ‌ترین دام آن به‌شمار می‌رود.

هر ماژول فعال، هر قاعده .htaccess و هر تنظیم MPM (Multi-Processing Module) هزینه مشخصی دارد که اگر اندازه‌گیری نشود، پنهان می‌ماند.

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

Apache را می‌توان با چند خط تنظیم سریع‌تر کرد؛ اما همان چند خط، اگر بر اساس الگوی واقعی ترافیک نوشته نشوند، در ساعات اوج به یک مانع تبدیل می‌شوند. تفاوت میان یک سرور آرام و یک سرور پرتنش، اغلب در دو یا سه ماژول غیرضروری است که کسی سراغشان نرفته.

جایگاه Apache در معماری وردپرس

وردپرس برای اجرا به سه چیز نیاز دارد: یک وب‌سرور که درخواست HTTP را بپذیرد، یک مفسر PHP که منطق را اجرا کند و یک پایگاه داده که داده را نگه دارد. Apache لایه نخست است و تصمیم می‌گیرد کدام درخواست به PHP برود و کدام مستقیم پاسخ بگیرد.

Apache (Apache HTTP Server) تاریخچه‌ای طولانی دارد و همین باعث شده مجموعه‌ای بسیار گسترده از ماژول‌ها و رفتارهای پیش‌فرض داشته باشد. این غنا در پروژه‌های سازمانی مزیت است؛ اما در یک سایت وردپرسی معمولی، بخش زیادی از آن بی‌استفاده می‌ماند و فقط منابع مصرف می‌کند.

نکته مهم این است که Apache به‌تنهایی کند نیست. آنچه سایت را کند می‌کند، ترکیب یک MPM نامناسب، فایل .htaccess سنگین، ماژول‌های فعال بی‌مصرف و لایه PHP تنظیم‌نشده است. بهینه‌سازی سرعت سایت بدون توجه به این ترکیب، فقط بخشی از مسئله را حل می‌کند.

انتخاب MPM و پیامدهای آن

MPM تعیین می‌کند Apache چگونه درخواست‌ها را میان فرآیندها و Threadها توزیع کند. سه گزینه اصلی وجود دارد و انتخاب اشتباه میان آن‌ها، اثرش از هر تنظیم دیگری بیشتر است.

حالت prefork برای هر اتصال یک فرآیند جدا می‌سازد. سازگارترین حالت است و با ماژول‌های قدیمی مشکلی ندارد، اما مصرف حافظه آن بالا و مقیاس‌پذیری آن محدود است. حالت worker از Thread استفاده می‌کند و حافظه کمتری مصرف می‌کند. حالت event نسخه تکامل‌یافته worker است و اتصال‌های بی‌کار را جدا مدیریت می‌کند.

<IfModule mpm_event_module>
    StartServers             3
    MinSpareThreads          75
    MaxSpareThreads          250
    ThreadsPerChild          25
    MaxRequestWorkers        400
    MaxConnectionsPerChild   10000
</IfModule>

مقدار MaxRequestWorkers تعیین‌کننده سقف ظرفیت است و باید با حافظه سرور هم‌خوان باشد. اگر هر فرآیند حدود ۴۰ مگابایت مصرف کند و سقف روی ۴۰۰ تنظیم شود، عدد واقعی حافظه مورد نیاز چندین گیگابایت خواهد بود. افزایش امنیت سرور و بهینه‌سازی عملکرد، دو مسیری هستند که در همین نقطه به هم می‌رسند.

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

هر پارامتری که مقدار پیش‌فرض دارد، یک فرض پنهان درباره اندازه سرور و الگوی ترافیک هم دارد.

هزینه پنهان فایل .htaccess

فایل .htaccess یکی از محبوب‌ترین ویژگی‌های Apache است، زیرا اجازه می‌دهد بدون دسترسی به فایل تنظیمات اصلی، رفتار سرور تغییر کند. اما همین انعطاف، هزینه‌ای دارد: Apache برای هر درخواست، مسیر دایرکتوری را از ریشه طی می‌کند تا فایل‌های .htaccess را پیدا و تفسیر کند.

در سایت‌هایی با فایل .htaccess سنگین یا با ساختار دایرکتوری عمیق، این هزینه قابل توجه می‌شود. راه‌حل استاندارد، انتقال قواعد به فایل تنظیمات اصلی و تنظیم AllowOverride None است؛ با این کار، Apache دیگر نیازی به خواندن .htaccess ندارد.

<Directory /var/www/html>
    AllowOverride None
    Require all granted
</Directory>

البته این تغییر بدون هزینه نیست. اگر وردپرس یا افزونه‌ای به‌طور خودکار قواعدی را در .htaccess بنویسد، آن قواعد دیگر اعمال نمی‌شوند. مسیر انتقال، جایگزینی قواعد و آزمایش کامل سایت است. قواعد رایجی مانند ریدایرکت HTTP به HTTPS با htaccess باید پیش از این تغییر به تنظیمات سرور منتقل شوند.

نکته کاربردی دیگر: در وردپرس، اگر ساختار پیوندهای یکتا به‌درستی تنظیم نشود، قواعد بازنویسی هر بار به‌صورت کامل بازنویسی می‌شوند. رفع ریشه‌ای خطای پیوند یکتای وردپرس پیش از بهینه‌سازی .htaccess ضروری است.

ماژول‌ها: چه چیزی لازم است و چه چیزی نیست

هر ماژول فعال، حافظه و زمان بارگذاری مصرف می‌کند. بارگذاری ماژولی که هرگز استفاده نمی‌شود، صرفاً یک بدهی فنی بی‌صدا است. یک رویکرد عملی این است که فهرست ماژول‌های فعال را استخراج و هر مورد را بر اساس نیاز واقعی سایت دسته‌بندی کنیم.

ماژولوضعیت پیشنهادی برای وردپرستوضیح
mod_rewriteضروریپیوندهای یکتا و ریدایرکت
mod_expiresضروریکنترل کش مرورگر
mod_deflateضروریفشرده‌سازی پاسخ
mod_securityمشروطقدرتمند اما پرمصرف و نیازمند تنظیم دقیق

ماژول‌هایی مانند mod_status در محیط تولید باید محدود به آدرس‌های مشخص باشند، وگرنه اطلاعات سرور را در معرض دید قرار می‌دهند. همچنین mod_info و mod_autoindex در محیط تولید توصیه نمی‌شوند.

لایه PHP و ارتباط آن با Apache

دو راه برای اجرای PHP زیر Apache وجود دارد: ماژول mod_php و روش PHP-FPM با mod_proxy_fcgi. روش دوم تقریباً در همه سناریوهای امروزی برتری دارد، زیرا PHP را از Apache جدا می‌کند و اجازه می‌دهد هر لایه مستقل تنظیم و مانیتور شود.

<FilesMatch .php$>
    SetHandler "proxy:unix:/run/php/php8.2-fpm.sock|fcgi://localhost"
</FilesMatch>

با این ساختار، تنظیمات PHP در فایل استخر PHP-FPM انجام می‌شود و Apache فقط درخواست را به سوکت می‌سپارد. این جداسازی، خطاهای ناشی از تنظیمات متناقض میان دو لایه را به‌شدت کاهش می‌دهد و زمان کاهش زمان بارگذاری سایت را قابل پیش‌بینی‌تر می‌کند.

در این لایه باید به مصرف حافظه هر فرآیند توجه شود. اگر حافظه سرور محدود است، تعداد فرآیندهای PHP-FPM باید پیش از تنظیم تعداد Workerهای Apache محدود شود؛ در غیر این صورت هر دو لایه برای منابع یکسان رقابت می‌کنند.

کش و فشرده‌سازی در لایه وب‌سرور

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

<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/webp "access plus 1 year"
    ExpiresByType text/css "access plus 1 year"
    ExpiresByType application/javascript "access plus 1 year"
    ExpiresByType text/html "access plus 0 seconds"
</IfModule>

<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/css application/javascript application/json
</IfModule>

نکته‌ای که اغلب نادیده می‌ماند این است که فایل‌های HTML نباید کش طولانی‌مدت شوند، چون محتوای آن‌ها پویاست. در مقابل، فایل‌های دارای نسخه در نام (Versioned Assets) می‌توانند کش تقریباً نامحدود داشته باشند.

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

Keep-Alive، اتصال‌ها و رفتار زیر بار

Keep-Alive به مرورگر اجازه می‌دهد یک اتصال TCP را برای چند درخواست باز نگه دارد. این ویژگی تأخیر راه‌اندازی اتصال را حذف می‌کند، اما در سرورهای پرمشغله هر اتصال باز، یک Worker یا Thread را اشغال می‌کند.

KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 3

مقدار KeepAliveTimeout باید کوتاه باشد. مقدارهای بزرگ مانند ۱۵ ثانیه باعث می‌شوند Workerها بی‌دلیل منتظر بمانند و ظرفیت سرور کاهش یابد. مقدار ۲ تا ۵ ثانیه برای بیشتر سایت‌ها متعادل است.

در سایت‌هایی که از یک شبکه توزیع محتوا استفاده می‌کنند، تنظیم Keep-Alive باید با رفتار شبکه هم‌خوان شود؛ زیرا نقش CDN در بهبود سرعت سایت تنها وقتی دیده می‌شود که اتصال میان شبکه و سرور مبدأ بهینه باشد.

امنیت لایه وب‌سرور

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

ServerTokens Prod
ServerSignature Off

<Files wp-config.php>
    Require all denied
</Files>

<DirectoryMatch "^/.*/.git/">
    Require all denied
</DirectoryMatch>

غیرفعال‌کردن ویرایشگر فایل در پیشخوان وردپرس، یک لایه امنیتی دیگر است که با یک ثابت در فایل تنظیمات اعمال می‌شود؛ روش انجام آن در قطعه کد غیرفعال کردن ویرایش فایل وردپرس توضیح داده شده است.

حفاظت از امن‌سازی فایل wp-config و محدودسازی ورودهای ناموفق، دو اقدام پایه هستند که پیش از هر بهینه‌سازی عملکردی باید انجام شوند، زیرا یک سایت سریع که هک شده باشد، دیگر یک سایت نیست.

اندازه‌گیری و عیب‌یابی

هر تغییری باید با عدد سنجیده شود. بدون اندازه‌گیری، تفاوت میان یک تنظیم بهتر و یک تنظیم خوش‌شانس قابل تشخیص نیست. سه سطح اندازه‌گیری وجود دارد: سرور، وب‌سرور و تجربه کاربر.

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

در سمت پایگاه داده نیز باید وضعیت جداول بررسی شود. کوئری کند، هر لایه بالاتر را بی‌اثر می‌کند؛ بنابراین بهینه‌سازی جداول MySQL بخشی از همان چرخه است، نه موضوعی جدا.

سنجش، تنها چیزی است که تفاوت میان حدس و تصمیم را مشخص می‌کند.

جدول تصمیم‌گیری تنظیمات کلیدی

تنظیممقدار محافظه‌کارانهمقدار تهاجمیریسک
MaxRequestWorkersبر اساس حافظه آزادنزدیک به سقف حافظهورود به Swap
KeepAliveTimeout51افزایش تأخیر در اتصال‌های کند
MaxConnectionsPerChild10000500هزینه راه‌اندازی مکرر فرآیند
AllowOverrideNoneAllهزینه خواندن .htaccess در هر درخواست

اشتباهات رایج

نخستین اشتباه، نگه‌داشتن حالت prefork روی سروری است که بار همزمان بالایی دارد. این انتخاب معمولاً از عادت یا از نیاز یک ماژول قدیمی می‌آید و بدون بررسی باقی می‌ماند.

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

سومین اشتباه، بزرگ‌کردن بی‌محاسبه MaxRequestWorkers بدون توجه به حافظه است. نتیجه، ورود به Swap و افت شدید عملکرد است؛ حالتی که در آن سرور پاسخ می‌دهد اما کندی آن از یک سرور اشباع‌شده هم بیشتر است.

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

پنجمین اشتباه، بی‌توجهی به مقاوم‌سازی ورود است. اجرای نادرست جلوگیری از حملات brute force در وردپرس یا نبود آن، سرور را در برابر تلاش‌های مکرر ورود آسیب‌پذیر می‌کند و منابع پردازشی را هدر می‌دهد.

پرسش‌های پرتکرار درباره بهینه‌سازی Apache برای وردپرس

آیا Apache برای سایت‌های پربازدید مناسب است؟

بله، به شرط انتخاب MPM مناسب و جداسازی لایه PHP. با پیکربندی درست، Apache می‌تواند بارهای سنگین را مدیریت کند. مسئله معمولاً معماری نیست، بلکه تنظیمات باقی‌مانده روی مقادیر پیش‌فرض است.

آیا باید .htaccess را به‌طور کامل حذف کرد؟

حذف کامل توصیه نمی‌شود. رویکرد درست، انتقال قواعد پایدار به فایل تنظیمات اصلی و نگه‌داشتن .htaccess فقط برای قواعد پویا یا موقتی است. این کار نیازمند آزمایش کامل سایت پس از انتقال است.

mod_php بهتر است یا PHP-FPM؟

در تقریباً همه سناریوهای امروزی، PHP-FPM انتخاب بهتری است. جداسازی لایه PHP از Apache، امکان تنظیم مستقل، مانیتورینگ دقیق‌تر و مصرف حافظه پایین‌تر را فراهم می‌کند.

چگونه بفهمم ماژول‌های اضافی روی سرور فعال هستند؟

فهرست ماژول‌های بارگذاری‌شده را استخراج کنید و هر مورد را با نیاز واقعی سایت مقایسه کنید. هر ماژولی که در شش ماه گذشته استفاده نشده است، کاندید غیرفعال‌سازی است.

آیا بهینه‌سازی Apache روی سرعت واقعی کاربر اثر دارد؟

بله، اما اثر آن با لایه‌های دیگر جمع می‌شود. اگر قالب سنگین باشد یا تصاویر بهینه نباشند، بهینه‌سازی وب‌سرور بخش بزرگی از مشکل را حل نمی‌کند. انتخاب یک قالب سبک وردپرس مکمل ضروری این کار است.

چه زمانی باید از Apache به سرور اختصاصی مهاجرت کرد؟

وقتی بهینه‌سازی نرم‌افزاری به سقف خود رسیده است. پیش از آن، مقایسه ساختارهای میزبانی مانند سرور اختصاصی و VPS کمک می‌کند تصمیم بر اساس داده گرفته شود، نه بر اساس حدس.

نکته‌ای برای ادامه مسیر

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

اگر روی سرور خودتان این مسیر را طی کرده‌اید، برای من جالب است بدانم کدام بخش بیشترین زمان را گرفت: انتخاب MPM، انتقال قواعد از .htaccess به تنظیمات سرور، یا هم‌خوان‌کردن Apache با PHP-FPM. تجربه خودتان را در دیدگاه‌ها بنویسید؛ به‌خصوص اگر راه‌حل متفاوتی پیدا کرده‌اید که می‌تواند برای خواننده بعدی مفید باشد.