Nginx — это отличный веб-сервер, который давно зарекомендовал себя как надежное решение даже для крупных проектов. Несмотря на то, что Nginx прекрасно работает “из коробки”, я рекомендую выполнить несколько оптимизационных настроек, которые помогут сократить время ответа сервера.
Не забывайте проверять корректность настроек после внесения изменений командой:
nginx -tА чтобы применить новые настройки, нужно перезапустить Nginx командой:
nginx -s reload
История изменений
27.03.2026: Добавлены разделы: сжатие Brotli, предварительное сжатие статики, оптимизация SSL/TLS, HTTP/3. Обновлена секция безопасности: добавлены Content-Security-Policy и Permissions-Policy, удалены устаревшие X-XSS-Protection и X-Permitted-Cross-Domain-Policies. Исправлен синтаксис HTTP/2 для Nginx 1.25+.
18.07.2022: Добавил информацию о кэшировании на стороне сервера. Провел общий рефакторинг статьи.
Оптимизация работы соединений
Начнем с настройки основных параметров, отвечающих за количество обрабатываемых соединений и их продолжительность.
worker_processes auto;
worker_priority -2;
...
events {
worker_connections 2048;
multi_accept on;
}
...
http {
...
keepalive_timeout 45;
reset_timedout_connection on;
client_body_timeout 35;
client_header_timeout 12;
send_timeout 30;
...
client_body_buffer_size 10K;
client_header_buffer_size 1k;
client_max_body_size 8m;
large_client_header_buffers 4 4k;
...
}worker_processes — определяет количество рабочих процессов. Обычно задается равным числу ядер процессора, но в последних версиях Nginx рекомендуется использовать значение auto, что позволяет серверу автоматически выбрать оптимальное количество процессов. По умолчанию — 1.
worker_connections — задает максимальное количество соединений, которое может обслуживать один рабочий процесс. Общая способность сервера обрабатывать запросы — это произведение worker_processes * worker_connections. Остальные запросы будут поставлены в очередь. Рекомендуемые значения — от 1024 до 4096. По умолчанию — 512.
multi_accept — позволяет рабочему процессу принимать несколько новых соединений одновременно. По умолчанию — off.
keepalive_timeout — определяет максимальное время поддержания keepalive-соединения, если пользователь по нему не делает запросы. Для современных систем оптимальные значения — от 30 до 50 секунд. В данном случае установлено 45. По умолчанию — 75 секунд.
reset_timedout_connection — если клиент перестал читать страницу, Nginx автоматически завершит соединение. По умолчанию — off.
client_body_timeout — определяет время ожидания тела запроса от клиента. Если в течение этого времени клиент не передает данные, соединение разрывается с ошибкой 408 (Request Time-out). По умолчанию — 60 секунд.
client_header_timeout — задает тайм-аут для чтения заголовка запроса. Если клиент не успеет передать заголовок за установленное время, Nginx разрывает соединение с ошибкой 408 (Request Time-out).
send_timeout — если клиент прекратит чтение ответа, сервер дождется установленное время и затем закроет соединение. По умолчанию — 60 секунд.
client_body_buffer_size — задает размер буфера для чтения тела запроса клиента. Если тело запроса больше буфера, его часть записывается во временный файл.
client_header_buffer_size — определяет размер буфера для заголовка клиентского запроса.
client_max_body_size — устанавливает максимально допустимый размер тела запроса клиента. Если размер превышает допустимый, возвращается ошибка 413 (Request Entity Too Large).
large_client_header_buffers — задает максимальное количество и размер буферов для обработки крупных заголовков клиента. Если размер строки запроса превышает размер буфера, сервер вернет ошибку 414 (Request-URI Too Large).
Сжатие GZIP
Одним из самых эффективных способов ускорить работу веб-сервера Nginx является включение GZIP-сжатия. GZIP обеспечивает сжатие без потерь, что означает, что исходные данные можно полностью восстановить при распаковке. Сжатие основано на алгоритме DEFLATE, который сочетает в себе алгоритмы LZ77 и Хаффмана.
Большинство современных клиентов и серверов поддерживают GZIP. Когда браузер или другой клиент, совместимый с GZIP, запрашивает ресурс у сервера с поддержкой GZIP, сервер сжимает ответ перед отправкой. Это позволяет значительно уменьшить объем передаваемых данных и ускорить загрузку страниц.
Пример конфигурации для включения GZIP-сжатия в Nginx. Откройте основной файл конфигурации /etc/nginx/nginx.conf и добавьте следующие директивы в блок http:
http {
...
gzip on;
gzip_min_length 500;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css text/javascript application/javascript application/x-javascript text/xml application/xml application/xml+rss application/json;
gzip_comp_level 6;
gzip_buffers 16 8k;
...
}gzip — включает сжатие GZIP на сервере.
gzip_min_length — устанавливает минимальный размер ответа, для которого будет применяться сжатие. По умолчанию значение равно 20 байтам, но имеет смысл установить большее значение (например, 500 байт), так как сжатие слишком маленьких файлов может создать ненужную нагрузку на процессоры сервера и клиента.
gzip_vary — добавляет заголовок Vary: Accept-Encoding в ответ сервера. Это позволяет кэшировать как сжатые, так и несжатые версии одного ресурса в зависимости от того, поддерживает ли клиент GZIP-сжатие.
gzip_proxied — определяет, нужно ли сжимать ответы для проксированных запросов в зависимости от их содержимого. Запрос считается проксированным, если в его заголовке присутствует поле Via. Можно указать несколько условий для применения сжатия:
Параметры gzip_proxied
off отключает сжатие для всех проксированных запросов.
expired разрешает сжатие, если в заголовке ответа есть поле Expires, запрещающее кэширование.
no-cache сжатие разрешено, если в заголовке ответа есть поле Cache-Control с параметром no-cache.
no-store сжатие разрешено, если в заголовке ответа есть поле Cache-Control с параметром no-store.
private разрешает сжатие, если в заголовке ответа есть поле Cache-Control с параметром private.
no_last_modified разрешает сжатие, если в заголовке ответа отсутствует поле Last-Modified.
no_etag разрешает сжатие, если в заголовке ответа нет поля ETag.
auth сжатие разрешено, если в заголовке запроса есть поле Authorization.
any разрешает сжатие для всех проксированных запросов без ограничений.
gzip_types — задает список типов MIME, для которых будет применяться сжатие. По умолчанию GZIP включен для ответов типа text/*. В данном примере сжатие включено для текстовых файлов, CSS, JavaScript и JSON.
gzip_comp_level — устанавливает уровень сжатия. Рекомендуемое значение — 6, так как оно обеспечивает баланс между скоростью сжатия и эффективностью (по умолчанию уровень сжатия равен 1, а максимальный — 9).
gzip_buffers — задает количество и размер буферов для хранения сжатых данных перед отправкой клиенту. В данном случае установлено 16 буферов по 8К.
Сжатие Brotli
Brotli — более современный алгоритм сжатия от Google, который обеспечивает на 15–25% лучшее сжатие по сравнению с GZIP при сопоставимой скорости. Все современные браузеры поддерживают Brotli через заголовок Accept-Encoding: br.
Brotli не входит в стандартную сборку Nginx — потребуется модуль ngx_brotli. В большинстве пакетных менеджеров он доступен как nginx-module-brotli или libnginx-mod-brotli.
http {
...
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css text/javascript application/javascript application/json application/xml image/svg+xml;
...
}brotli — включает сжатие Brotli.
brotli_comp_level — уровень сжатия от 1 до 11. Значение 6 обеспечивает хороший баланс между скоростью и степенью сжатия. Для предварительного сжатия статики можно использовать максимальный уровень 11.
brotli_types — типы MIME для сжатия, аналогично gzip_types.
Brotli и GZIP не конфликтуют — Nginx выберет алгоритм по заголовку клиента. Если браузер поддерживает оба, приоритет получит Brotli.
Предварительное сжатие статики
Конфигурация выше сжимает каждый ответ на лету, тратя CPU на каждый запрос. Для статических файлов (CSS, JS, SVG, JSON) это расточительно — содержимое не меняется между деплоями, а сжимается каждый раз заново.
Директивы gzip_static и brotli_static решают эту проблему: Nginx ищет заранее сжатые файлы .gz и .br рядом с оригиналом и отдаёт их без сжатия на лету.
server {
...
location ~* \.(css|js|svg|json|html|xml)$ {
gzip_static on;
brotli_static on;
}
...
}Остаётся создать сжатые копии. Проще всего — добавить шаг в CI/CD при деплое:
find /var/www/static -type f \( -name "*.css" -o -name "*.js" -o -name "*.svg" -o -name "*.json" \) \
-exec gzip -9 -k {} \; \
-exec brotli -9 -k {} \;Флаг -k сохраняет оригинал — Nginx будет отдавать его клиентам без поддержки сжатия.
Такой подход позволяет использовать максимальный уровень сжатия (9 для GZIP, 11 для Brotli) без влияния на время ответа — вся работа делается один раз при деплое.
Кэширование на стороне браузера
Статический контент — это элементы веб-сайта, которые остаются неизменными на протяжении долгого времени на всех страницах. К такому контенту относятся файлы изображений, CSS и JavaScript. Поскольку эти файлы редко изменяются, их можно сохранять в кэше браузера пользователя. Это позволяет браузеру загружать локальные копии файлов, а не запрашивать их каждый раз с сервера, что ускоряет работу сайта.
Чтобы настроить кэширование статического контента, можно добавить следующие директивы в основной конфигурационный файл Nginx:
server {
...
# Media
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|mp4|ogg|ogv|webm|htc)$ {
expires 30d;
}
# CSS and Js
location ~* \.(css|js|woff2)$ {
expires 365d;
add_header Cache-Control "public, immutable";
}
...
}В этом примере медиа-файлы, такие как изображения и видео, будут кэшироваться на 30 дней, а файлы CSS, JS и шрифты — на 365 дней.
Директива immutable в заголовке Cache-Control указывает браузеру, что файл не изменится до истечения срока кэша. Без неё браузер всё равно отправляет условный запрос (If-Modified-Since) при каждой навигации, даже если кэш ещё актуален. Для файлов с fingerprint это лишний запрос.
Fingerprint
Однако, если дизайн сайта обновляется, пользователи могут продолжать использовать устаревшую версию CSS-файлов, что может вызвать проблемы с отображением страницы. Чтобы избежать этого, рекомендуется использовать fingerprint для файлов.
Fingerprint — это метод, при котором при каждом изменении файла его название изменяется. Обычно это делается путем добавления префикса или суффикса, сгенерированного на основе хэша файла. Например, для файла стилей style.css можно вычислить его MD5-хэш и добавить его к имени файла. В итоге получится файл с именем style.e626dd36e0085927f334adbe3eb38e7a.css.
Каждый раз, когда файл изменяется, хэш пересчитывается, и файл получает новое имя. Это заставляет браузер скачать актуальную версию файла, игнорируя старую кэшированную копию.
Кэширование на стороне Nginx
Для повышения производительности можно кэшировать ответы на запросы на стороне Nginx, которые редко изменяются. Это позволяет серверу один раз получить результат от вашего приложения и в дальнейшем возвращать его другим клиентам, снижая нагрузку на приложение.
Для начала необходимо создать директорию, в которой будут храниться данные кэша:
sudo mkdir -p /var/nginx/cacheПосле этого, в основной конфигурационный файл nginx.conf нужно добавить несколько директив:
http {
proxy_cache_path /var/nginx/cache levels=1:2 keys_zone=nginxcash:60m max_size=256m inactive=24h;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_methods GET HEAD;
proxy_cache_min_uses 2;
}proxy_cache_path — указывает путь к директории, где будут храниться кэшированные данные.
- Параметр
levelsзадает структуру папок для хранения кэша, keys_zone определяет размер зоны для хранения метаданных (в данном случае 60 мегабайт). max_size=256mзадает максимальный размер кэша.inactive=24hуказывает, что кэшированные данные, к которым не было обращений в течение 24 часов, будут автоматически удалены.
proxy_cache_key — определяет ключ кэширования. В данном случае используется комбинация схемы запроса, метода, хоста и URI. Этот ключ позволяет разделить кэш для разных поддоменов и запросов.
proxy_cache_methods — указывает, какие HTTP-методы будут кэшироваться (в данном примере — только методы GET и HEAD).
proxy_cache_min_uses — задает минимальное количество обращений к ресурсу перед его кэшированием. Установка значения 2 означает, что кэширование начнется только после второго обращения, что предотвращает кэширование редко используемых данных и снижает нагрузку на запись.
Переносим кэш Nginx в RAM
Чтобы значительно ускорить кэш, можно разместить его в оперативной памяти (RAM) вместо файловой системы. Это позволит значительно сократить время доступа к кэшированным данным.
Для этого создаем директорию для кэша (если она уже создана, нужно очистить её от содержимого) и монтируем её в RAM с помощью tmpfs. Выделим 256 мегабайт под кэш:
sudo mount -t tmpfs -o size=256M tmpfs /var/nginx/cacheЕсли потребуется отключить RAM-кэш, выполните команду:
sudo umount /var/nginx/cacheЧтобы автоматически пересоздавать кэш в RAM после перезагрузки системы, необходимо обновить файл /etc/fstab. Добавьте в него следующую строку:
tmpfs /var/nginx/cache tmpfs defaults,size=256M 0 0
Оптимизация работы с файлами
Для повышения производительности Nginx можно использовать ряд настроек, которые оптимизируют работу с файлами. Эти настройки помогают ускорить передачу данных и снизить нагрузку на систему.
http {
...
sendfile on;
aio on;
tcp_nopush on;
open_file_cache max=100000 inactive=20s;
open_file_cache_valid 45s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
...
}sendfile — включает использование системного вызова sendfile(), который обеспечивает более эффективную передачу файлов. Вместо использования отдельных вызовов для чтения и записи (read и write), sendfile() позволяет напрямую передавать данные из файловой системы в сетевое соединение. Это значительно ускоряет передачу больших файлов, таких как изображения или видео.
aio — активирует асинхронный ввод-вывод (AIO), который позволяет серверу обрабатывать файловые запросы асинхронно. Это сокращает время ожидания при обработке запросов, устраняя блокировки потоков и очереди операций чтения/записи.
tcp_nopush — позволяет передавать заголовок HTTP-ответа и начало файла в одном сетевом пакете, что снижает количество отправляемых пакетов и уменьшает накладные расходы на установку соединения.
open_file_cache — включает кэширование информации о файлах, с которыми работает Nginx. По умолчанию эта опция отключена. Настройка позволяет кэшировать данные о состоянии файлов (например, наличие, размер, права доступа), что снижает нагрузку на файловую систему при частых обращениях к одним и тем же файлам.
open_file_cache_valid задает время, через которое веб-сервер будет проверять актуальность данных. По умолчанию 60 секунд.
max=100000— определяет максимальное количество файловых дескрипторов, которые могут быть кэшированы одновременно.inactive=20s— задает время, в течение которого файл будет оставаться в кэше, если к нему не было обращений. После этого периода файл удаляется из кэша, если не был запрошен заново.
open_file_cache_min_uses — определяет минимальное количество обращений к файлу, чтобы дескриптор файла остался в кэше. В данном примере, файл должен быть запрошен не менее двух раз, чтобы оставаться в кэше.
open_file_cache_errors — включает кэширование ошибок, связанных с файлами (например, если файл не найден). Это позволяет избежать повторного обращения к файлу, который отсутствует или к которому нет доступа, и снижает нагрузку на файловую систему.
Оптимизация SSL/TLS
Если ваш сайт работает через HTTPS, настройка SSL/TLS может заметно сократить время установки соединения.
server {
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
}ssl_protocols — включает только TLS 1.2 и 1.3. Более старые версии (SSLv3, TLS 1.0, TLS 1.1) уязвимы и отключены в современных браузерах.
ssl_session_cache — кэширует параметры SSL-сессий в разделяемой зоне памяти. 10 мегабайт хватает примерно на 40 000 сессий. Повторное подключение клиента происходит без полного TLS-рукопожатия.
ssl_session_timeout — время жизни кэшированной сессии. Значение 1 день — разумный баланс между производительностью и безопасностью.
ssl_session_tickets off — отключает session tickets. Они удобны, но ключ шифрования tickets не ротируется автоматически, что ослабляет forward secrecy.
ssl_stapling — включает OCSP Stapling. Nginx сам запрашивает статус сертификата у центра сертификации и отдаёт его клиенту вместе с сертификатом, экономя клиенту отдельный запрос к OCSP-серверу.
resolver — DNS-сервер для OCSP-запросов. Необходим для работы ssl_stapling.
Прочие оптимизации
Оптимизация журнала доступа
Ведение журнала важно для устранения неполадок и аудита работы сервера. Однако запись каждого запроса, поступающего на сервер, может снижать производительность Nginx.
Существует два подхода для решения этой проблемы:
- Полное отключение ведения журнала доступа — используется в случаях, когда нет необходимости в записи всех запросов. Это позволяет сократить нагрузку на диск.
- Буферизация журнала доступа — вместо записи каждого запроса по отдельности, Nginx будет буферизировать несколько записей и сохранять их на диск пакетами. Это уменьшает количество операций записи и повышает производительность.
Для отключения журнала достаточно добавить следующую директиву в конфигурацию:
http {
access_log off;
}Буферизация может быть настроена с использованием двух триггеров:
- Буфер заполняется — запись на диск происходит, когда буфер полностью заполнен.
- Таймер flush — данные в буфере записываются на диск, если они находились там дольше, чем указано в параметре
flush.
Пример настройки буферизации:
server {
...
access_log /var/log/nginx/fast_api.log combined buffer=256k flush=10s;
error_log /var/log/nginx/fast_api.err.log;
}В этой конфигурации Nginx будет записывать данные журнала на диск, когда размер буфера достигнет 256 КБ или если данные находятся в буфере дольше 10 секунд.
HTTP/2 и HTTP/3
HTTP/2 позволяет браузеру загружать несколько ресурсов через одно TCP-соединение вместо открытия отдельного соединения на каждый файл. Это особенно заметно на страницах с большим количеством CSS, JS и изображений.
Начиная с Nginx 1.25.1 синтаксис включения HTTP/2 изменился — параметр http2 вынесен из директивы listen в отдельную:
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
}HTTP/3
Nginx поддерживает HTTP/3 начиная с версии 1.25.0. Протокол использует QUIC поверх UDP, что устраняет блокировку очереди (head-of-line blocking) на транспортном уровне и ускоряет установку соединения — особенно на мобильных сетях с потерями пакетов.
server {
listen 443 ssl;
listen 443 quic;
http2 on;
http3 on;
add_header Alt-Svc 'h3=":443"; ma=86400';
}Заголовок Alt-Svc сообщает браузеру о поддержке HTTP/3 — при следующем подключении клиент попробует QUIC.
Для работы HTTP/3 необходимо открыть UDP-порт 443 в файрволе.
QUIC в России. С 2022 года ТСПУ блокирует QUIC-трафик к зарубежным серверам по анализу UDP/443-пакетов. Браузеры автоматически откатываются на HTTP/2 через TCP, но первое подключение будет медленнее из-за таймаута QUIC. Если ваш сервер расположен за рубежом и основная аудитория в России — отправлять заголовок Alt-Svc может быть нецелесообразно.
Безопасность
Помимо оптимизации времени отклика веб-сервера, необходимо уделить внимание вопросам безопасности. Рассмотрим ключевые HTTP-заголовки, которые помогут защитить ваш сайт от распространенных угроз.
X-Frame-Options
Заголовок X-Frame-Options предотвращает атаки типа clickjacking (перехват кликов), запрещая загрузку вашей страницы в frame или iframe. Этот заголовок говорит браузеру, как следует обрабатывать страницы, встраиваемые в iframe, и снижает риск того, что злоумышленники могут использовать ваш сайт в таких атаках.
Способы настройки:
DENY— полностью запрещает использование страницы в iframe.SAMEORIGIN: — разрешает использование iframe только для страниц с того же домена.ALLOW-FROM— разрешает использование iframe только с определенных URL-адресов.
Пример настройки для запрета использования iframe:
server {
...
add_header X-Frame-Options "DENY";
...
}Параметр ALLOW-FROM не поддерживается современными браузерами. Для гибкого контроля встраивания используйте Content-Security-Policy: frame-ancestors (описан ниже).
Strict-Transport-Security
Заголовок Strict-Transport-Security (HSTS) обеспечивает использование только защищенных HTTPS-соединений на сайте. Он запрещает использование HTTP-протокола, перенаправляя все запросы на HTTPS, и защищает сайт от атак типа “downgrade” (понижение протокола).
Настройка заголовка HSTS может выглядеть так:
server {
...
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
...
}Параметр max-age=31536000 указывает, что браузер должен запоминать настройку в течение года, а includeSubDomains применяет политику ко всем поддоменам.
X-Content-Type-Options
Заголовок X-Content-Type-Options предотвращает браузерам (особенно Internet Explorer) “угадывать” тип содержимого файла на основе его содержимого, а не заголовка MIME. Это важно для защиты от атак, при которых текстовые файлы могут быть интерпретированы как скрипты.
Пример настройки:
server {
...
add_header X-Content-Type-Options nosniff;
...
}Заголовок nosniff запрещает браузеру изменять тип содержимого, что помогает предотвратить возможные XSS-атаки.
Content-Security-Policy
Заголовок Content-Security-Policy (CSP) — основной инструмент защиты от XSS-атак. Он определяет, какие ресурсы браузер может загружать на странице: скрипты, стили, изображения, шрифты, фреймы.
server {
...
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'none';" always;
...
}default-src 'self' — по умолчанию разрешает загрузку ресурсов только с текущего домена.
script-src 'self' — скрипты только с текущего домена. Блокирует inline-скрипты и скрипты с чужих доменов — основная защита от XSS.
frame-ancestors 'none' — запрещает встраивание страницы в iframe. Заменяет X-Frame-Options: DENY.
CSP требует тщательной настройки под конкретный сайт. Начните с заголовка Content-Security-Policy-Report-Only, чтобы выявить нарушения, не ломая работу сайта.
Permissions-Policy
Заголовок Permissions-Policy ограничивает доступ страницы к API браузера: камера, микрофон, геолокация, автовоспроизведение видео. Если вашему сайту не нужны эти функции, лучше явно их запретить.
server {
...
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;
...
}Пустые скобки () означают полный запрет. Для разрешения на текущем домене используется (self).
Резюмирую
Мы рассмотрели основные направления оптимизации Nginx:
- Сжатие — GZIP и Brotli на лету, а для статики предварительное сжатие через gzip_static и brotli_static, чтобы не тратить CPU на каждый запрос.
- Кэширование — на стороне браузера с fingerprint и immutable, на стороне Nginx с возможностью размещения кэша в RAM.
- Работа с файлами — sendfile, асинхронный I/O, кэширование файловых дескрипторов.
- SSL/TLS — кэш сессий, OCSP Stapling, актуальные протоколы.
- Протоколы — HTTP/2 и HTTP/3 для параллельной загрузки ресурсов.
- Безопасность — HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Permissions-Policy.