Когда сайт уже упирается в производительность Apache или конфигурации стали слишком разношерстными из‑за множества .htaccess, переход на Nginx выглядит логичным шагом. Но «просто заменить веб‑сервер» — путь к неожиданностям: отличия в синтаксисе, приоритетах правил, модели обработки PHP и поведении прокси легко приводят к 404/502, сломанным редиректам и просадке SEO. Ниже — подробный чек‑лист миграции, ориентированный на практику и быструю верификацию.
Стратегия миграции: параллельный запуск и план отката
Безопаснее всего запускать Nginx параллельно Apache на соседних портах или вторичном адресе. Это позволяет прогнать функциональные и нагрузочные тесты, не затрагивая боевой трафик. Затем выполняется переключение (порт/Firewall/DNS) и короткая валидация. Не забывайте о плане отката: четко описанные шаги, как вернуть Apache в дело за минуты. Для стенда удобно арендовать тестовый VDS, чтобы не трогать боевой сервер.
Правило ноль: миграция — это не только перенос конфигов. Это инвентаризация правил и согласование ожиданий приложения с новой моделью обработки запросов Nginx.
 
        Карта соответствия: Apache → Nginx
Ключевые различия, которые определяют форму миграции:
- vhost → server: виртуальные хосты Apache переезжают в server‑блоки Nginx. Директивы ServerName/ServerAliasсоответствуютserver_name.
- .htaccess исчезают: Nginx не читает .htaccess. Все rewrite/доступ/индексы переносятся в конфиги. Это плюс к производительности и предсказуемости.
- rewrite: синтаксис и приоритеты другие. В Nginx локации и try_filesиграют ключевую роль; избыточныеrewriteупрощаются.
- DirectoryIndex → index, Options →autoindex, AllowOverride → отсутствует концептуально.
- ProxyPass/ProxyPassReverse → proxy_passс явными заголовками и буферами.
- mod_php → PHP‑FPM: FastCGI вместо встроенного интерпретатора. Нужна корректная передача SCRIPT_FILENAMEиPATH_INFO.
- MPM против событийной модели Nginx: иное влияние на память и конкуренцию сокетов.
- Журналы: Combined формат можно воспроизвести через log_format; ротация — через системные инструменты.
Чек‑лист подготовки
- Соберите список всех vhost: домены, поддомены, порты, TLS/ALPN, требования к HTTP/2/HTTP/3.
- Слейте все .htaccess в единый реестр: редиректы, правила ЧПУ, ограничения доступа, Basic‑Auth, кеш‑контроль, CORS. Отмечайте приоритеты и порядок.
- Инвентаризируйте PHP: версии, расширения, лимиты (memory_limit,max_execution_time,post_max_size,upload_max_filesize), особенностиPATH_INFO.
- Опишите прокси‑бэкенды: адреса upstream (PHP‑FPM, Node.js, Python/WSGI, Go), таймауты, поддержка WebSocket/SSE, требования к буферизации.
- Проверьте TLS: цепочки сертификатов, ключи, шифры, OCSP‑Stapling. Путь хранения и права. Если требуется выпуск/подмена, оформите SSL‑сертификаты заранее.
- Уточните лимиты и загружаемые файлы: целевые значения client_max_body_size, ожидаемые типы и объемы.
- Подготовьте SEO‑карту редиректов: канонические домены, хвосты слешей, HTTP→HTTPS, перевод старых URL. Приоритизируйте 301 над 302.
- Учтите реальный IP за балансировщиками/CDN: план real_ip_headerи доверенных источников.
- Определите требования к производительности: RPS, пиковые нагрузки, целевая латентность, кеш‑стратегии (статические, микрокеш).
- Опишите мониторинг и логи: форматы, ротацию, алерты по 4xx/5xx, объемы логов.
Для выбора архитектуры и компромиссов полезно взглянуть на актуальное сравнение Nginx и Apache.

Базовый каркас Nginx
Стартовый скелет для изоляции виртуальных хостов и чёткой логики:
user www-data;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
events {
    worker_connections 4096;
    multi_accept on;
}
http {
    include mime.types;
    default_type application/octet-stream;
    log_format combined '$remote_addr - $remote_user [$time_local] "$request" '
                        '$status $body_bytes_sent "$http_referer" '
                        '"$http_user_agent"';
    access_log /var/log/nginx/access.log combined;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65s;
    types_hash_max_size 4096;
    server {
        listen 80;
        server_name example.com www.example.com;
        root /var/www/example/public;
        index index.php index.html;
        location = /favicon.ico { access_log off; log_not_found off; }
        location = /robots.txt  { access_log off; log_not_found off; }
        location / {
            try_files $uri $uri/ /index.php?$args;
        }
        location ~ \.php$ {
            include fastcgi_params;
            fastcgi_pass unix:/run/php/php-fpm.sock;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_read_timeout 60s;
        }
        location ~* \.(css|js|png|jpe?g|gif|svg|webp|ico)$ {
            expires 30d;
            access_log off;
        }
    }
}
Важно: директива root действует в пределах контекста; при использовании alias для подкаталогов следите за формами путей (см. раздел «Частые грабли»).
Миграция rewrite и try_files
Большая часть «магии» .htaccess — это две категории: простые редиректы и внутренние перезаписи к фронт‑контроллеру. В Nginx вместо каскадов RewriteRule чаще выигрывает try_files.
Примеры переноса:
# Apache: Redirect 301 /old /new
# Nginx — эквивалент в server:
location = /old {
    return 301 /new;
}
# Apache: RewriteRule ^category/(.*)$ /catalog/$1 [R=301,L]
# Nginx:
rewrite ^/category/(.*)$ /catalog/$1 permanent;
# Apache (WordPress/фронт-контроллер):
# RewriteCond %{REQUEST_FILENAME} !-f
# RewriteCond %{REQUEST_FILENAME} !-d
# RewriteRule . /index.php [L]
# Nginx (эквивалент через try_files):
location / {
    try_files $uri $uri/ /index.php?$args;
}
Где у Nginx отличия:
- Приоритет: locationвыбирается до примененияrewrite, аrewriteвнутри локации применяются по ходу обработки. Не смешивайте глобальные и локальные правила без необходимости.
- Флаги QSA,NC,Lимеют иные соответствия. Объединение аргументов запроса в Nginx делается явно:/path?$args&new=value.
- Регулярные выражения используют синтаксис PCRE; обратите внимание на экранирование и порядок локаций (~,~*,=, префиксные).
Прокси к бэкендам: proxy_pass и заголовки
Перенос ProxyPass на Nginx требует явной передачи заголовков и корректной буферизации. Базовый шаблон:
upstream app_backend {
    server 127.0.0.1:3000;
    keepalive 32;
}
location /api/ {
    proxy_pass http://app_backend;
    proxy_http_version 1.1;
    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_buffering on;
    proxy_buffers 16 8k;
    proxy_busy_buffers_size 64k;
    proxy_read_timeout 60s;
}
# WebSocket/СSE:
location /ws/ {
    proxy_pass http://app_backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 1d;
    proxy_buffering off;
}
Частая причина 502/504 — несовпадение таймаутов и буферов с реальными профилями ответов. Если бэкенд отдаёт крупные JSON или генерирует ответ долго, увеличьте proxy_read_timeout, а для потоковых ответов отключите буферизацию.

PHP‑FPM: аккуратная передача скриптов и PATH_INFO
Переезд с mod_php требует пересборки цепочки FastCGI. Ключевые моменты:
- fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;— путь к скрипту. Не путать с- request_filenameпри сложных alias.
- Если используется PATH_INFO, добавьтеfastcgi_param PATH_INFO $fastcgi_path_info;и настройте регулярную локацию для захвата.
- Согласуйте лимиты: client_max_body_sizeв Nginx ≥post_max_sizeв PHP, иначе будут 413/500.
- Проверьте fastcgi_read_timeoutиmax_execution_time— они должны соответствовать ожиданиям приложения.
location ~ \.php$ {
    include fastcgi_params;
    fastcgi_pass unix:/run/php/php-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_read_timeout 120s;
}
# Альтернативно, для "разрыва" PATH_INFO:
location ~ ^(.+\.php)(/.*)$ {
    include fastcgi_params;
    fastcgi_pass unix:/run/php/php-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$1;
    fastcgi_param PATH_INFO $2;
}
Производительность: быстрые выигрыши
Переход на Nginx уже даёт профит по статике и конкуренции соединений, но есть быстрые твики:
- Сетевые параметры: worker_processes auto, разумныеworker_connections, включенныйsendfile,tcp_nopush,tcp_nodelay.
- Кэширование статики: длительные expires, аккуратныеCache-Control, ETag/Last-Modified для экономии трафика. Смотрите также наш материал про настройку Cache-Control и ETag для статики.
- open_file_cache: уменьшает статс‑звонки к FS под нагрузкой.
- Upstream keepalive: снижает накладные расходы на частые короткие запросы к бэкенду.
- Микрокеш для динамики (если уместно): секунда‑две кэша часто дают сильное сглаживание пиков.
- Буферизация прокси: подгоните proxy_buffers/proxy_busy_buffers_sizeпод типичные ответы, чтобы избежать лишних дисковых операций.
http {
    open_file_cache max=10000 inactive=60s;
    open_file_cache_valid 120s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;
}
Журналы и мониторинг
Чтобы не терять совместимость с текущей аналитикой, настройте формат, близкий к Apache Combined:
log_format combined '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent"';
access_log /var/log/nginx/access.log combined;
error_log /var/log/nginx/error.log warn;
Минимальные алерты: всплески 5xx и рост латентности upstream. На этапе миграции включите временно повышенный уровень логирования для проблемных локаций. Заодно проверьте защитные заголовки — поможет наш гайд по HTTP security headers.
Проверки перед переключением
Прогоняем функционал, метрики и SEO‑критичные сценарии:
- curl‑проверки: статические файлы (200), динамика (200), редиректы (301/308), HEAD/GET идентичны по заголовкам к Apache.
- Коды и заголовки: Content-Type,Cache-Control,Vary,ETag,Last-Modified,Locationу редиректов.
- Пути: чувствительность к слешу, регистру и завершающим слешам; файл /robots.txt,/sitemap.xml,/.well-known/.
- Загрузки: граничные размеры POST/файлов; корректность 413/422/500 и сообщений.
- Аутентификация: Basic‑Auth, куки, сессии PHP; кросс‑доменные запросы, если используется CORS.
- Потоки: WebSocket/SSE, таймауты, отсутствие лишней буферизации.
- Кеш: статика с правильным TTL; условные запросы (If-Modified-Since/If-None-Match).
# Примеры быстрых тестов
curl -I http://127.0.0.1:8080/
curl -I -L http://127.0.0.1:8080/old
curl -I -H "Accept-Encoding: gzip" http://127.0.0.1:8080/style.css
curl -I http://127.0.0.1:8080/robots.txt
curl -I http://127.0.0.1:8080/.well-known/acme-challenge/test
curl -I -H "Connection: upgrade" -H "Upgrade: websocket" http://127.0.0.1:8080/ws/
Переключение трафика без простоя
Три базовых подхода:
- Перепривязка портов: Nginx слушает 80/443, Apache временно уходит на 8080/8443. После проверки — остановка Apache.
- Firewall DNAT/REDIRECT: трафик направляется на новый порт/процесс, быстрое возвратное переключение при откате.
- DNS с низким TTL: заранее уменьшите TTL, затем смените A/AAAA. Учитывайте кеши клиентов и промежуточных резолверов.
# Проверка конфигов
nginx -t
# Грациозная перезагрузка
nginx -s reload
systemctl reload nginx
# Диагностика занятых портов
ss -ltnp | grep ':80\|:443'
Частые грабли
- Порядок location: регулярные локации перехватывают больше, чем ожидается; используйте =для точных совпадений и корректные префиксы.
- root vs alias: при aliasпуть строится иначе. Дляlocation /img/сalias /data/images/запрос/img/a.jpgищется по пути/data/images/a.jpg— не добавляйте лишний суффикс.
- Зацикливание редиректов: проверяйте условия редиректов с учетом протокола/домена; храните канонический домен в одной директиве.
- Размеры запросов: 413 из‑за маленького client_max_body_sizeпри больших загрузках; синхронизируйте с PHP.
- 502 при PHP: неверный путь к сокету fastcgi_passили ошибкаSCRIPT_FILENAME. Смотрите error.log PHP‑FPM и Nginx.
- Заголовок Host: без proxy_set_header Host $host;многие бэкенды дают 404/400.
- Кодировки: явно задайте charsetпри необходимости и проверьте отдачу статических файлов.
- Индекс: index index.php index.html;— порядок важен для фронт‑контроллеров.
- Права и SELinux/AppArmor: проверьте доступ Nginx к web‑root, сокетам PHP‑FPM и каталогам временных файлов.
Контрольный чек‑лист перед выкладкой
- Все vhost хозяйства заведены серверами с корректными server_nameи корнями.
- Критичные rewrite перенесены и покрыты автотестами или ручными сценариями.
- PHP через PHP‑FPM работает, загружаются большие файлы, корректны таймауты.
- Прокси к бэкендам стабильны, включены нужные заголовки, WebSocket/SSE проверены.
- Логи пишутся, ротация настроена, уровни ошибок на время миграции повышены.
- Параметры производительности соответствуют целям: keepalive, буферы, кеш статики.
- Канонические редиректы (HTTP→HTTPS, www↔non‑www, слеши) отрабатывают единственным прыжком 301.
- Реальный IP посетителя восстанавливается (если есть внешний балансировщик/CDN).
- Проверены /robots.txt,/sitemap.xml,/.well-known/и ответы на HEAD.
- Описан и проверен план отката: как вернуть Apache или старый маршрут трафика.
 
        Откат и документация
Откат — не поражение, а гарантия контроля рисков. Держите рядом рабочие юниты и конфиги Apache, сохраните старые правила редиректов, зафиксируйте команды возврата портов или изменения правил Firewall. После успешного перехода обновите документацию: реестр серверов, upstream‑пулы, чек‑лист эксплуатации и точки мониторинга.
Миграция с Apache на Nginx — это проект: инвентаризация, перенос логики, верификация, оптимизация и устойчивая эксплуатация. Хороший чек‑лист экономит часы ночных разбирательств.
Следуя этому плану, вы перенесете сервисы без сюрпризов, получите предсказуемый стек и заодно улучшите производительность и управляемость инфраструктуры.
 
                            

