بهینه‌سازی Nginx برای وردپرس یعنی تنظیم دقیق لایه وب‌سرور (Web Server) به‌گونه‌ای که هر درخواست داینامیک PHP (Hypertext Preprocessor) و هر فایل استاتیک با کمترین هزینه پردازش پاسخ بگیرد.

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

نقطه اثرگذاری اصلی، مدیریت Worker Process، تنظیم PHP-FPM (FastCGI Process Manager)، بافرها، کش لایه وب‌سرور و پروتکل انتقال است.

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

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

بار اولی که یک سایت وردپرسی روی Nginx مهاجرت می‌کند، معمولاً حس می‌شود همه‌چیز سریع‌تر شده؛ اما این حس چند هفته بعد با رشد ترافیک از بین می‌رود. تفاوت میان یک سرور سریع و یک سرور پایدار، دقیقاً در همان تنظیماتی است که کسی وقت نکرده بازشان کند.

چرا Nginx در معماری وردپرس یک لایه مستقل است

وردپرس در لایه‌ای اجرا می‌شود که هر بار فراخوانی می‌شود، بخش قابل‌توجهی از فایل‌های هسته، افزونه‌ها و قالب را بارگذاری می‌کند. اگر وب‌سرور بخواهد برای هر تصویر، هر فایل CSS و هر فایل JavaScript هم همین مسیر را طی کند، هزینه پردازش به‌سرعت از توان سرور خارج می‌شود. بهینه‌سازی سرور برای وردپرس بدون جدا کردن این دو مسیر عملاً ناقص می‌ماند.

Nginx (Nginx) این جداسازی را به‌صورت معماری درونی انجام می‌دهد. درخواست‌هایی که به فایل فیزیکی روی دیسک اشاره می‌کنند، بدون عبور از PHP پاسخ می‌گیرند و بقیه درخواست‌ها به یک سوکت Unix یا پورت TCP سپرده می‌شوند که PHP-FPM پشت آن نشسته است.

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

مدل رویدادمحور و تفاوت آن با مدل process-per-connection

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

Nginx از یک حلقه رویداد (Event Loop) استفاده می‌کند. هر Worker تعداد زیادی اتصال را در یک حلقه مدیریت می‌کند و تا زمانی که یک اتصال داده‌ای برای پردازش نداشته باشد، منابعی مصرف نمی‌کند. اینجا نقطه‌ای است که کندی سرور بیشتر از آنکه به سخت‌افزار مربوط باشد، به تنظیم اشتباه لایه PHP برمی‌گردد.

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

هر جا لایه وب‌سرور سریع باشد اما لایه اجرای PHP اشباع شود، گلوگاه فقط جابه‌جا شده است؛ نه حذف.

Worker Process و Worker Connections

تعداد Worker Process در Nginx باید با تعداد هسته‌های پردازشی سرور هماهنگ باشد. مقدار پیشنهادی مرسوم، تعداد هسته‌ها یا دو برابر آن است؛ اما در محیط‌هایی که PHP-FPM نیز همان هسته‌ها را مصرف می‌کند، انتخاب تهاجمی می‌تواند رقابت پردازشی ایجاد کند.

مقدار worker_connections تعیین می‌کند هر Worker چند اتصال را همزمان بپذیرد. حاصل‌ضرب این دو عدد، سقف نظری اتصال‌های همزمان است؛ اما سقف واقعی به محدودیت فایل‌های باز سیستم‌عامل و به ظرفیت PHP-FPM وابسته است. بی‌توجهی به این هم‌بستگی، دلیل رایج خطاهای 502 در ساعات اوج ترافیک است. مانیتورینگ سرور باید هم‌زمان هر دو لایه را زیر نظر بگیرد.

worker_processes auto;
worker_rlimit_nofile 65535;

events {
    worker_connections 4096;
    multi_accept on;
    use epoll;
}

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

PHP-FPM و معماری استخرها

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

سه مقدار کلیدی وجود دارد: pm.max_children سقف فرآیندهای همزمان، pm.start_servers تعداد فرآیندهای آغازین و pm.max_requests تعداد درخواست‌هایی که هر فرآیند پیش از بازنشستگی پردازش می‌کند. مقدار pm.max_requests ابزاری برای مهار نشتی حافظه در افزونه‌های ضعیف است؛ نه یک تزئین.

انتخاب حالت استخر نیز مهم است. در حالت static همه فرآیندها از ابتدا ساخته می‌شوند و تأخیر راه‌اندازی حذف می‌شود، اما حافظه به‌طور دائم اشغال می‌ماند. در حالت ondemand فرآیندها بر حسب نیاز ساخته می‌شوند و حافظه کمتری مصرف می‌شود، اما نخستین درخواست‌ها کندتر پاسخ می‌گیرند. برای سایت‌های پربازدید، حالت dynamic با مقادیر میانی معمولاً متعادل‌ترین انتخاب است.

محاسبه سقف pm.max_children از یک رابطه ساده بیرون می‌آید: حافظه آزاد سرور تقسیم بر میانگین مصرف هر فرآیند PHP. اگر میانگین مصرف ۸۰ مگابایت و حافظه آزاد ۳ گیگابایت باشد، سقف منطقی حدود ۳۷ فرآیند است و عبور از آن به قیمت استفاده از Swap تمام می‌شود. مشخصات سرور وردپرس باید پیش از این محاسبه بررسی شود.

بافرها، Timeout و رفتار زیر بار سنگین

بافرها تعیین می‌کنند پاسخ PHP در چه اندازه‌ای نگهداری شود پیش از آنکه به کلاینت فرستاده شود. بافر کوچک باعث نوشتن روی دیسک موقت (Temporary File) و افت کارایی می‌شود؛ بافر بسیار بزرگ، حافظه را در اوج ترافیک می‌بلعد.

fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_busy_buffers_size 64k;
fastcgi_read_timeout 120;
fastcgi_send_timeout 120;
keepalive_timeout 30;

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

Timeout کوتاه، سرور را سریع نشان می‌دهد؛ اما تنها کاری که می‌کند قطع امید کاربر است، نه حل مشکل.

کش لایه وب‌سرور با FastCGI Cache

کش وردپرسی معمولاً در لایه افزونه انجام می‌شود؛ یعنی صفحه کامل ساخته می‌شود و بعد ذخیره می‌گردد. کش لایه وب‌سرور یک قدم جلوتر است: پاسخ PHP پیش از ورود به وردپرس ذخیره می‌شود و درخواست‌های بعدی هیچ‌گاه به PHP-FPM نمی‌رسند.

اثر این کار روی زمان پاسخ چشمگیر است. تفاوت میان چند صد میلی‌ثانیه و چند ده میلی‌ثانیه در معیارهایی مثل TTFB (Time To First Byte) به‌وضوح دیده می‌شود و مستقیماً روی کاهش زمان TTFB اثر می‌گذارد.

fastcgi_cache_path /var/cache/nginx/wpk levels=1:2 keys_zone=wpk:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";

set $skip_cache 0;
if ($request_method = POST) { set $skip_cache 1; }
if ($query_string != "") { set $skip_cache 1; }

fastcgi_cache wpk;
fastcgi_cache_valid 200 301 302 60m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
add_header X-FastCGI-Cache $upstream_cache_status;

نکته حیاتی این است که صفحات پویا مانند سبد خرید، تسویه حساب و پیشخوان مدیریت هرگز نباید کش شوند. هدر X-FastCGI-Cache ابزار تشخیصی خوبی است: مقدار HIT نشان می‌دهد کش کار کرده و MISS یعنی درخواست به لایه PHP رسیده است.

کش لایه وب‌سرور جایگزین افزونه‌های کش وردپرس نیست؛ این دو مکمل یکدیگرند. افزونه کش، منطق سطح محتوا را مدیریت می‌کند و Nginx، هزینه ورود به PHP را حذف می‌کند.

فشرده‌سازی، HTTP/2 و HTTP/3

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

gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_vary on;
gzip_types text/plain text/css application/javascript application/json image/svg+xml;

brotli on;
brotli_comp_level 5;

فعال‌سازی HTTP/2 مزیت چندگانه‌سازی (Multiplexing) را به همراه دارد و تعداد اتصال‌های TCP را برای یک صفحه کاهش می‌دهد. HTTP/3 روی پروتکل QUIC سوار می‌شود و در شبکه‌های بی‌کیفیت با نرخ خطای بالا، تأخیر را محسوس کم می‌کند.

اگر سایت از یک شبکه توزیع محتوا استفاده می‌کند، تنظیم درست سرور مبدأ اهمیت دوچندان دارد؛ زیرا نقش CDN در بهبود سرعت سایت تنها وقتی دیده می‌شود که پاسخ سرور مبدأ قابل کش و قابل پیش‌بینی باشد.

فایل‌های استاتیک و قواعد مسیر

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

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

location ~* .(css|js|jpg|jpeg|png|webp|avif|svg|woff2)$ {
    expires 365d;
    add_header Cache-Control "public, immutable";
    access_log off;
    log_not_found off;
}

location = /wp-login.php { limit_req zone=login burst=5 nodelay; }
location = /xmlrpc.php { deny all; }

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

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

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

limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

location ~ /.(ht|git|env) { deny all; }
location ~* /(wp-config.php|readme.html|license.txt) { deny all; }
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
add_header Referrer-Policy strict-origin-when-cross-origin;

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

اندازه‌گیری و مانیتورینگ

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

در سطح سرور، مصرف CPU، حافظه، ورودی‌خروجی دیسک و صف فرآیندها بررسی می‌شود. در سطح وب‌سرور، وضعیت کش، تعداد اتصال‌های فعال و نرخ خطا اهمیت دارد. در سطح کاربر، معیارهایی مانند Core Web Vitals و به‌طور خاص بهینه‌سازی LCP تعیین‌کننده‌اند.

نکته‌ای که در پروژه‌ها کم‌تر دیده می‌شود: نتیجه بهینه‌سازی سرور باید در ترافیک ارگانیک هم دیده شود، چون تأثیر سرعت سایت بر سئو یک اثر تجمعی است، نه لحظه‌ای.

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

تنظیممقدار محافظه‌کارانهمقدار تهاجمیریسک
worker_connections10244096+اشباع فایل‌های باز سیستم‌عامل
pm.max_childrenبر اساس حافظه آزادنزدیک به سقف حافظهورود به Swap و افت شدید
fastcgi_read_timeout60300اشغال طولانی فرآیند PHP
gzip_comp_level49مصرف بی‌مورد CPU

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

نخستین اشتباه، کپی‌کردن پیکربندی از اینترنت بدون توجه به مشخصات سرور است. عددی که روی یک سرور ۱۶ هسته‌ای جواب می‌دهد، روی یک سرور ۲ هسته‌ای به فاجعه تبدیل می‌شود.

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

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

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

پیکربندی خوب، عدد جادویی ندارد؛ نسبتی دارد میان منابع موجود و الگوی واقعی ترافیک.

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

آیا Nginx همیشه از Apache سریع‌تر است؟

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

آیا FastCGI Cache جایگزین افزونه کش است؟

نه. این دو در دو لایه مختلف کار می‌کنند. FastCGI Cache پیش از ورود به وردپرس پاسخ می‌دهد، در حالی که افزونه کش منطق سطح محتوا و استثناهای آن را مدیریت می‌کند. ترکیب هر دو، بهترین نتیجه را می‌دهد.

چه زمانی باید سراغ سرور اختصاصی رفت؟

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

مقدار مناسب pm.max_children چقدر است؟

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

آیا بهینه‌سازی Nginx روی سئو اثر مستقیم دارد؟

اثر مستقیم ندارد، اما اثر غیرمستقیم آن جدی است. زمان پاسخ پایین‌تر، معیارهای تجربه صفحه را بهبود می‌دهد و این معیارها در رتبه‌بندی نقش دارند. همچنین نرخ خزش خزنده‌های موتور جستجو با پاسخ‌های سریع‌تر افزایش می‌یابد.

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

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

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