Понимание серверных блоков Nginx: Часто задаваемые вопросы по настройке

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

Понимание серверных блоков Nginx: Часто задаваемые вопросы по настройке

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

Если вы размещаете более одного домена, перенаправляете HTTP на HTTPS или запускаете приложения за Nginx, серверные блоки — это то, с чего начинается большая часть маршрутизации.

Что такое серверный блок Nginx?

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

Базовый серверный блок для статического сайта выглядит так:

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

    root /var/www/example.com/public;
    index index.html;

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

Это указывает Nginx слушать порт 80, сопоставлять запросы для example.com и www.example.com, обслуживать файлы из публичного каталога и возвращать 404, когда файл не найден.

Название "серверный блок" распространено в Nginx. Пользователи Apache могут знать аналогичную концепцию как виртуальный хост. Цель та же: позволить одному веб-серверу обрабатывать несколько сайтов или приложений.

Серверные блоки обычно хранятся в /etc/nginx/sites-available/ и активируются с помощью символических ссылок в /etc/nginx/sites-enabled/ в системах Debian и Ubuntu. Некоторые дистрибутивы используют /etc/nginx/conf.d/ вместо этого. Точная структура менее важна, чем знание того, какие файлы включены в nginx.conf.

Как Nginx выбирает правильный серверный блок?

Выбор Nginx происходит поэтапно. Сначала он учитывает IP-адрес и порт из директивы listen. Затем он сравнивает имя хоста запроса с server_name.

Если ни одно имя хоста не совпадает, Nginx использует сервер по умолчанию для этого адреса и порта. Вы можете явно указать его:

server {
    listen 80 default_server;
    server_name _;
    return 444;
}

Некоторые команды используют такой блок по умолчанию для отклонения несовпадающих запросов. Другие возвращают простой 404. Лучший выбор зависит от ваших предпочтений в логировании и безопасности.

Если вы все еще учитесь, видимый 404 по умолчанию может быть проще для отладки, чем return 444, потому что 444 — это специфичное для Nginx закрытие соединения и может выглядеть как сетевая проблема со стороны клиента. В продакшене некоторые команды предпочитают тихое закрытие для случайных несовпадающих хостов. Любой выбор подходит, если команда его понимает.

Точные имена предпочтительнее имен с подстановочными знаками. Например, api.example.com более конкретен, чем *.example.com. Возможны серверные имена с регулярными выражениями, но они должны быть редкими, потому что их сложнее читать и отлаживать.

Распространенная ошибка — добавление нового домена в DNS, но забывание добавить его в server_name. Запрос достигает сервера, но Nginx отправляет его в блок по умолчанию. С точки зрения пользователя, отображается неправильный сайт или запрос не выполняется.

Другая распространенная ошибка — создание двух блоков, которые оба претендуют на один и тот же listen и server_name. Nginx может предупредить о конфликтующих именах серверов и игнорировать один из них. Всегда тестируйте конфигурацию после добавления сайта.

Используйте это, когда отвечает неправильный сайт:

sudo nginx -T | grep -n "server_name"
curl -I -H 'Host: example.com' http://127.0.0.1/

nginx -T выводит полную загруженную конфигурацию, включая включенные файлы. Это часто быстрее, чем открывать каждый файл в sites-enabled.

Что находится внутри серверного блока?

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

Для обратного прокси блок может выглядеть так:

server {
    listen 443 ssl;
    server_name app.example.com;

    ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;

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

Здесь Nginx завершает HTTPS и перенаправляет трафик в локальное приложение на порту 3000. Это распространено для приложений на Node.js, Python, Ruby, Go и Java.

Если вышестоящему приложению нужно знать исходную схему или IP-адрес клиента, эти строки proxy_set_header имеют значение. Без них приложение может думать, что каждый запрос пришел с 127.0.0.1 по обычному HTTP. Это может нарушить перенаправления, журналы аудита, ограничения скорости и сгенерированные URL-адреса обратного вызова.

Используйте четкие пути к журналам при размещении нескольких сайтов:

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

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

Для загруженного хоста это также упрощает хранение. Возможно, вам понадобятся подробные журналы для API во время инцидента и более легкое логирование для статического сайта. Хранение файлов отдельно дает вам эту возможность без изменения каждого серверного блока сразу.

Чем серверные блоки отличаются от блоков location?

Серверные блоки выбирают сайт. Блоки location выбирают, что делать с путями внутри этого сайта.

Например:

server {
    server_name example.com;

    location /assets/ {
        expires 30d;
    }

    location /api/ {
        proxy_pass http://api_backend;
    }

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

Запросы к /assets/logo.png получают кэширование статических файлов. Запросы к /api/users идут к вышестоящему бэкенду. Другие запросы переходят к фронтенд-приложению.

Это разделение важно. Если отвечает неправильный домен, смотрите сопоставление серверных блоков. Если отвечает правильный домен, но происходит неправильное поведение пути, смотрите сопоставление location.

Это различие экономит время. Запрос к api.example.com/users может не выполниться, потому что api.example.com совпал с неправильным серверным блоком, или потому что /users совпал с неправильным location внутри правильного блока. Это разные проблемы.

Для более подробной информации о маршрутизации путей смотрите Объяснение блоков location Nginx.

Как организовать несколько сайтов?

По возможности используйте один файл на сайт или приложение. Дайте каждому файлу имя, соответствующее домену или назначению:

/etc/nginx/sites-available/example.com
/etc/nginx/sites-available/api.example.com
/etc/nginx/sites-available/admin.example.com

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

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

Практическая настройка может включать:

include snippets/proxy-headers.conf;
include snippets/security-headers.conf;

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

Перед удалением или переименованием файла серверного блока проверьте, как он включен. В макетах Debian удаление файла из sites-available ничего не дает, если другая копия все еще существует в conf.d. С другой стороны, удаление символической ссылки в sites-enabled отключает сайт без удаления исходного файла.

ls -l /etc/nginx/sites-enabled/
sudo nginx -T | grep -n "include"

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

Когда обращаться за помощью с проблемами серверных блоков

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

Вам также следует обратиться за помощью, если Nginx продолжает обслуживать неправильный сайт после того, как вы считаете конфигурацию правильной. Проблема может включать DNS, IPv6, балансировщик нагрузки, CDN или файл включения, который вы не заметили.

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