О насБлогКонтакты
DevOps и инфраструктура12 марта 2014 г. 4 мин 112Обновлено: 22 июня 2026 г.

Прощай Apache: как мы перешли на Nginx + PHP-FPM и что из этого вышло

AunimedaAunimeda
📋 Содержание

В начале 2014 года у нас было три VPS-сервера на Ubuntu 12.04 с Apache 2.2 и mod_php. Каждый обслуживал несколько сайтов. При пиковой нагрузке - более 200 одновременных соединений - серверы уходили в своп, появлялись 502-ошибки, и всё встававало.

Проблема была не в мощности железа. Проблема была в архитектуре Apache.


Почему Apache тормозит под нагрузкой

Apache в режиме prefork (стандартный при mod_php) создаёт отдельный процесс для каждого HTTP-соединения. Каждый такой процесс загружает интерпретатор PHP в память.

На сервере с 2GB RAM:

Один процесс Apache + mod_php: ~30-40MB
200 одновременных соединений × 35MB = 7GB нужно
Доступно: 2GB
Результат: своп, OOM killer, падение сервера

Nginx устроен принципиально иначе: один мастер-процесс запускает несколько воркеров (обычно по числу ядер CPU). Каждый воркер обрабатывает тысячи соединений через неблокирующий I/O. PHP-код при этом выполняется в отдельном пуле процессов PHP-FPM.


Установка и тест без остановки Apache

Сначала устанавливаем Nginx, не трогая работающий Apache:

# Apache остаётся на порту 80, Nginx ставим на 8080 для тестирования
apt-get install nginx php5-fpm

# Меняем порт Nginx на 8080 временно
nano /etc/nginx/sites-available/default
# listen 8080;

Тестируем на 8080, убеждаемся что всё работает, потом переключаем.


Конфигурация PHP-FPM

; /etc/php5/fpm/pool.d/www.conf

[www]
user = www-data
group = www-data

; Unix-сокет быстрее TCP на одном сервере
listen = /var/run/php5-fpm.sock

; Динамический пул процессов
pm = dynamic
pm.max_children = 25        ; Максимум PHP-воркеров
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
pm.max_requests = 500       ; Перезапускать воркер после 500 запросов (борьба с утечками памяти)

; Таймауты
request_terminate_timeout = 30s
request_slowlog_timeout = 5s
slowlog = /var/log/php5-fpm-slow.log

Правило для pm.max_children: берём доступную RAM для PHP и делим на средний размер PHP-процесса. Для нашего сервера: 1.5GB / 40MB ≈ 37, взяли 25 с запасом.


Конфигурация Nginx

# /etc/nginx/sites-available/mysite.com

server {
    listen 80;
    server_name mysite.com www.mysite.com;
    root /var/www/mysite/public;
    index index.php index.html;

    # Сжатие
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml;
    gzip_min_length 256;
    gzip_comp_level 6;

    # Статика - отдаём напрямую, без PHP
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # PHP-файлы → PHP-FPM
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_read_timeout 30;
        fastcgi_buffer_size 128k;
        fastcgi_buffers 4 256k;
    }

    # Красивые URL для CMS и фреймворков
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # Скрываем скрытые файлы (.git, .env и т.д.)
    location ~ /\. {
        deny all;
    }
}

Переключение

# Останавливаем Apache
service apache2 stop
update-rc.d apache2 disable

# Возвращаем Nginx на порт 80
# Убираем временный listen 8080, ставим listen 80

# Запускаем
service nginx start
service php5-fpm start

# Следим за ошибками первые 10 минут
tail -f /var/log/nginx/error.log

Что сломалось при переезде

PHP-сессии. Apache и PHP-FPM запускаются под разными пользователями. Файлы сессий, созданные Apache, были недоступны PHP-FPM:

chown -R www-data:www-data /var/lib/php5/sessions

$_SERVER['REMOTE_ADDR'] возвращал 127.0.0.1 вместо IP клиента. Nginx проксирует запросы и передаёт реальный IP в заголовке X-Forwarded-For. Добавили в fastcgi_params:

fastcgi_param REMOTE_ADDR $remote_addr;

.htaccess - Nginx его не читает вообще. Все правила из .htaccess (редиректы, rewrite) пришлось вручную переписать в location-блоки Nginx. На это ушло около 3 часов на сайт.


Результаты

Метрика Apache + mod_php Nginx + PHP-FPM
RAM в простое 490MB 90MB
RAM при 200 соединениях 2.1GB (своп!) 380MB
Статика, запросов/сек 750 9200
PHP-страницы, запросов/сек 270 310
Время ответа (среднее) 190ms 85ms

Самый неожиданный результат - статика. Nginx отдаёт картинки и CSS без участия PHP в десятки раз быстрее. Нагрузка на сервер при одинаковом трафике упала на 60%.


Один VPS - несколько сайтов

Отдельный пул PHP-FPM на каждый сайт даёт изоляцию:

; /etc/php5/fpm/pool.d/site1.conf
[site1]
user = site1_user
listen = /var/run/php5-fpm-site1.sock
pm.max_children = 10

; /etc/php5/fpm/pool.d/site2.conf
[site2]
user = site2_user
listen = /var/run/php5-fpm-site2.sock
pm.max_children = 8

Если один сайт съест все свои воркеры - остальные продолжают работать. Под Apache с mod_php пул процессов был общим.

Принцип разделения веб-сервера и runtime приложения, который мы освоили в 2014-м, до сих пор актуален - только теперь это Docker-контейнеры вместо процессов.

Читайте также

Хостинг для сайта в Кыргызстане: VPS, shared или облако - что выбрать в 2026aunimeda
DevOps и инфраструктура

Хостинг для сайта в Кыргызстане: VPS, shared или облако - что выбрать в 2026

Разбираем типы хостинга для сайтов в Кыргызстане: shared, VPS, облачный и выделенный сервер. Реальные цены в сомах, рейтинг провайдеров и когда стоит апгрейдиться.

Docker и CI/CD для небольшой команды: что мы реально запускаем в продакшенеaunimeda
DevOps и инфраструктура

Docker и CI/CD для небольшой команды: что мы реально запускаем в продакшене

Kubernetes - не для всех. Наш продакшен-стек для 6 проектов командой из 8 человек: Docker Compose, GitHub Actions, Nginx - без Kubernetes и без $800/месяц на AWS.

Как настроить HTTPS на nginx в 2015 году: от покупки сертификата до A+ на SSL Labsaunimeda
DevOps и инфраструктура

Как настроить HTTPS на nginx в 2015 году: от покупки сертификата до A+ на SSL Labs

В 2015 году Let's Encrypt ещё не вышел. HTTPS стоил денег и требовал ручной настройки. Мы прошли путь от покупки сертификата за $10 до рейтинга A+ на SSL Labs для сервисов наших бишкекских клиентов. Конфигурация nginx, цепочка сертификатов, HSTS - точный рабочий конфиг.

Нужна IT-разработка для вашего бизнеса?

Разрабатываем сайты, мобильные приложения и AI-решения для бизнеса в Кыргызстане. Бесплатная консультация.

DevOps и инфраструктура

Получить консультацию Все статьи