Nginx — веб-сервер и reverse proxy
Nginx (произносится «engine-x») — высокопроизводительный веб-сервер, который обслуживает более трети сайтов в интернете. В этом уроке ты научишься устанавливать Nginx, настраивать виртуальные хосты, раздавать статику, проксировать приложения и включать HTTPS.
1. Что такое веб-сервер и зачем Nginx
Веб-сервер — программа, которая принимает HTTP-запросы от браузеров и отвечает файлами или результатами работы приложения. Nginx — один из самых популярных веб-серверов, но его главная особенность в том, что он также отлично работает как reverse proxy: принимает запросы снаружи и передаёт их внутренним приложениям.
Проверить, какой сервер отдаёт сайт, можно через HTTP-заголовок Server:
curl -I https://example.com
# HTTP/2 200
# server: nginx
# date: Sat, 19 Sep 2026 10:00:00 GMTКлассическую альтернативу — Apache — Nginx чаще всего превосходит по производительности на статике благодаря событийной модели обработки соединений.
| Характеристика | Nginx | Apache |
|---|---|---|
| Модель обработки | событийная, один процесс | процесс на соединение |
| Статические файлы | очень быстро | быстро |
| Гибкие .htaccess | нет | да |
| Reverse proxy «из коробки» | да | требует модулей |
.htaccess как Apache — вся конфигурация живёт в файлах конфигурации сервера.2. Установка Nginx
Проще всего установить Nginx из репозитория дистрибутива. На Ubuntu и Debian:
sudo apt update
sudo apt install -y nginx
sudo systemctl enable --now nginx
sudo systemctl status nginxПроверь, что сервер отвечает:
curl http://localhost
# приветственная HTML-страница Nginx
nginx -v
# nginx version: nginx/1.24.0start nginx запускает сервер, nginx -s stop останавливает. Однако для практики надёжнее использовать Docker: docker run -d -p 80:80 nginx.nginx -t (проверка синтаксиса) и nginx -s reload (перезагрузка без остановки). Забудь про них — и одна опечатка в конфиге уронит весь сайт.3. Директивы server и location
Рабочая конфигурация Nginx собирается из блоков. Главный файл — /etc/nginx/nginx.conf, а отдельные сайты обычно лежат в /etc/nginx/sites-available и подключаются симлинками из /etc/nginx/sites-enabled.
Минимальный server-блок описывает один домен:
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}listen— порт и IP, на котором сервер принимает соединения.server_name— домен, по которому выбирается блок.root— директория с файлами сайта.location— правило для подмножества URI.
Каждый location обрабатывает запросы по пути: location /images/ — все пути, начинающиеся с /images/.
| Директива | Что задаёт |
|---|---|
| listen | порт и адрес: 80, 443 ssl, 127.0.0.1:8080 |
| server_name | домен или шаблон: *.example.com |
| root | базовая директория для файлов |
| index | файл, отдаваемый для каталога: index.html |
| location | правило маршрутизации по URI |
try_files $uri $uri/ =404 сначала ищет точный файл, затем каталог, а если ничего нет — отдаёт ошибку 404.4. Статическая раздача файлов
Nginx отлично справляется с раздачей картинок, CSS, JS и других статических файлов без участия бэкенда. Для сайта-одностраничника достаточно одного server-блока.
server {
listen 80;
server_name static.example.com;
root /srv/www/static.example.com;
location /assets/ {
expires 30d;
add_header Cache-Control "public";
}
location / {
try_files $uri $uri/ /index.html;
}
}Директива expires 30d добавляет браузеру заголовки кэширования: повторные заходы на страницу станут заметно быстрее.
root и alias. root подставляет путь к корню в начало URI, а alias заменяет совпавшую часть location целиком.| Директива | URI /assets/img/logo.png |
|---|---|
| root /srv/www; | файл /srv/www/assets/img/logo.png |
| location /assets/ { alias /srv/files/; } | файл /srv/files/img/logo.png |
dist/ как статику — бэкенд при этом не нужен до появления форм и API.5. Виртуальные хосты
На одном сервере Nginx может обслуживать много доменов. Каждый домен — отдельный server-блок в отдельном файле, а выбор происходит по server_name.
Создай файл /etc/nginx/sites-available/shop.conf:
server {
listen 80;
server_name shop.example.com;
root /var/www/shop/public;
index index.php index.html;
}Затем включи хост симлинком и перезагрузи конфигурацию:
sudo ln -s /etc/nginx/sites-available/shop.conf /etc/nginx/sites-enabled/shop.conf
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginxsites-enabled подключаются в главный файл директивой include. Если в DNS домен ещё не указывает на сервер, проверяй локально через curl -H "Host: shop.example.com" http://localhost.-s создаст копию, и правки исходного файла не будут подхватываться. Бесплатный способ наделать багов в продакшене.6. Reverse proxy на приложение
Веб-приложения (Django, FastAPI, Node.js) слушают свой порт, например 8000. Nginx стоит перед ними и передаёт запросы через директиву proxy_pass. Такой сервер называется reverse proxy.
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:8000;
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_pass— адрес внутреннего приложения.proxy_set_header Host $host— сохраняет исходный домен запроса.X-Forwarded-For— реальный IP клиента, иначе приложение увидит адрес Nginx.
| Директива | Назначение |
|---|---|
| proxy_pass | куда передавать запросы |
| proxy_connect_timeout | время ожидания соединения с бэкендом |
| proxy_read_timeout | время ожидания ответа приложения |
| client_max_body_size | максимальный размер тела запроса (загрузки файлов) |
proxy_pass http://127.0.0.1:8000; и proxy_pass http://127.0.0.1:8000/; — слоб слэш на конце. / отбрасывает совпавшую часть URI location, что часто ломает пути приложения.X-Forwarded-Proto и X-Forwarded-For.7. Балансировка нагрузки
Когда одно приложение не справляется, за ним ставят несколько инстансов, а Nginx распределяет трафик между ними. Группа бэкендов описывается блоком upstream.
upstream backend {
least_conn;
server 10.0.0.1:8000 weight=3;
server 10.0.0.2:8000;
server 10.0.0.3:8000 backup;
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://backend;
}
}По умолчанию запросы уходят по кругу (round-robin). Дополнительные параметры:
weight=3— этот сервер получает втрое больше запросов;backup— сервер включается только когда основные недоступны;least_conn— балансировка по числу активных соединений;ip_hash— один и тот же клиент попадает на один бэкенд (для сессий).
| Метод | Когда использовать |
|---|---|
| round-robin | равномерное распределение по умолчанию |
| weight | бэкенды разной мощности |
| least_conn | запросы с разной длительностью |
| ip_hash | нужны стабильные сессии пользователя |
nginx-plus или внешние инструменты.8. HTTPS и переадресация
Современные сайты обязаны работать по HTTPS. Сначала все HTTP-запросы перенаправляются на HTTPS, а затем уже работает защищённый server-блок с сертификатом.
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /var/www/example;
}Самый быстрый способ получить бесплатный сертификат — Certbot, который сам обновляет конфигурацию Nginx:
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com| Директива | Назначение |
|---|---|
| return 301 | постоянная переадресация на HTTPS |
| ssl_certificate | путь к сертификату (цепочка) |
| ssl_certificate_key | путь к приватному ключу |
| add_header Strict-Transport-Security | запрет доступа по HTTP на уровне браузера |
systemd timer — проверяй, что служба включена.9. Логирование
Nginx пишет два лога: access.log — каждый запрос и error.log — ошибки и предупреждения. Формат записей настраивается директивой log_format.
http {
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
}Смотреть логи в реальном времени:
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log| Код | Что значит в error.log |
|---|---|
| emerg | система не может работать, конфигурация критически неверна |
| alert | требуется немедленное вмешательство |
| error | запрос не обработан (5xx, таймауты) |
| warn | нештатная, но обработанная ситуация |
| info / debug | отладочные детали (debug включается отдельно) |
logrotate: старые файлы сжимаются и удаляются по расписанию, поэтому ручная чистка не нужна.10. Сжатие gzip и кэширование
Сжатие ответов сокращает трафик и ускоряет загрузку сайта. Директива gzip включается на уровне http:
gzip on;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_types text/plain text/css application/json
application/javascript application/xml
image/svg+xml;Сжатие gzip_types применяется только к типизированным ответам — картинки JPEG и PNG уже сжаты и обрабатывать их незачем.
Кэширование уменьшает нагрузку на бэкенд за счёт сохранения ответов Nginx. Для статики достаточно заголовков браузера:
location /assets/ {
expires 30d;
add_header Cache-Control "public, immutable";
}
location ~* \.(css|js|png|jpg|svg|woff2)$ {
expires 7d;
add_header Cache-Control "public";
}| Директива | Назначение |
|---|---|
| gzip_level | степень сжатия 1–9 (6 — оптимум) |
| expires | срок жизни кэша в браузере |
| proxy_cache_path | диск для кэша ответов проксируемых приложений |
| map $http_upgrade | поддержка WebSocket через proxy |
Cache-Control: immutable означает «не перезапрашивать никогда». Используй его только для хэшированных имён файлов сборщиками, иначе пользователи не увидят обновления.proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=app:10m max_size=1g inactive=60m; и proxy_cache app;.11. WebSocket, SSE и push-уведомления
Nginx отлично проксирует долгоживущие соединения, но для этого ему нужно открыть обновление соединения и снять таймауты. Иначе WebSocket-рукопожатие закроется через 60 секунд.
location /ws/ {
proxy_pass http://backend_nodes;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
}12. Ограничение нагрузки и DDoS-защита
Модуль limit_req ограничивает частоту запросов с IP или по любому ключу. Он работает через «дырявое ведро»: избыточные запросы получат 503 вместо выполнения.
http {
limit_req_zone $binary_remote_addr
zone=api:10m rate=10r/s;
server {
location /api/ {
limit_req zone=api burst=20 nodelay;
proxy_pass http://backend;
}
}
}- burst — кратковременная очередь сверх лимита.
- nodelay — отдавать запросы из очереди без задержки.
- limit_conn — ограничение одновременных соединений клиента.
13. Redirect, rewrite и канонические URL
Корректные редиректы важны для SEO и миграций. rewrite менят URI «на лету», return отвечает кодом напрямую и запрещает перезапись на следующих уровнях.
# HTTP → HTTPS
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
# Канонический домен
server {
listen 443 ssl;
server_name www.example.com;
return 301 https://example.com$request_uri;
}14. Проверка конфигурации и мониторинг
Ошибка в конфиге оставляет сайт недоступным. Сначала всегда проверяйте синтаксис, потом перезагружайте конфигурацию без остановки сервера.
# Проверка синтаксиса
nginx -t
# Применение изменений без паузы
nginx -s reload
# Активные соединения и статистика
curl http://127.0.0.1/nginx_status| Лог | Путь по умолчанию |
|---|---|
| Доступ | /var/log/nginx/access.log |
| Ошибки | /var/log/nginx/error.log |
| EC2/VM | можно перенаправить в stdout |
15. Nginx в Docker: практичная сборка
Контейнер с Nginx удобен для локальной разработки и деплоя. Возьмите официальный образ nginx:alpine, смонтируйте конфиг и статику через volume, а при релизе соберите образ с файлами внутри — так приложение станет самодостаточным артефактом.
# nginx.conf кладём в ./conf
server {
listen 80;
root /usr/share/nginx/html;
location /api/ {
proxy_pass http://backend:3000;
}
}docker run --rm -d -p 8080:80 \
-v "$PWD/site:/usr/share/nginx/html" \
-v "$PWD/conf:/etc/nginx/conf.d:ro" \
nginx:alpineВнутри compose-сети адрес бэкенда — имя сервиса (backend), а не localhost. Не зашивайте хардкод доменов: передавайте их переменными окружения через шаблон envsubst, чтобы один конфиг работал в dev и prod.
16. Тюнинг производительности и microcaching
Базовый деплой легко ускорить без смены архитектуры: включите keepalive, кэш открытых файлов и, главное, microcaching — кэширование составных страниц на доли секунды. Для push-уведомлений и персонализации, где кэш недопустим, добавьте исключения по cookie.
http {
proxy_cache_path /tmp/nxcache levels=1:2
keys_zone=cz:10m max_size=1g;
server {
location / {
proxy_cache cz;
proxy_cache_valid 200 1s;
proxy_cache_key "$request_uri$cookie_session";
proxy_cache_bypass $cookie_session;
}
}
}Ключ кэша должен включать то, что влияет на ответ: параметры запроса, заголовок Accept-Language или идентификатор сессии, если страница персонализирована. Метрика $upstream_cache_status в логе покажет, сколько запросов реально отдано из кэша (HIT/MISS).
- Держите worker_connections и worker_processes под числом ядер.
- Включайте open_file_cache для статики — меньше системных вызовов.
- Кэш TTL подбирайте от частоты изменения данных, а не «на глаз».
17. Аутентификация и авторизация через auth_request
Директива auth_request делегирует проверку доступа внешнему сервису: Nginx делает внутренний запрос на онлайн-эндпоинт, и если тот вернул 200 — пропускает пользователя дальше. Так можно закрыть админку, лендинг для партнёров или API.
server {
location = /auth-check {
internal;
proxy_pass http://auth-service:8888/v1/verify;
proxy_set_header Cookie $http_cookie;
}
location /admin/ {
auth_request /auth-check;
auth_request_set $user $upstream_http_x_user;
proxy_set_header X-User $user;
proxy_pass http://admin-ui:3000;
}
}Сервис авторизации возвращает в заголовках данные о пользователе, которые auth_request_set перекладывает в переменную и передаёт бэкенду. Отдельный эндпоинт под токен, отозванный после логаута, обновляет состояние мгновенно — без ждать истечения cookie.
18. Медиа и стриминг: mp4, HLS и диапазонные запросы
Nginx отдаёт видео и потоковый контент с минимальной настройкой. Для mp4 включите модуль ngx_http_mp4_module: он поддерживает перемотку через range-запросы и не отдаёт файл целиком при поиске по таймлайну.
location /video/ {
mp4;
mp4_buffer_size 1M;
mp4_max_buffer_size 5M;
root /srv/media;
expires 7d;
add_header Accept-Ranges bytes;
}Для адаптивного стриминга на любых устройствах укладывайте контент в HLS: сервер раздаёт плейлисты .m3u8 и сегменты .ts как статику, а переключение качества и буферизацию делает плеер. Ограничьте параллельные запросы к сегментам через limit_conn, чтобы один поток не вытеснил остальных зрителей.
19. PHP-FPM и динамические страницы
Nginx не исполняет PHP напрямую: запросы передаются процессу PHP-FPM по протоколу FastCGI. Связка типична для WordPress, Битрикса и большинства CMS: статику отдаёт Nginx, а динамику — пул PHP-воркеров.
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}Второй блок закрывает прямой доступ: все запросы, не совпавшие с реальным файлом, уходят в index.php — так фронт-контроллер приложения получает любой маршрут, а файлы загрузки не исполняются даже при верном расширении.
- Настраивайте pm.max_children из расчёта памяти: переполнение пула давит CPU.
- Папки загрузок (uploads) держите вне root или с fastcgi_pass, отключённым для них.
- Версии PHP согласовывайте с требованиями CMS и модулями расширений.
20. Надёжность upstream: таймауты и health-чеки
Когда инстанс приложения падает, Nginx должен быстро переключиться на здоровый. Для этого используют таймауты, счётчики сбоев и проверки доступности: неисправный сервер снимается с ротации, а запрос уходит в резерв.
upstream backend {
server app1:8080 max_fails=3 fail_timeout=30s;
server app2:8080 max_fails=3 fail_timeout=30s;
keepalive 32; // пул соединений
}
location / {
proxy_pass http://backend;
proxy_connect_timeout 3s;
proxy_read_timeout 10s;
proxy_next_upstream error timeout;
proxy_next_upstream_tries 2;
}- max_fails / fail_timeout
- сколько сбоев за период выводит узел из пула
- proxy_next_upstream
- какие ошибки разрешают переключение на следующий сервер
- proxy_read_timeout
- максимум ожидания ответа от приложения
Для активных проверок установите health-checks (коммерческая версия) или примените пассивный контроль через счётчики сбоев. Ретраи на POST-запросы включайте осторожно: повторный платёж может улететь дважды.
21. map, geo и динамические переменные
Директивы map и geo вычисляют переменные по условиям и избавляют от громоздких конструкций с if. Классический пример — поддержка WebSocket: значение заголовка Connection зависит от Upgrade-заголовка клиента.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
geo $is_allowed {
default 0;
192.168.0.0/16 1;
}
location /ws {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}Гео-режимы применяют для региона-контроля и A/B-экспериментов, а map позволяет строить вложенные условия, не засоряя конфиг. Переменные вычисляются один раз на запрос и доступны во всех директивах.
- Выносите повторяющиеся условия в map: код конфига читается лучше и быстрее отлаживается.
- Для geo подключайте внешний файл CIDR-диапазонов: он обновляется без перезагрузки сервера.
- Избегайте if в location: примените map или внутренние редиректы.
22. Stream-модуль: TCP и UDP-проксирование
Помимо HTTP Nginx умеет проксировать сырые TCP- и UDP-потоки через модуль stream. Это удобно для балансировки баз данных, Redis, почтовых серверов и DNS-запросов на сетевом уровне, без переписывания протокола.
stream {
upstream mysql_pool {
server db1:3306;
server db2:3306;
}
server {
listen 3306;
proxy_pass mysql_pool;
proxy_timeout 10s;
proxy_connect_timeout 5s;
}
}Конфиг stream пишется в отдельном контексте верхнего уровня и подключается директивой include stream.conf. Варианты: TLS-терминация для безопасного трафика, балансировка по IP-хешу и ограничение числа подключений.
- Для приложений, требующих прилипание сессии, используйте хэширование по адресу клиента.
- Держите лог stream отдельным, чтобы различать проксированный и HTTP-трафик.
- Redis и MySQL отлично балансируются через stream, если приложение умеет работать с пулом серверов.
Что дальше
Ты научился настраивать Nginx: статику, виртуальные хосты, reverse proxy, балансировку, HTTPS, логи, сжатие и кэширование. Логичный следующий шаг — завернуть Nginx и приложение в Docker и автоматизировать деплой через GitHub Actions. Если хочешь глубже разобраться в HTTP и DNS — читай урок HTTP и DNS.