۱۳
IRANSERVER · LINUX BOOTCAMP

سیزدهمین بوت‌کمپ لینوکس ایران‌سرور

تنظیم php.ini روی دایرکت‌ادمین، انتخاب درست اکستنشن‌ها، و شناخت معماری وب‌سرورها — از فرآیندهای Apache تا حلقهٔ رویداد NGINX و LSAPI لایت‌اسپید.

DirectAdmin · CustomBuild php.ini & OPcache PHP Extensions Apache MPM LiteSpeed / LSAPI NGINX event-loop
۲۶ اسلاید · فشردن ← برای شروع
AGENDA

مسیری که امروز طی می‌کنیم

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

01 php.ini و اکستنشن‌ها

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

۱۱ اسلاید

02 سه معماری

Apache با مدل process/thread، LiteSpeed با LSAPI و کش داخلی، و NGINX با حلقهٔ رویداد غیر بلاکینگ — هرکدام با دیاگرام و کانفیگ تیونینگ.

۶ اسلاید

03 ترکیب و انتخاب

NGINX جلو، Apache عقب در حالت nginx_apache: چه به دست می‌آوریم و چه هزینه‌ای می‌دهیم؟ در پایان جدول مقایسه و راهنمای تصمیم.

۵ اسلاید
پیش‌نیاز: دسترسی root به یک سرور دایرکت‌ادمین و آشنایی مقدماتی با systemctl. همهٔ مسیرها و دستورها بر پایهٔ چیدمان استاندارد دایرکت‌ادمین و CustomBuild نوشته شده‌اند: نسخهٔ PHP در مثال‌ها php83 است — آن را با نسخهٔ سرور خودتان جایگزین کنید.
بخش یک

php.ini و اکستنشن‌ها —
جایی که کارایی و امنیت شروع می‌شود

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

DIRECTADMIN · LOAD ORDER

اول بدان کجا بنویسی، بعد بنویس

  • در دایرکت‌ادمین هر نسخهٔ PHP پیشوند نصب مستقل دارد: /usr/local/php83/، /usr/local/php82/ و … . نسخه‌های فعال در options.conf با کلیدهای php1_release و php2_release تعیین می‌شوند.
  • فایل پایهٔ php.ini را CustomBuild تولید می‌کند؛ ویرایش مستقیم آن با اولین ./build php n از بین می‌رود. تغییرات شما جای دیگری می‌رود.
  • مقدار مؤثر را از خود PHP بپرسید: /usr/local/php83/bin/php --ini برای CLI و یک صفحهٔ phpinfo() در همان دامنه برای وب.
قانون طلایی دایرکت‌ادمین: هیچ‌وقت فایل تولیدشده را دستی ویرایش نکنید. تغییر را در php.conf.d/ یا در تمپلیت custom/ بگذارید و سپس ./build rewrite_confs بزنید.
۱ · فایل پایه — تولید CustomBuild /usr/local/php83/lib/php.ini ۲ · محل تغییرات شما ✓ /usr/local/php83/lib/php.conf.d/99-custom.ini ۳ · pool اختصاصی هر کاربر /usr/local/php83/etc/php-fpm.d/USER.conf ۴ · ‎.user.ini در مسیر سایت /home/USER/domains/DOMAIN/public_html/ ۵ · ‎ini_set()‎ در زمان اجرا فقط تا پایان همان درخواست
هر لایه مقدار لایهٔ بالای خود را بازنویسی می‌کند — مگر آنکه در pool با php_admin_value قفل شده باشد. لایهٔ ۱ و ۳ را دایرکت‌ادمین بازتولید می‌کند.
RESOURCE LIMITS

سقف‌هایی که باید با هم هماهنگ باشند

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

the upload chain; ترتیب صحیح: memory ≥ post ≥ upload
memory_limit = 256M
post_max_size = 128M
upload_max_filesize = 64M
max_file_uploads = 50

; فرم‌های سنگین (ووکامرس، المنتور)
max_input_vars = 5000

; زمان‌ها — با FPM هماهنگ شود
max_execution_time = 60
max_input_time = 60

; کش مسیرها؛ برای پروژه‌های پرفایل
realpath_cache_size = 8M
realpath_cache_ttl = 600

چرا آپلود ۵۰ مگابایتی رد می‌شود؟

اگر post_max_size از upload_max_filesize کوچک‌تر باشد، PHP کل بدنهٔ درخواست را دور می‌ریزد و $_POST و $_FILES هر دو خالی می‌شوند — بدون خطا. جلوی وب‌سرور هم سقف جداگانه دارد: client_max_body_size در NGINX و LimitRequestBody در Apache.

max_execution_time همهٔ ماجرا نیست

این شمارنده فقط زمان اجرای کد PHP را می‌شمارد؛ انتظار برای دیتابیس یا sleep در آن حساب نمی‌شود. مهلت واقعی را request_terminate_timeout در pool و fastcgi_read_timeout در وب‌سرور تعیین می‌کنند.

قانون سرانگشتی: fastcgi_read_timeout > request_terminate_timeout > max_execution_time. برعکسش یعنی خطای ۵۰۲ به‌جای پیام خطای قابل‌فهم.
OPCACHE

بزرگ‌ترین برد عملکردی با کمترین تغییر

درخواست .php file تحلیل واژگانی Lex / Parse کامپایل Compile تولید opcode Opcodes اجرا Zend VM این سه مرحله در هر درخواست تکرار می‌شوند — مگر آنکه OPcache روشن باشد CACHE HIT — opcode از حافظهٔ اشتراکی خوانده و مستقیم اجرا می‌شود
OPcache خروجی کامپایل را در حافظهٔ اشتراکی نگه می‌دارد؛ درخواست دوم به بعد، سه مرحلهٔ میانی را کامل رد می‌کند.
/etc/php/8.3/fpm/conf.d/10-opcache.iniopcache.enable=1
opcache.memory_consumption=256          ; MB
opcache.interned_strings_buffer=32
opcache.max_accelerated_files=100000
opcache.revalidate_freq=2
opcache.save_comments=1            ; برای annotation ها لازم است
opcache.validate_timestamps=1      ; پروداکشن: 0 + ریلود بعد از دیپلوی
  • سایز را از روی داده تنظیم کنید: خروجی opcache_get_status() را ببینید؛ اگر num_cached_keys به سقف نزدیک شده یا oom_restarts بالا رفته، حافظه کم است.
  • validate_timestamps=0 بیشترین سود را دارد ولی تا ریلود FPM یا opcache_reset() کد جدید دیده نمی‌شود — فقط با دیپلوی خودکار.
  • JIT (opcache.jit=tracing) برای بار CPU‑محور سود دارد؛ اپلیکیشن وب معمولی که منتظر I/O است تفاوت محسوسی نمی‌بیند.
هرگز opcache.save_comments=0 نگذارید مگر مطمئن باشید هیچ کتابخانه‌ای (Doctrine، PHPUnit، Symfony) به annotation نیاز ندارد.
ERRORS & LOGGING

خطا را بنویس، اما به کاربر نشان نده

نمایش خطا در پروداکشن هم نشت اطلاعات است (مسیر فایل، نام دیتابیس، نسخهٔ کتابخانه) و هم تجربهٔ کاربری خراب. دقیقاً همان تنظیمات در محیط توسعه باید برعکس باشند.

PRODUCTION
display_errors = Off
display_startup_errors = Off
html_errors = Off
log_errors = On
error_log = /var/log/php-fpm/83-errors.log
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
log_errors_max_len = 2048
ignore_repeated_errors = On
DEVELOPMENT
display_errors = On
display_startup_errors = On
html_errors = On
log_errors = On
error_reporting = E_ALL
zend.assertions = 1
opcache.validate_timestamps = 1
opcache.revalidate_freq = 0

لاگ‌های دایرکت‌ادمین کجاست؟

  • /var/log/httpd/domains/DOMAIN.error.log
  • /var/log/nginx/domains/DOMAIN.error.log
  • /var/log/php-fpm/
  • /var/log/directadmin/error.log

لاگ کند را جدی بگیرید

در تمپلیت pool مقدار request_slowlog_timeout را روی 5s بگذارید. خروجی، دقیقاً stack trace همان درخواست‌هایی است که سرور را زمین می‌زنند — نه حدس و گمان.

چرخش لاگ

دایرکت‌ادمین لاگ دامنه‌ها را خودش می‌چرخاند، اما فایلی که شما در error_log تعریف کرده‌اید در این چرخه نیست. یک قانون logrotate با copytruncate برایش بنویسید.

HARDENING

سخت‌سازی، بدون شکستن اپلیکیشن

security block; اثر انگشت سرور
expose_php = Off

; توابع پرخطر — با فهرست افزونه‌ها تطبیق دهید
disable_functions = exec,passthru,shell_exec,
  system,proc_open,popen,dl,pcntl_exec

; جداسازی هر کاربر — دایرکت‌ادمین این را
; در pool هر کاربر خودش تنظیم می‌کند
open_basedir = /home/USER/:/tmp/:/var/tmp/
session.save_path = /home/USER/tmp
upload_tmp_dir = /home/USER/tmp

; ورودی از راه دور
allow_url_fopen = Off
allow_url_include = Off

; کوکی نشست
session.cookie_httponly = 1
session.cookie_secure = 1
session.cookie_samesite = Lax
session.use_strict_mode = 1
session.gc_maxlifetime = 1440

۱ پیش از قطع تابع، تست کنید

proc_open برای بکاپ‌گیری و exec برای پردازش تصویر در بسیاری از افزونه‌ها استفاده می‌شود. قطع سراسری آن‌ها معمولاً به‌جای امنیت، یک تیکت پشتیبانی می‌سازد. اول در staging.

۲ محافظ واقعی برابر اجرای فایل آپلودی

تنظیم قدیمی cgi.fix_pathinfo=0 هنوز توصیه می‌شود، اما لایهٔ اصلی در pool است: security.limit_extensions = .php و در وب‌سرور، بلاک کردن اجرای PHP در مسیر uploads/.

۳ جای درست اعمال این تنظیمات

مقادیر عمومی در php.conf.d/99-custom.ini؛ مقادیر وابسته به کاربر (مثل open_basedir) در تمپلیت /usr/local/directadmin/data/templates/custom/php-fpm.conf و سپس ./build rewrite_confs. حفاظت open_basedir در پنل هم به‌صورت هر‌کاربره قابل روشن‌کردن است.

RISKY EXTENSIONS

هر اکستنشن، یک سطح حمله اضافه می‌کند

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

EXTENSIONچرا پرریسک استتوصیه
ffiفراخوانی مستقیم توابع کتابخانه‌های C از دل PHP — عملاً خروج کامل از هر محدودیتی که در php.ini گذاشته‌ایدهرگز روی هاست اشتراکی
imapمتکی به کتابخانهٔ قدیمی c-client با سابقهٔ اجرای کد از راه دور؛ از PHP 8.4 از هستهٔ زبان جدا شده استفقط اگر سرویس ایمیل خاصی لازمش دارد
pcntlpcntl_exec یعنی جایگزینی فرآیند با هر باینری دلخواه روی سرورفقط در SAPI خط فرمان، نه در FPM
posixposix_getpwuid کاربران سیستم را فهرست می‌کند و posix_kill فرآیند می‌کشددر disable_functions محدود شود
shmop · sysv*حافظهٔ اشتراکی سیستم‌عامل، بدون مرز بین کاربران — نشت داده بین اکانت‌های یک سرورغیرفعال در هاست اشتراکی
soapپردازش WSDL از منبع بیرونی: زمینهٔ XXE و SSRF به شبکهٔ داخلیفقط برای درگاه‌هایی که نیاز دارند
xmlrpcسابقهٔ deserialization و XXE؛ از PHP 8 از هسته حذف شده و نگهداری نمی‌شودنصب نکنید
ریسک صفر وجود ندارد، ریسک بی‌دلیل چرا. exif هم سابقهٔ آسیب‌پذیری دارد اما وردپرس واقعاً به آن نیاز دارد؛ xmlrpc را هیچ‌کس نیاز ندارد. تصمیم بر پایهٔ «چه کسی استفاده می‌کند» گرفته می‌شود، نه ترس.
CONTAINMENT

وقتی نمی‌شود حذف کرد، مهار کنید

/usr/local/php83/lib/php.conf.d/99-custom.ini; FFI فقط در حالت preload، نه در کد کاربر
ffi.enable = Off

; جلوگیری از ساخت/تغییر آرشیو phar در زمان اجرا
phar.readonly = On

; بارگذاری ماژول دلخواه در زمان اجرا
enable_dl = Off

; یک MySQL مخرب نتواند فایل سرور را بخواند
mysqli.allow_local_infile = Off
pdo_mysql.default_socket = /usr/local/mysql/data/mysql.sock

; ورودی از راه دور
allow_url_fopen = Off
allow_url_include = Off

غیرفعال‌سازی یک اکستنشن در دایرکت‌ادمین

هر اکستنشن یک فایل ini جدا در php.conf.d/ دارد. کافی است پسوندش را عوض کنید تا دیگر بارگذاری نشود — بدون کامپایل مجدد PHP:

cd /usr/local/php83/lib/php.conf.d/
mv 50-imap.ini 50-imap.ini.disabled
systemctl restart php-fpm83
/usr/local/php83/bin/php -m | grep imap
حواستان به phar:// باشد.phar.readonly=On فقط جلوی نوشتن را می‌گیرد؛ حملهٔ deserialization از راه خواندن رخ می‌دهد. مهار واقعی، ندادن مسیر فایل کنترل‌شدهٔ کاربر به توابع فایل است.
راه‌حل ساختاری: به‌جای یک php.ini سخت‌گیر برای همه، در دایرکت‌ادمین می‌توانید دو نسخهٔ PHP تعریف کنید — یکی سخت‌گیر به‌عنوان پیش‌فرض و یکی با اکستنشن‌های بیشتر، و فقط دامنه‌هایی که واقعاً نیاز دارند را روی دومی بگذارید.
WORDPRESS · REQUIRED MODULES

وردپرس دقیقاً به چه چیزی نیاز دارد؟

در ابزار «سلامت سایت» وردپرس تنها یک ماژول با برچسب «الزامی» گزارش می‌شود؛ بقیه «توصیه‌شده»‌اند — اما نبودشان بخش‌های واقعی سایت را می‌شکند، نه اینکه فقط هشدار بدهد.

بدون این‌ها بالا نمی‌آید

jsonmysqlipcre hashfilterdate sessionzlib

json تنها موردی است که وردپرس رسماً «الزامی» می‌داند؛ بقیهٔ این فهرست جزو هستهٔ PHP هستند و معمولاً دست‌کاری نمی‌شوند.

نبودشان سایت را می‌شکند

curldomsimplexml xmlreadermbstringopenssl zipgdexif fileinfoiconvintl sodium

zip و sodium برای بروزرسانی خودکار و بررسی امضای بسته‌ها؛ fileinfo برای تشخیص نوع فایل آپلودی.

بسته به کاربرد

imagickbcmathsoap opcacheredismemcached igbinary

imagick کیفیت تصویر بهتری از gd می‌دهد، bcmath برای ووکامرس، و redis برای آبجکت‌کش پایدار.

برای سایت فارسی حیاتی‌اند: mbstring برای برش و شمارش درست حروف فارسی، و intl برای مرتب‌سازی، قالب‌بندی عدد و تاریخ. بدون این دو، نامک‌های فارسی و خلاصهٔ نوشته‌ها خراب می‌شوند.
exif استثنای قاعده است: در فهرست پرریسک قرار می‌گیرد، ولی وردپرس برای چرخاندن خودکار تصاویر موبایل به آن نیاز دارد. حذفش نکنید — به‌جایش PHP را به‌روز نگه دارید.
CUSTOMBUILD · EXTENSIONS

نصب و راستی‌آزمایی، به روش دایرکت‌ادمین

۱ · مسیر CustomBuildcd /usr/local/directadmin/custombuild
./build update
./build options            # دیدن نام دقیق گزینه‌ها
./build set php1_release 8.3
./build set php1_mode php-fpm
./build php n              # کامپایل مجدد PHP
./build rewrite_confs
۲ · افزودن ماژول PECL روی یک نسخهٔ خاص/usr/local/php83/bin/pecl install redis
echo 'extension=redis.so' > \
  /usr/local/php83/lib/php.conf.d/70-redis.ini
systemctl restart php-fpm83
۳ · راستی‌آزمایی# فهرست ماژول‌های یک نسخه
/usr/local/php83/bin/php -m

# مقایسهٔ دو نسخهٔ نصب‌شده روی سرور
diff <(/usr/local/php82/bin/php -m) \
     <(/usr/local/php83/bin/php -m)

# آنچه واقعاً روی وب فعال است
# ← یک فایل phpinfo() در همان دامنه
مهم‌ترین دام: ماژول را روی php82 نصب کنید و سایت روی php83 اجرا شود. هر نسخه باینری، php.ini و pecl جداگانه دارد. همیشه مسیر کامل نسخه را بنویسید، نه php خالی.
پس از هر ./build php n فهرست ماژول‌ها را دوباره بگیرید؛ کامپایل مجدد می‌تواند ماژول‌های دستی‌نصب‌شده را کنار بگذارد. اگر ماژولی همیشگی است، آن را از راه options.conf فعال کنید تا در هر build بازساخته شود.
PHP-FPM POOLS

php.ini تنها نصف کار است

در معماری مدرن، PHP یک فرآیند جداست. آنچه ظرفیت واقعی سرور را تعیین می‌کند، تنظیمات pool است — نه php.ini.

تمپلیت: data/templates/custom/php-fpm.conf
خروجی: /usr/local/php83/etc/php-fpm.d/USER.conf
[USER] user = USER group = USER listen = /usr/local/php83/sockets/USER.sock pm = dynamic pm.max_children = 30 pm.start_servers = 6 pm.min_spare_servers = 4 pm.max_spare_servers = 10 pm.max_requests = 500 request_terminate_timeout = 90s slowlog = /var/log/php-fpm/83-USER-slow.log request_slowlog_timeout = 5s ; بازنویسی php.ini فقط برای این کاربر php_admin_value[memory_limit] = 256M php_admin_flag[log_errors] = on php_admin_value[open_basedir] = /home/USER/:/tmp/ php_admin_value[session.save_path] = /home/USER/tmp

pm.max_children را حدس نزنید

میانگین حافظهٔ هر worker را اندازه بگیرید (معمولاً ۴۰ تا ۱۲۰ مگابایت) و آن را بر رم قابل‌تخصیص تقسیم کنید. عدد بزرگ‌تر از این یعنی swap و کندی کل سرور — نه ظرفیت بیشتر.

php_value یا php_admin_value؟

نسخهٔ admin قفل می‌کند: کد اپلیکیشن نمی‌تواند با ini_set() آن را دور بزند. برای open_basedir و disable_functions همیشه از این نسخه استفاده کنید.

سه حالت pm: static برای سرور اختصاصی پرترافیک، dynamic پیش‌فرض متعادل، و ondemand برای ده‌ها سایت کم‌بازدید روی یک سرور — حالت رایج در هاستینگ اشتراکی دایرکت‌ادمین.
گردش کار درست: فایل php-fpm.conf را از data/templates/ به data/templates/custom/ کپی کنید، آنجا ویرایش کنید، سپس ./build rewrite_confs. فایل php-fpm.d/USER.conf خروجی است، نه ورودی.
CHECKLIST

از پیش‌فرض تا پروداکشن — یک نگاه

DIRECTIVE DEFAULT PRODUCTION چرا
memory_limit128M256Mفضای کافی برای فریم‌ورک و افزونه‌ها بدون میدان‌دادن به نشت حافظه
upload_max_filesize2M64Mآپلود رسانه و بکاپ؛ همیشه کوچک‌تر از post_max_size
post_max_size8M128Mسقف کل بدنهٔ درخواست، شامل همهٔ فیلدها و فایل‌ها
max_input_vars10005000فرم‌های تنظیمات بزرگ بی‌سروصدا بریده می‌شوند
realpath_cache_size4096K8Mکاهش چشمگیر syscall در پروژه‌های با هزاران فایل
opcache.memory_consumption128256جا برای کل کدبیس؛ در غیر این‌صورت restart مکرر کش
opcache.max_accelerated_files10000100000وردپرس با افزونه‌ها به‌راحتی از ۱۰٬۰۰۰ فایل عبور می‌کند
expose_phpOnOffحذف هدر X-Powered-By و افشای نسخهٔ PHP
display_errorsOnOffجلوگیری از نشت مسیر فایل و ساختار پروژه
session.cookie_httponly01کوکی نشست از دسترس جاوااسکریپت خارج می‌شود
پس از هر تغییر: php -i | grep memory_limit برای CLI کافی نیست — مقدار مؤثر روی وب را از phpinfo() یا php-fpm -tt بررسی کنید.
بخش دو

سه پاسخ متفاوت
به یک پرسش واحد

«چطور هزاران کانکشن همزمان را با حافظهٔ محدود مدیریت کنیم؟» Apache، LiteSpeed و NGINX هر کدام از مسیر متفاوتی به این پرسش رسیده‌اند — و همین تفاوت، انتخاب شما را تعیین می‌کند.

APACHE HTTPD · MPM

یک درخواست، یک واحد اجرایی

کانکشن‌ها شامل کانکشن‌های ‏keep-alive بی‌کار CHILD PROCESS × ServerLimit Listener Thread پارک keep-alive Worker Thread Worker Thread Worker Thread Worker Thread ThreadsPerChild = 25 PHP-FPM mod_proxy_fcgi فرآیند مستقل FastCGI
در MPM event، کانکشن بی‌کار نزد listener می‌ماند و worker آزاد می‌شود؛ در MPM prefork هر کانکشن یک فرآیند کامل را تا آخر اشغال می‌کند.

prefork

یک فرآیند مستقل به‌ازای هر درخواست، بدون thread. تنها گزینهٔ سازگار با mod_php، و گران‌ترین گزینه از نظر حافظه.

worker

چند فرآیند، هرکدام با چندین thread. مصرف حافظه به‌ازای هر کانکشن به‌شدت کمتر، اما نیازمند ماژول‌های thread-safe.

event

مثل worker، به‌علاوهٔ یک thread شنونده برای کانکشن‌های keep-alive. پیش‌فرض توصیه‌شدهٔ امروز در کنار PHP-FPM.

APACHE · TRADE-OFFS

انعطاف بی‌رقیب، با هزینهٔ حافظه

قوت ‎.htaccess و ماژول‌ها

تنظیمات در سطح دایرکتوری و بدون ریلود سرویس؛ همان چیزی که هاست اشتراکی و اپلیکیشن‌های آماده روی آن حساب می‌کنند. اکوسیستم ماژول‌ها هم بزرگ‌ترین در میان وب‌سرورهاست.

ضعف هزینهٔ هر کانکشن

هر درخواست یک فرآیند یا thread می‌گیرد. با افزایش کانکشن‌های همزمان — به‌ویژه کانکشن‌های کند — مصرف حافظه خطی بالا می‌رود و سرور به سقف MaxRequestWorkers می‌خورد.

هزینهٔ پنهان .htaccess: با AllowOverride All، Apache برای هر درخواست تمام مسیر تا ریشه را برای یافتن .htaccess جست‌وجو می‌کند. اگر قوانین ثابت‌اند، آن‌ها را به بلاک <Directory> منتقل و AllowOverride None کنید.
/etc/httpd/conf/extra/httpd-mpm.conf<IfModule mpm_event_module>
  StartServers              4
  MinSpareThreads           25
  MaxSpareThreads           75
  ThreadsPerChild           25
  MaxRequestWorkers         400   ; = ServerLimit × ThreadsPerChild
  MaxConnectionsPerChild    10000
</IfModule>

KeepAlive                  On
MaxKeepAliveRequests       200
KeepAliveTimeout           5
Timeout                    60

# در دایرکت‌ادمین این بلاک را خودِ تمپلیت
# virtual_host2.conf برای هر دامنه می‌سازد
<FilesMatch \.php$>
  SetHandler "proxy:unix:/usr/local/php83/sockets/USER.sock|fcgi://localhost"
</FilesMatch>
LITESPEED · LSAPI

رویدادمحور، اما با زبان Apache

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

کلاینت HTTP/3 · QUIC LITESPEED WEB SERVER LSCache — کش در خودِ وب‌سرور در صورت HIT، پاسخ بدون اجرای هیچ خط PHP برمی‌گردد هستهٔ رویدادمحور — چند فرآیند به‌تعداد هسته‌های CPU بدون یک thread به‌ازای هر کانکشن LSAPI — مدیریت مستقیم فرآیندهای PHP و خواندن ‎.htaccess بومی فرآیندهای lsphp persistent workers CACHE HIT
تفاوت کلیدی با زوج «NGINX + PHP-FPM»: کش و مدیریت فرآیندهای PHP هر دو داخل خود وب‌سرور هستند، نه در دو سرویس جدا.

LSAPI

پروتکل اختصاصی جایگزین FastCGI با سربار کمتر در تبادل داده و مدیریت مستقیم چرخهٔ عمر فرآیندهای PHP.

LSCache

کش صفحهٔ کامل در سطح سرور، با پشتیبانی ESI، crawler و افزونهٔ رسمی وردپرس برای باطل‌سازی هوشمند.

سازگاری

خواندن مستقیم httpd.conf و .htaccess؛ مهاجرت از Apache معمولاً بدون تغییر کانفیگ انجام می‌شود.

QUIC / HTTP/3

پشتیبانی بومی و از ابتدا؛ ضدِ DDoS ساده و محدودسازی نرخ هم در هستهٔ سرور تعبیه شده است.

OLS vs. ENTERPRISE

دو نسخه، دو کاربرد متفاوت

ویژگیOpenLiteSpeed رایگانLiteSpeed Enterprise تجاری
سازگاری .htaccessقوانین rewrite خوانده می‌شود، اما بسیاری از تغییرات نیازمند graceful restart استسازگاری کامل و اعمال آنی، مانند خود Apache
جایگزینی drop-inکانفیگ باید به فرمت خود OLS منتقل شودhttpd.conf را مستقیم می‌خواند؛ مهاجرت در حد دقایق
کنترل‌پنلپنل ادمین وب داخلی؛ ادغام با CyberPanelادغام رسمی با cPanel، Plesk، DirectAdmin
LSCacheموجودموجود، به‌همراه امکانات پیشرفتهٔ ESI و crawler
هزینهمتن‌باز، بدون محدودیت تعداد سایتلایسنس دوره‌ای، معمولاً بر اساس تعداد worker و رم
مناسب برایسرور اختصاصی، پروژهٔ تک‌سایته، محیط کانتینریهاستینگ اشتراکی و سرورهای پرمشتری با کنترل‌پنل
در دایرکت‌ادمین: هر دو با ./build set webserver litespeed یا openlitespeed و سپس ./build rewrite_confs فعال می‌شوند. کانفیگ سرور در /usr/local/lsws/conf/ است و دایرکت‌ادمین همچنان vhostها را به فرمت آپاچی تولید می‌کند.
ملاحظه: اکوسیستم ماژول‌های شخص ثالث در مقایسه با Apache و NGINX کوچک‌تر است و بخشی از قابلیت‌های پیشرفته پشت لایسنس قرار دارد.
NGINX · EVENT LOOP

تعداد کمی فرآیند، هزاران کانکشن

کانکشن‌ها ۱۰٬۰۰۰+ همزمان با حافظهٔ تقریباً ثابت Master Process خواندن کانفیگ، bind پورت، مدیریت و ریلود بی‌وقفهٔ workerها Worker #1 event loop ‏epoll · غیر بلاکینگ Worker #2 event loop ‏epoll · غیر بلاکینگ Worker #n event loop ‏worker_processes auto ظرفیت ≈ worker_processes × worker_connections فایل static sendfile · بدون کپی PHP-FPM fastcgi_pass unix:…
هیچ کانکشنی یک فرآیند را قفل نمی‌کند؛ worker بین هزاران سوکت جابه‌جا می‌شود و فقط روی رویدادهای آماده کار می‌کند.

قوت مقیاس‌پذیری

مصرف حافظه با تعداد کانکشن رشد نمی‌کند. برای کانکشن‌های کند، فایل‌های استاتیک و نقش reverse proxy بی‌رقیب است.

قوت کانفیگ متمرکز

نبودِ .htaccess یعنی هیچ جست‌وجوی فایل به‌ازای هر درخواست انجام نمی‌شود — سریع‌تر و قابل بازبینی در گیت.

ضعف انعطاف کمتر

همان نبودِ .htaccess در هاست اشتراکی مشکل‌ساز است، و افزودن ماژول اغلب نیازمند کامپایل مجدد یا ماژول پویاست.

NGINX · TUNING

کانفیگی که واقعاً فرق می‌سازد

  • سوکت یونیکس یا TCP؟ روی همان ماشین، سوکت یونیکس سربار کمتری دارد. به‌محض اینکه PHP روی سرور دیگری برود، 127.0.0.1:9000 تنها گزینه است.
  • بافرها را ببینید، نه اینکه حدس بزنید. پیام upstream sent too big header در لاگ یعنی fastcgi_buffers کوچک است — نه اینکه اپلیکیشن خراب باشد.
  • worker_rlimit_nofile باید از worker_connections بزرگ‌تر باشد، وگرنه سقف فایل‌های باز سیستم‌عامل زودتر از کانفیگ شما می‌رسد.
کش FastCGI: با fastcgi_cache می‌توان پاسخ صفحات را در خود NGINX نگه داشت — معادل کاری که LSCache به‌صورت داخلی انجام می‌دهد، فقط با کانفیگ دستیِ بیشتر.
/etc/nginx/nginx.confworker_processes       auto;
worker_rlimit_nofile   65535;

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

http {
  sendfile      on;
  tcp_nopush    on;
  tcp_nodelay   on;
  keepalive_timeout 30;
  client_max_body_size 128m;   # با post_max_size هماهنگ

  gzip on;
  gzip_types text/css application/javascript image/svg+xml;

  fastcgi_buffers       16 16k;
  fastcgi_buffer_size   32k;
  fastcgi_read_timeout  120s;      # > request_terminate_timeout
}
HYBRID · REVERSE PROXY

NGINX جلو، Apache عقب

هدف این معماری، برداشتن نقطهٔ ضعف Apache بدون از دست دادن نقطهٔ قوت آن است: کانکشن‌های کند و فایل‌های استاتیک را NGINX می‌گیرد، و .htaccess سرِ جایش می‌ماند.

کلاینت مرورگر / اپ موبایل اتصال کند، شبکهٔ ضعیف NGINX ‏:443 پایان‌دهی TLS و HTTP/2 پاسخ static · بافر کردن محافظت از کانکشن کند Apache ‏:8080 فقط روی ‏127.0.0.1 ‏.htaccess · mod_rewrite ‏mod_remoteip برای IP واقعی PHP-FPM اجرای اپلیکیشن unix socket HTTPS proxy_pass fcgi CSS / JS / تصویر — بدون رسیدن به Apache
هر لایه کاری را می‌کند که در آن بهترین است؛ ولی هر لایه یک نقطهٔ کانفیگ و یک نقطهٔ خرابی بیشتر هم هست.

دستاورد جذب کانکشن کند

NGINX پاسخ Apache را کامل می‌گیرد و worker آپاچی را فوراً آزاد می‌کند؛ کاربر با شبکهٔ ضعیف دیگر یک thread گران را اشغال نمی‌کند.

دستاورد مهاجرت تدریجی

می‌توانید مسیر به مسیر ترافیک را از Apache به NGINX منتقل کنید، بدون توقف سرویس و بدون بازنویسی یکبارهٔ همهٔ قوانین.

هزینه پیچیدگی مضاعف

دو فایل لاگ، دو مجموعه هدر، دو جای تنظیم timeout. هر اشکالی باید در دو لایه ردیابی شود و مصرف رم پایه هم بالاتر می‌رود.

HYBRID · CONFIG

کانفیگ حداقلی و درست

خروجی دایرکت‌ادمین: data/users/USER/nginx.conf
تمپلیت قابل ویرایش: templates/custom/nginx_server_secure.conf
server { listen 443 ssl; http2 on; server_name example.ir; root /var/www/site/public; # استاتیک مستقیم از NGINX location ~* \.(jpg|png|webp|css|js|woff2)$ { expires 30d; access_log off; try_files $uri @apache; } location / { proxy_pass http://127.0.0.1:8080; } location @apache { proxy_pass http://127.0.0.1:8080; } proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 120s; }
فعال‌سازی حالت ترکیبی در CustomBuildcd /usr/local/directadmin/custombuild
./build set webserver nginx_apache
./build nginx_apache
./build rewrite_confs
# آپاچی خودکار روی 127.0.0.1:8080 می‌رود
# و mod_remoteip در تمپلیت گنجانده می‌شود
آنچه باید در آپاچی تأیید کنیدListen 127.0.0.1:8080

<IfModule mod_remoteip.c>
  RemoteIPHeader        X-Forwarded-For
  RemoteIPInternalProxy 127.0.0.1
</IfModule>

# ‎%a به‌جای ‎%h تا IP واقعی لاگ شود
LogFormat "%a %l %u %t \"%r\" %>%s %O" combined
اگر mod_remoteip را جا بیندازید، تمام لاگ‌های Apache و همهٔ ابزارهای امنیتی مثل fail2ban فقط 127.0.0.1 می‌بینند — یعنی مسدودسازی مهاجم عملاً کل سایت را می‌بندد.
  • پورت ۸۰۸۰ را روی رابط عمومی باز نگذارید؛ فقط 127.0.0.1.
  • گواهی TLS فقط در NGINX نصب می‌شود؛ Apache همیشه HTTP ساده صحبت می‌کند.
  • در اپلیکیشن (وردپرس، لاراول) X-Forwarded-Proto را به‌عنوان proxy مورد اعتماد تعریف کنید تا حلقهٔ ریدایرکت رخ ندهد.
COMPARISON

چهار معماری، کنار هم

معیار Apache (event) LiteSpeed NGINX NGINX + Apache
مدل همزمانیفرآیند + threadرویدادمحوررویدادمحوررویدادمحور در لبه، thread در عقب
حافظه در کانکشن بالارشد خطیتقریباً ثابتتقریباً ثابتمتوسط
‏.htaccessبومیبومی (کامل در Enterprise)نداردبومی، در لایهٔ Apache
کش داخلی صفحهmod_cacheLSCache، آمادهfastcgi_cache، دستیproxy_cache در NGINX
اتصال به PHPproxy_fcgi → FPMLSAPI، داخلیfastcgi_pass → FPMاز راه Apache
‏HTTP/3محدودبومیپشتیبانی می‌شوددر لایهٔ NGINX
پیچیدگی نگهداریکمکممتوسطبالا
بهترین کاربرداپ‌های قدیمی، ماژول‌های خاصهاست اشتراکی، وردپرس پرترافیکAPI، اپ اختصاصی، کانتینرمهاجرت تدریجی، سرورهای موجود
DECISION GUIDE

کدام را انتخاب کنم؟

پاسخ به «کدام سریع‌تر است؟» تقریباً همیشه «بستگی دارد» است. اما پاسخ به این چهار پرسش، تصمیم را قطعی می‌کند.

اگر ده‌ها مشتری روی یک سرور دارید

هر مشتری قوانین .htaccess خودش را می‌خواهد و شما نمی‌توانید برای هر تغییر سرویس را ریلود کنید.

LiteSpeed Enterpriseیا Apache event + PHP-FPM

اگر یک وردپرس پرترافیک دارید

بیشترین سود از کش صفحهٔ کامل می‌آید، نه از خود وب‌سرور. LSCache این را آماده می‌دهد؛ با NGINX باید fastcgi_cache را دستی بسازید.

LiteSpeed + LSCache

اگر API یا اپ اختصاصی دارید

کانکشن زیاد، کانفیگ نسخه‌بندی‌شده در گیت، و استقرار کانتینری. نیازی به .htaccess ندارید.

NGINX + PHP-FPM

اگر سروری با Apache دارید که کند شده

پیش از هر مهاجرتی، NGINX را جلو بگذارید. اغلب همین یک لایه، بدون تغییر اپلیکیشن، فشار را برمی‌دارد.

NGINX جلو، Apache عقب
و پیش از همهٔ این‌ها: OPcache را روشن و درست تنظیم کنید. تغییر وب‌سرور معمولاً چند درصد جابه‌جا می‌کند؛ یک OPcache تنظیم‌نشده چند برابر.
WRAP-UP

چهار چیزی که با خودتان می‌برید

01

php.ini را از روی داده تنظیم کنید، نه از روی مقاله. phpinfo()، opcache_get_status() و slowlog سه منبع حقیقت شما هستند.

02

سقف‌ها زنجیره‌اند. از client_max_body_size تا post_max_size، و از fastcgi_read_timeout تا max_execution_time — یک حلقهٔ ناهماهنگ کافی است.

03

معماری یعنی نحوهٔ خرج‌کردن حافظه. Apache حافظه را به ازای کانکشن می‌دهد، NGINX و LiteSpeed به ازای کار واقعی.

04

ترکیب، یک ابزار است نه یک هدف. اگر Apache را برای .htaccess لازم ندارید، لایهٔ دوم فقط پیچیدگی است.

برای تمرین بعد از جلسه

  • یک سایت نمونه را با ab یا wrk قبل و بعد از فعال‌سازی OPcache تست کنید.
  • pm.max_children را از روی مصرف واقعی حافظهٔ workerها محاسبه کنید.
  • یک NGINX را جلوی Apache موجودتان بگذارید و mod_remoteip را درست کنید.
QUESTIONS

پرسش و پاسخ

سیزدهمین بوت‌کمپ لینوکس ایران‌سرور

00 / 00