Публикация

Nginx простыми словами: зачем нужен веб-сервер

30 минАктуально на 9 сентября 2026

Nginx простыми словами

Ты собрал приложение с ИИ, запустил его на своём компьютере, увидел заветное http://localhost:3000 — и всё работает. А потом решил показать проект другим людям, арендовал сервер, запустил там ту же команду — и наткнулся на слово, которое встречается в каждой второй инструкции: Nginx. Что это за зверь, почему без него «наружу» никто не выходит и правда ли он нужен именно тебе — разберём спокойно, без жаргона и без магии.

Содержание
  1. Что такое Nginx простыми словами
  2. Когда новичку Nginx нужен, а когда нет
  3. Обратный прокси: как запрос доходит от браузера до приложения
  4. Статика: как Nginx раздаёт файлы
  5. Nginx: настройка конфига без страха
  6. HTTPS: сертификат перед приложением
  7. Частые ошибки: nginx 502, 404 и права доступа
  8. Nginx, Apache и Caddy — чем отличаются
  9. Частые вопросы
  10. Коротко о главном

Что такое Nginx простыми словами

Nginx (произносится «энджин-экс») — это программа, которая принимает запросы из интернета и решает, что с ними делать. Она стоит на сервере, слушает входящие соединения и либо сама отдаёт нужный файл, либо передаёт запрос дальше — тому приложению, которое умеет отвечать по существу.

Аналогия из офисной жизни: Nginx — это ресепшен в бизнес-центре. Посетитель заходит с улицы и говорит, куда ему надо. Дальше возможны варианты. Если человек просит буклет со стойки — администратор просто протягивает его, никого не отвлекая. Если человеку нужен конкретный отдел — администратор звонит туда по внутреннему номеру, соединяет и передаёт ответ обратно. Внутренние номера с улицы никто не набирает, посетители про них даже не знают: снаружи есть только один вход и один человек, который держит всю маршрутизацию в голове.

Вот это «снаружи один вход, внутри много номеров» и есть главная идея. Твоё приложение слушает какой-нибудь порт вроде 3000 или 8080. Порт — это номер двери на сервере: у одного компьютера один сетевой адрес, но тысячи пронумерованных дверей, и каждая программа занимает свою. Браузер же по умолчанию стучится в дверь 80 (обычный http://) или 443 (защищённый https://). Nginx занимает эти две публичные двери и разводит запросы по внутренним.

Чем веб-сервер отличается от приложения

Разница на первый взгляд неочевидная, потому что и Node.js-приложение, и Nginx умеют «отвечать на запросы по HTTP». Но задачи у них разные.

Приложение знает бизнес-логику. Оно умеет проверить пароль, посчитать рекорд игрока, сходить в базу данных, собрать HTML-страницу под конкретного пользователя. Каждый запрос для него — работа: подумать и сформировать ответ.

Веб-сервер знает про транспорт. Он умеет принять тысячи одновременных соединений, отдать неизменный файл с диска, сжать ответ, разорвать зависшую сессию, зашифровать канал, записать строчку в журнал и переслать запрос дальше. Логики твоего проекта он не понимает вообще и понимать не должен.

Разделение выгодно обеим сторонам. Приложение пишется проще: оно не думает про сертификаты, сжатие и медленных клиентов. Веб-сервер работает быстро: он делает одну узкую задачу и делает её очень хорошо.

Почему Nginx устроен именно так

Классические веб-серверы прошлого поколения на каждое соединение выделяли отдельный процесс или поток операционной системы. Пока клиент качает файл через медленный мобильный интернет, целый процесс сидит и ждёт. Сто медленных клиентов — сто процессов, тысяча — сервер задыхается от переключений между ними.

Nginx построен на другой модели, событийной. Небольшое число рабочих процессов крутится в цикле и обслуживает множество соединений одновременно: пока одно ждёт данных от сети, обрабатываются другие. Соединение стоит немного памяти, а не целый процесс. Отсюда репутация Nginx как сервера, который держит огромное количество параллельных подключений на скромном железе.

Для тебя как новичка вывод простой: Nginx почти никогда не становится узким местом. Если сайт тормозит, виновато обычно приложение, база или сеть, а не он.

💡

Главная мысль: Nginx не «запускает» твой код и не заменяет его. Он стоит перед приложением, встречает посетителей и решает, кому передать запрос.

Когда новичку Nginx нужен, а когда нет

Честный ответ, который редко пишут в инструкциях: для учебной «Змейки» на курсе Nginx не нужен вообще. Игра лежит на GitHub Pages, публичная ссылка работает, сертификат выдан автоматически, чинить нечего. Ставить туда веб-сервер — то же самое, что нанимать вахтёра для двери, которой нет.

Разберём по ситуациям.

Когда точно не нужен

Статический сайт на GitHub Pages. Игра из HTML, CSS и JavaScript, лендинг, портфолио, документация — всё это набор файлов. Их раздаёт инфраструктура GitHub, и делает это лучше, чем ты настроишь на первом своём сервере. Домен и HTTPS подключаются в настройках репозитория.

Приложение на PaaS. PaaS расшифровывается как «платформа как услуга»: ты отдаёшь код, платформа сама собирает его, запускает и выставляет наружу. Внутри у неё, скорее всего, тот же Nginx или что-то похожее, но тебя это не касается — конфиг ты не пишешь. Именно так работают Amvera, Railway, Render и подобные сервисы. Если тебе хватает такого сценария, статья про деплой на Amvera для новичка покажет короткий путь без единой строчки серверных настроек.

Прототип, который смотрит один человек. Пока проект живёт на твоём ноутбуке и его видишь только ты, промежуточные слои — лишние сущности.

Когда Nginx начинает окупаться

У тебя свой виртуальный сервер. Арендованный VPS — пустая машина: там нет ничего, кроме операционной системы. Всё, что делает платформа за тебя, тут придётся сделать самому, и Nginx — стандартный инструмент для этого. Как вообще выглядит аренда такой машины, разобрано в статье про зарубежный VPS на DigitalOcean.

На одном сервере живёт несколько проектов. Два приложения не могут занять один и тот же порт 443. Nginx занимает его один раз и разводит запросы по доменам: игра.твойдомен.ру в одно приложение, блог.твойдомен.ру в другое.

Нужен домен и HTTPS перед приложением. Технически приложение может само работать по HTTPS, но тогда сертификаты, их обновление и перенаправление с http:// придётся встраивать в код. Проще вынести это наружу.

Приложение отдаёт и страницы, и файлы. Картинки, шрифты, собранные скрипты — статика. Отдавать её через Node.js расточительно: приложение будет заниматься перекладыванием байтов вместо своей работы.

Проект в контейнерах. Когда приложение упаковано в Docker, снаружи обычно стоит Nginx, а внутри контейнеры общаются по внутренней сети. Про сами контейнеры есть отдельный разбор — Docker и контейнеры для развёртывания.

Нужны вещи, которых нет в приложении. Ограничение частоты запросов, закрытие раздела паролем, ограничение размера загружаемого файла, аккуратные страницы ошибок, журналы обращений — всё это Nginx умеет из коробки.

Простое правило выбора

Ситуация Что взять
Только файлы, без сервера GitHub Pages
Приложение, но возиться с сервером не хочется PaaS
Свой VPS, один или несколько проектов Nginx перед приложением
Много сервисов, контейнеры, свои правила Nginx как обязательный слой

Идти по этой лесенке лучше снизу вверх и только когда упрёшься в потолок текущего варианта. Преждевременно поднятый сервер — это не «по-взрослому», это лишние часы отладки вместо работы над продуктом.

Обратный прокси: как запрос доходит от браузера до приложения

Словосочетание «nginx proxy» пугает новичков зря. Прокси — это посредник, который передаёт запрос от твоего имени. Обычный прокси работает на стороне клиента: ты просишь его сходить на сайт, сайт видит прокси вместо тебя. Обратный прокси стоит с другой стороны, на стороне сервера: клиент думает, что общается с сайтом напрямую, а на самом деле его встречает Nginx и втихую пересылает запрос куда надо.

Путь запроса по шагам

  1. Ты вводишь в браузере адрес сайта.
  2. Браузер спрашивает у DNS, какой IP-адрес соответствует домену. DNS — это телефонная книга интернета: имена в ней превращаются в числовые адреса.
  3. Получив адрес, браузер открывает соединение на порт 443 этого сервера.
  4. Соединение принимает Nginx. Он расшифровывает трафик и смотрит две вещи: какой домен запрошен и какой путь после домена.
  5. Дальше развилка. Путь ведёт к файлу — Nginx берёт файл с диска и отдаёт сам. Путь ведёт к приложению — Nginx открывает внутреннее соединение на порт вроде 3000 и пересылает запрос туда.
  6. Приложение формирует ответ и отдаёт его Nginx.
  7. Nginx возвращает ответ браузеру — уже зашифрованным и, если нужно, сжатым.

Браузер про шаги 5 и 6 не знает ничего. Для него весь сайт живёт по одному адресу.

flowchart TB
    Browser["Браузер"] --> DNS["DNS: домен в IP"]
    DNS --> Nginx["Nginx: порты 80 и 443"]
    Nginx --> Static["Статика: файлы с диска"]
    Nginx --> App["Приложение на порту 3000"]
    App --> Answer["Ответ браузеру"]
    Static --> Answer

Что даёт эта прослойка

Один публичный вход. Приложения слушают внутренние порты и снаружи недоступны. Это заодно и безопаснее: если приложение не выставлено в интернет напрямую, до него не достучится случайный сканер портов.

Смена приложения без смены адреса. Переписал проект с одного стека на другой, поменял внутренний порт — снаружи ничего не изменилось.

Несколько приложений за одним доменом. Путь /api можно отправить в одно приложение, а всё остальное — в другое. Пользователь видит единый сайт.

Защита от медленных клиентов. Nginx принимает запрос целиком и только потом отдаёт его приложению. Клиент с плохим мобильным интернетом мучает Nginx, а не твой код.

Место для общих правил. Заголовки безопасности, ограничение частоты обращений, лимит на размер загрузки — всё в одном месте, а не в каждом приложении отдельно.

Заголовки, о которых спотыкаются все

Когда Nginx пересылает запрос, приложение видит соединение не от посетителя, а от самого Nginx: с адреса 127.0.0.1. Если не передать исходные данные явно, приложение решит, что все пользователи мира сидят внутри сервера, а сайт работает по обычному http://. Ломается статистика, ломаются ссылки, ломаются перенаправления после входа.

Лечится тремя строчками, которые нужно просто запомнить как обязательные:

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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

Если чат работает на локальном компьютере, но молчит на сервере, начинай проверку именно отсюда.

Статика: как Nginx раздаёт файлы

Статика — это то, что одинаково для всех посетителей: HTML-страницы, стили, скрипты, картинки, шрифты, звуки. Динамика — то, что собирается под конкретного пользователя: личный кабинет, список его рекордов, корзина.

Nginx создавался в том числе ради быстрой раздачи статики, и делает это с минимальными накладными расходами: читает файл с диска и отправляет в сеть, не тратя времени на разбор логики.

Корневой каталог и поиск файла

За раздачу отвечают две вещи: указание корневого каталога и правило поиска.

server {
    listen 80;
    server_name igra.example.ru;

    root /var/www/igra;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

Читается это так. Сервер слушает порт 80 и отзывается на домен igra.example.ru. Файлы лежат в каталоге, указанном в root. Директива try_files перебирает варианты по очереди: сначала ищет файл с точным именем из запроса, потом каталог с таким именем, а если ничего не нашлось — возвращает ошибку 404.

Каталог в примере условный. Куда именно класть файлы, решаешь ты сам; главное, чтобы путь в конфиге совпадал с реальным и у Nginx были права туда заглядывать.

Одностраничные приложения

У приложений, где переходы между «страницами» происходят внутри браузера, файла под адрес /scores на диске нет. Пользователь обновляет страницу на этом адресе и получает 404, хотя по ссылке из меню всё работало. Решается заменой последнего варианта в try_files: вместо ошибки отдавать главный файл, дальше разберётся сам скрипт.

location / {
    try_files $uri $uri/ /index.html;
}

Кэширование и сжатие

Браузер не обязан скачивать один и тот же логотип при каждом заходе. Заголовки кэширования говорят, сколько времени файл можно считать актуальным.

location ~* \.(css|js|png|jpg|svg|woff2)$ {
    expires 30d;
    add_header Cache-Control "public";
}

Тут есть ловушка, на которую попадаются все. Ты выкатываешь новую версию игры, а посетители видят старую — браузер честно берёт файл из кэша, как ему и велели. Выход стандартный: при сборке проекта в имена файлов добавляется отпечаток вроде game.a3f9c1.js. Изменился код — изменилось имя — браузер скачивает заново. Сам HTML при этом кэшировать надолго не стоит, иначе он не узнает про новые имена.

Сжатие уменьшает объём текстовых ответов в несколько раз:

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

Картинки в форматах JPEG и PNG сжимать бессмысленно — они уже сжаты, а процессор потратится зря.

Разделение статики и приложения

Типичная схема для проекта, где есть и то, и другое: файлы отдаёт Nginx, всё остальное уходит в приложение.

server {
    listen 80;
    server_name example.ru;

    location /static/ {
        root /var/www/app;
        expires 7d;
    }

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Приложение при этом вообще не участвует в раздаче картинок и скриптов и занимается только своей работой.

Nginx: настройка конфига без страха

Конфиг Nginx — обычный текстовый файл с блоками в фигурных скобках. Никакого своего языка программирования, только набор указаний вида «параметр значение;». Точка с запятой в конце каждой строки обязательна, и её пропуск — самая частая причина того, что конфиг не проходит проверку.

Как устроена иерархия

Файл читается сверху вниз и состоит из вложенных уровней.

Верхний уровень — общие вещи: от чьего имени работать, сколько рабочих процессов запускать, куда писать журналы.

Блок http — всё, что касается веб-трафика: сжатие, форматы журналов, таймауты, а внутри — сайты.

Блок server — один сайт. Тут указано, какой порт слушать и на какое доменное имя отзываться. Таких блоков может быть сколько угодно.

Блок location — правило для пути внутри сайта. Один location для картинок, другой для API, третий для всего остального.

Схематично:

http {
    gzip on;

    server {
        listen 80;
        server_name example.ru;

        location /api/ {
            proxy_pass http://127.0.0.1:3000;
        }

        location / {
            root /var/www/example;
        }
    }
}

Настройки наследуются сверху вниз: включил сжатие в http — оно работает во всех сайтах, если внутри его явно не отключили.

Где лежат файлы

Главный файл традиционно называется nginx.conf. Рядом обычно есть каталог, куда складывают конфиги отдельных сайтов, и в главном файле стоит директива вроде include, которая их подхватывает. Точные пути зависят от того, как именно установлен Nginx на твоей системе, поэтому надёжнее не гадать, а спросить у самой программы:

nginx -t

Эта команда проверяет конфигурацию и в ответе показывает путь к файлу, который она проверяла. Заодно она — твой главный защитный механизм: никогда не перезагружай Nginx, не прогнав nginx -t. Ошибка в синтаксисе при перезапуске уронит сайт целиком, а проверка ловит её заранее.

Применить изменения без разрыва соединений:

nginx -s reload

При такой перезагрузке старые рабочие процессы дообслуживают текущие запросы и только потом завершаются. Посетители ничего не замечают.

Как выбирается location

Правило, которое экономит часы недоумения: Nginx выбирает один подходящий location, а не применяет все по очереди. Порядок такой. Сначала ищется точное совпадение (location = /health). Потом — самый длинный из подходящих префиксов. Потом проверяются регулярные выражения (location ~* \.png$) в порядке их следования в файле, и первое сработавшее побеждает.

Отсюда типичная путаница: ты дописал правило для картинок в конец файла, а работает предыдущее. Или наоборот — регулярное выражение перехватило запросы, которые ты ждал в общем блоке.

Мелочь, на которой спотыкаются в proxy_pass

Косая черта в конце адреса меняет поведение. Без неё путь запроса приклеивается к адресу целиком, с ней — часть пути, совпавшая с location, отбрасывается.

location /api/ {
    proxy_pass http://127.0.0.1:3000;
}

Запрос /api/scores уйдёт в приложение как /api/scores.

location /api/ {
    proxy_pass http://127.0.0.1:3000/;
}

Тот же запрос придёт как /scores. Разница в одном символе, а результат — либо рабочее API, либо стабильные 404. Когда маршруты «почти работают, но не находятся», проверяй эту черту первым делом.

Минимальный рабочий конфиг

Вот всё, что нужно для одного приложения за доменом. Больше на старте не требуется.

server {
    listen 80;
    server_name example.ru www.example.ru;

    client_max_body_size 10m;

    access_log /var/log/nginx/example.access.log;
    error_log  /var/log/nginx/example.error.log;

    location / {
        proxy_pass http://127.0.0.1:3000;
        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;
    }
}

Параметр client_max_body_size заслуживает отдельного слова: он ограничивает размер тела запроса. По умолчанию лимит небольшой, и загрузка аватарки или картинки для профиля упирается в ошибку 413 — «слишком большой запрос». Люди в этот момент ищут баг в коде приложения, хотя запрос до приложения даже не дошёл.

Порты, домены и мысленная модель

Чтобы всё это перестало быть набором заклинаний, держи в голове три уровня.

Домен — имя, которое человек вводит в браузере. Он должен указывать на IP твоего сервера, и настраивается это не в Nginx, а в DNS-записях у того, где куплен домен. Изменения расходятся по сети не мгновенно, поэтому «настроил, но не открывается» первые часы — норма.

Порт — дверь на сервере. Публичные: 80 и 443. Внутренние: любые свободные, обычно 3000, 5000, 8000, 8080.

Путь — то, что после домена. По нему Nginx выбирает location.

Если хоть одно из трёх не сходится, сайт не откроется, и ошибка при этом будет выглядеть по-разному. Домен не туда указывает — браузер вообще не найдёт сервер. Порт закрыт файрволом — соединение будет висеть и отвалится по таймауту. Путь не подходит ни под один location — придёт 404.

HTTPS: сертификат перед приложением

HTTPS — это тот же HTTP, но внутри зашифрованного канала. Без него данные идут открытым текстом, браузеры показывают предупреждение «не защищено», а часть современных возможностей (например, установка сайта как приложения на телефон) просто не работает. Что такое сертификат и откуда он берётся, подробно разобрано в статье про SSL-сертификат простыми словами.

Почему шифрование логично держать в Nginx

Приём защищённых соединений называют «терминацией»: Nginx расшифровывает трафик снаружи и дальше внутри сервера общается с приложением уже обычным способом. Внутренний участок пути не выходит за пределы машины, поэтому шифровать его повторно смысла нет.

Выгода очевидна. Сертификат один на весь сервер, а не по копии в каждом приложении. Обновление сертификата не требует перезапуска приложений. Приложение вообще ничего не знает про шифрование — его код становится проще.

Как это выглядит в конфиге

server {
    listen 443 ssl;
    server_name example.ru;

    ssl_certificate     /путь/к/fullchain.pem;
    ssl_certificate_key /путь/к/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

server {
    listen 80;
    server_name example.ru;
    return 301 https://$host$request_uri;
}

Первый блок принимает защищённые соединения, второй ловит обычные и отправляет посетителя на защищённый адрес постоянным перенаправлением (код 301). Пути к файлам сертификата подставляет инструмент, которым ты его получал, — писать их наугад не нужно.

Бесплатные сертификаты выдаёт некоммерческий центр Let's Encrypt, и получают их автоматическими утилитами: они запрашивают сертификат, кладут файлы на место, правят конфиг и настраивают продление по расписанию. Срок жизни у таких сертификатов короткий именно в расчёте на автоматику, поэтому проверить, что автопродление действительно настроено, важнее, чем однократно получить сертификат. Сайт, который внезапно перестал открываться через пару месяцев после запуска, — почти всегда истёкший сертификат.

Пара разумных настроек

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
add_header Strict-Transport-Security "max-age=31536000" always;

Первая строка отключает устаревшие версии протокола. Последняя говорит браузеру: этот сайт всегда открывать только по защищённому адресу. Включать её стоит, когда HTTPS уже стабильно работает — браузер запомнит указание надолго, и откатиться обратно будет непросто.

Частые ошибки: nginx 502, 404 и права доступа

Тут кроется главная практическая ценность понимания Nginx. Когда знаешь, кто за что отвечает, номер ошибки сразу показывает, где копать.

Ключевое различие: 4xx против 5xx

Коды, начинающиеся с 4 — про запрос. Клиент попросил то, чего нет, или то, что ему не положено. Коды на 5 — про сервер. Запрос нормальный, сломалось на нашей стороне.

Ещё полезнее делить ошибки по тому, кто их сгенерировал. Ответ от Nginx выглядит как аскетичная страница с названием сервера внизу. Ответ от приложения обычно оформлен в стиле проекта или приходит в формате JSON. Одного взгляда достаточно, чтобы понять, дошёл запрос до приложения или нет.

502 Bad Gateway — самая частая

Формулировка «nginx 502 bad gateway» переводится дословно: «плохой шлюз». Nginx честно попытался передать запрос дальше, но собеседник не ответил. Ошибка почти никогда не в самом Nginx.

Причины по убыванию частоты:

Приложение не запущено. Упало при старте, забыли включить после перезагрузки сервера, вылетело из-за нехватки памяти. Проверяется просто: посмотреть, живёт ли процесс, и попробовать обратиться к нему прямо на сервере.

curl -I http://127.0.0.1:3000

Ответ есть — приложение живо, проблема в связке. Ответа нет — проблема в приложении, и Nginx тут ни при чём.

Порт не совпадает. В конфиге указан 3000, приложение слушает 8080. Классика после смены фреймворка.

Приложение слушает не тот адрес. Внутри контейнеров и виртуальных окружений программа, привязанная к 127.0.0.1, не видна снаружи своего окружения. Лечится привязкой к 0.0.0.0.

Приложение отвечает слишком долго. Nginx ждёт ответа ограниченное время, потом отдаёт 502 или 504. Если запрос тяжёлый по своей природе, таймаут увеличивают:

proxy_read_timeout 120s;

Но сначала стоит выяснить, почему ответ занимает больше минуты. Обычно это не про настройки, а про неоптимальный запрос к базе.

Ограничения безопасности на уровне системы. На некоторых конфигурациях исходящие соединения от Nginx к приложению по умолчанию запрещены политикой безопасности. Это редкий случай, но в журнале ошибок он выглядит характерно — как отказ в доступе при попытке соединения.

Порядок диагностики 502, который работает почти всегда: приложение живо → приложение отвечает на своём порту → в конфиге тот же порт → в журнале ошибок Nginx есть строчка с деталями.

404 Not Found — кто из двоих

Тут важно определить автора ответа. Скупая страница с надписью Nginx означает, что запрос не дошёл до приложения: не нашёлся файл или не подошёл ни один location. Оформленная страница означает, что приложение получило запрос и само не нашло маршрут — Nginx свою работу сделал.

Частые причины со стороны Nginx: опечатка в пути root, лишняя или недостающая косая черта в proxy_pass, забытая настройка try_files для одностраничного приложения, конфликт правил, где неожиданный location перехватил запрос.

403 Forbidden и права доступа

Ошибка 403 от Nginx почти всегда означает одно: файл существует, но прочитать его не удаётся. Nginx работает от имени служебного пользователя с ограниченными правами, и этому пользователю нужен доступ не только к самому файлу, но и ко всем каталогам по пути к нему. Загрузил проект под своей учётной записью в домашний каталог — и упёрся в закрытую дверь на середине пути.

Практический вывод: держи файлы сайта в каталоге, предназначенном для веб-содержимого, а не в личной папке. Так меньше шансов упереться в права. Второй частый источник 403 — запрос каталога, в котором нет индексного файла: показывать список файлов Nginx по умолчанию отказывается, и это правильно.

413 и 504 — короткие приметы

413 Request Entity Too Large — превышен client_max_body_size. Ошибка приходит от Nginx, приложение о запросе не узнало.

504 Gateway Timeout — приложение приняло соединение, но не ответило вовремя. Отличается от 502 тем, что связь установилась: проблема в скорости, а не в доступности.

Журналы: где искать правду

У Nginx два журнала, и они отвечают на разные вопросы.

Журнал доступа фиксирует каждый запрос: время, адрес клиента, метод, путь, код ответа, размер. По нему видно, дошёл ли запрос вообще и что было отдано в ответ.

Журнал ошибок содержит подробности сбоев: почему не удалось соединиться с приложением, какой файл не найден по какому пути, где отказано в доступе. Именно тут лежит ответ на вопрос «а что конкретно случилось».

Смотреть журнал в реальном времени и одновременно обновлять страницу в браузере — самый быстрый способ диагностики:

tail -f /var/log/nginx/error.log

Строчка появилась в момент твоего запроса — причина найдена. Не появилась — запрос до Nginx не дошёл, и разбираться надо с DNS, файрволом или тем, запущен ли сервер вообще.

Отдельная ценность журнала ошибок в том, что он пишет полный путь, по которому искал файл. Сравнить его с реальным расположением файла — и опечатка в конфиге видна невооружённым глазом.

Порядок разбора любой поломки

  1. Открывается ли сайт по IP-адресу сервера, минуя домен? Нет — проблема в самом сервере или файрволе. Да — проблема в DNS.
  2. Что говорит nginx -t? Ошибка в конфиге — дальше можно не искать.
  3. Какой код ошибки и от кого он пришёл?
  4. Что в журнале ошибок в момент запроса?
  5. Отвечает ли приложение напрямую на своём порту?

Эти пять вопросов закрывают подавляющее большинство проблем новичка. И почти всегда ответ находится на третьем-четвёртом шаге.

Nginx, Apache и Caddy — чем отличаются

Nginx не единственный веб-сервер, и выбор между тремя популярными вариантами сводится к нескольким различиям.

Apache — ветеран, появившийся раньше остальных. Его сильная сторона — модульность и возможность менять настройки через файлы прямо в каталогах сайта, из-за чего он десятилетиями был стандартом на дешёвом общем хостинге. Расплата — более тяжёлая модель обработки соединений и конфиги, которые с ростом проекта разрастаются.

Caddy — молодой сервер, главная особенность которого в том, что он получает и продлевает сертификаты сам, без дополнительных утилит. Конфиг у него заметно короче: рабочий сайт с HTTPS описывается парой строк. Взамен — меньше готовых рецептов в интернете и меньше шансов, что нужный тебе нестандартный сценарий уже кем-то разобран.

Nginx посередине: быстрый, экономный, с огромным количеством документации и ответов на форумы за много лет. Сертификаты требуют отдельного инструмента, конфиг длиннее, чем у Caddy, но каждая строчка предсказуема.

Признак Nginx Apache Caddy
Модель работы Событийная Процессы и потоки Событийная
Сертификат HTTPS Отдельным инструментом Отдельным инструментом Автоматически
Длина конфига Средняя Длинная Короткая
Настройки в каталогах сайта Нет Есть Нет
Материалов и ответов в сети Очень много Очень много Меньше
Кому подойдёт Прокси и статика на своём сервере Наследство и общий хостинг Быстрый старт с HTTPS

Практический совет: если ты только начинаешь и хочешь минимум возни с сертификатами, Caddy сэкономит тебе вечер. Если ты хочешь, чтобы на любую твою ошибку в поиске нашлось три готовых ответа, бери Nginx. Apache осмысленно выбирать, когда он уже стоит и работает, — специально переезжать на него смысла мало.

Частые вопросы

Nginx нужен, чтобы выложить игру из курса?

Нет. «Змейка» — набор статических файлов, для них хватает GitHub Pages: ссылка, домен и HTTPS достаются бесплатно и без настроек. Nginx понадобится позже, когда появится собственный сервер и приложение с серверной частью.

Чем Nginx отличается от хостинга?

Хостинг — это услуга: тебе дают место и инфраструктуру. Nginx — программа, которая на этой машине принимает запросы. На PaaS-платформе похожий слой уже развёрнут и настроен провайдером, а на голом VPS ты ставишь и настраиваешь его сам.

Что делать, если появился nginx bad gateway?

Проверить, запущено ли приложение, и обратиться к нему прямо на сервере командой curl по внутреннему порту. Отвечает — сверить порт в конфиге с реальным. Не отвечает — искать причину в самом приложении. Детали в обоих случаях будут в журнале ошибок Nginx.

Нужно ли перезапускать Nginx после каждой правки конфига?

Изменения применяются только после перезагрузки. Порядок такой: сначала nginx -t для проверки синтаксиса, затем nginx -s reload — она применяет настройки без разрыва текущих соединений. Полный перезапуск нужен редко.

Может ли приложение работать вообще без Nginx?

Может. Node.js и большинство фреймворков умеют слушать порт 80 напрямую. Но тогда на приложении оказываются сертификаты, сжатие, раздача статики, ограничение запросов и защита от медленных клиентов. На одном маленьком проекте это терпимо, дальше — неудобно.

Сколько сайтов можно держать на одном Nginx?

Технически — десятки, ограничение упирается в ресурсы сервера, а не в сам Nginx. Каждый сайт описывается своим блоком server со своим доменом, и на маленьком VPS несколько небольших проектов уживаются спокойно.

Обязательно ли учить конфиги наизусть?

Нет. Держать в голове стоит модель: домен → порт → путь → куда передаётся запрос. Синтаксис ищется в документации или запрашивается у ИИ-ассистента, а вот понимание, где сломалось, ассистент за тебя не сформирует — именно оно превращает «ничего не работает» в конкретный вопрос.

Коротко о главном

Nginx — не обязательный этап взросления, а инструмент под конкретную задачу: пустить трафик из интернета внутрь сервера, где живёт твоё приложение. Пока проект помещается в статические файлы или в PaaS, он не нужен и только отнимет время. Как только появляется свой сервер, несколько проектов на одной машине или связка «статика плюс приложение», Nginx становится самым коротким путём.

Полезнее всего запомнить три вещи. Первая: Nginx стоит перед приложением и сам код не запускает. Вторая: конфиг — это домен, порт и правила для путей, остальное детали. Третья: 502 почти всегда значит, что упало приложение, а не веб-сервер, и первым делом надо смотреть журнал ошибок и отвечать ли приложение на своём порту.

С этой картинкой в голове ты уже можешь осмысленно поставить задачу ИИ-ассистенту: не «сделай так, чтобы работало», а «настрой обратный прокси с домена на порт 3000 и добавь заголовки с реальным адресом клиента». Разница в результате будет заметная.

Читай дальше

Все статьи

Не просто статьи — тебя доведут до результата

В практикуме за 2499 ₽ рядом живая команда практикующих разработчиков и маркетологов: ведём по шагам до твоего работающего приложения. Не «ролики и сам разбирайся» — помогаем на каждом затыке.

Перейти к практикуму
Все статьи Ещё: публикация и продвижение