Настройка nginx: рабочий конфиг сайта с нуля

Настройка nginx на VPS: рабочий конфиг за 30 минут

Марина
Марина
📅 10 сентября 2026
Настройка nginx на VPS: рабочий конфиг за 30 минут

Настройка nginx для обычного сайта укладывается в один файл на 30–40 строк: описываете домен, путь к файлам, индексный файл, включаете сжатие и кэш статики, добавляете сертификат и редирект на HTTPS. Всё остальное — тонкая доводка под нагрузку. Ставится он на любой виртуальный сервер: тарифы, где nginx уже развёрнут или ставится одной командой, собраны в разделе VPS под nginx — там 44 провайдера и цены от 139 ₽/мес.

Материал для тех, кто впервые открыл конфиг и не понимает, что означают фигурные скобки и почему сайт отдаёт «Welcome to nginx» вместо своих страниц. Разберём структуру конфигурации и рабочий server-блок построчно. Дальше — директивы, которые чаще всего ломают сайт, порядок включения HTTPS и проверка изменений до перезапуска.

Что делает nginx и где физически лежат его конфиги

nginx — это веб-сервер: программа, которая слушает сетевой порт, принимает HTTP-запросы браузера и отдаёт в ответ файлы. Второй вариант — передать запрос дальше: в PHP-FPM (службу, которая выполняет PHP-код сайта) или в приложение на Node.js. Порт 80/TCP он занимает для обычного HTTP, порт 443/TCP — для HTTPS. Один процесс nginx спокойно обслуживает несколько десятков сайтов на одном сервере.

После установки на Debian или Ubuntu файлы раскладываются по трём местам. Главный файл — /etc/nginx/nginx.conf: в нём глобальные настройки, общие для всего сервера. Описания отдельных сайтов лежат в /etc/nginx/sites-available/ — по одному файлу на домен. Каталог /etc/nginx/sites-enabled/ содержит символические ссылки на те файлы, которые сейчас активны.

Такое разделение удобно: чтобы временно отключить сайт, файл с настройками не удаляют — убирают только ссылку. На CentOS и Rocky Linux каталогов sites-available нет, вместо них используется /etc/nginx/conf.d/, куда кладут файлы с расширением .conf. Логи по умолчанию пишутся в /var/log/nginx/access.log и /var/log/nginx/error.log — второй файл открывают первым, когда что-то не работает.

Как устроен конфиг: контексты, директивы и точка с запятой

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

Внутри http живут блоки server — по одному на сайт. Внутри server находятся блоки location, которые описывают поведение для конкретных путей: отдельно для картинок, отдельно для PHP-скриптов, отдельно для всего остального. Правило наследования простое: настройка, заданная снаружи, действует внутри, пока её не переопределили.

Каждая строка-директива заканчивается точкой с запятой. Забытая точка с запятой — причина примерно половины ошибок запуска у новичков, и nginx честно сообщает номер строки. Комментарии начинаются с решётки. Регистр важен: gzip on; работает, GZIP On; — нет.

Ещё одна частая конструкция — директива include. Она подключает содержимое другого файла: строка include /etc/nginx/sites-enabled/*; в главном файле втягивает описания всех активных сайтов. Поэтому ошибка, о которой сообщает nginx, нередко живёт не в том файле, который вы правили.

Минимальный server-блок: домен, root и индексный файл

Файл сайта создают в /etc/nginx/sites-available/ и называют по домену, например example.ru. Директива listen указывает порт, server_name — домены, на которые отвечает этот блок, root — каталог с файлами сайта, index — какой файл отдавать при запросе каталога.

server {
    listen 80;
    server_name example.ru www.example.ru;
    root /var/www/example.ru;
    index index.html index.php;

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

Строка try_files $uri $uri/ =404; означает: сначала поискать файл с таким именем, потом каталог, а если ничего не нашлось — вернуть ошибку 404. Для сайтов на WordPress и других CMS с человекопонятными адресами последнюю часть меняют на /index.php?$args, иначе внутренние страницы будут отдавать 404.

Каталог root должен существовать и быть доступен на чтение пользователю www-data — от его имени работают рабочие процессы. Права 755 на каталоги и 644 на файлы закрывают вопрос: владелец может менять, остальные — только читать. Если сайт лежит в домашней папке пользователя, проверьте права и на неё саму: nginx проверяет права на весь путь целиком.

Проверка конфигурации nginx командой nginx -t
Проверка конфига до перезапуска: две строки «ok» и «successful»

Включение сайта симлинком и проверка через nginx -t

Созданный файл сам по себе ничего не делает — nginx читает только каталог sites-enabled. Символическую ссылку (её же называют симлинком) создают командой ln -s /etc/nginx/sites-available/example.ru /etc/nginx/sites-enabled/: она указывает на исходный файл, но самого файла не копирует. Заодно стоит удалить ссылку default: именно она отдаёт страницу «Welcome to nginx» и перехватывает запросы к домену, для которого не нашлось своего блока.

Перед перезапуском конфиг проверяют командой nginx -t — она разбирает все файлы и печатает syntax is ok и test is successful либо точный путь и номер строки с ошибкой. Проверка занимает доли секунды и не трогает работающий сервер, поэтому её делают всегда, даже после правки одной строки.

Применяют изменения командой nginx -s reload. Она не убивает текущие соединения: старые рабочие процессы дорабатывают начатые запросы и завершаются, новые запросы уходят уже в процессы с новым конфигом. Полный restart нужен редко — например, после смены директивы listen на другой порт. На чистом сервере эти шаги удобно делать сразу после базовой подготовки системы, порядок которой описан в гайде как настроить VPS с нуля.

worker_processes и worker_connections: сколько запросов держит сервер

Директива worker_processes auto; в главном контексте говорит nginx запустить столько рабочих процессов, сколько у сервера ядер. На тарифе с 1 ядром процесс будет один, на 4 ядрах — четыре. Ручное завышение не ускоряет сайт: процессы начинают конкурировать за то же самое время процессора.

Внутри блока events задаётся worker_connections — сколько одновременных соединений держит один процесс. Значение по умолчанию 1024. Теоретический максимум для сервера считается умножением: 4 ядра × 1024 = 4096 одновременных соединений. Браузер обычно открывает 2–6 соединений на страницу, так что даже базовые 1024 покрывают сотни посетителей онлайн.

Упереться в лимит системы проще, чем в лимит nginx: процесс в Linux по умолчанию может держать открытыми 1024 файловых дескриптора — так называют любой открытый файл или соединение. Каждое соединение занимает один дескриптор. Потолок поднимает директива worker_rlimit_nofile 8192;. Трогать её есть смысл от нескольких тысяч посетителей в сутки.

Директива Контекст По умолчанию Рабочее значение
worker_processes главный 1 auto (по числу ядер)
worker_connections events 1024 1024–4096
client_max_body_size http, server 1 МБ 16–64 МБ
keepalive_timeout http 75 с 15–30 с
gzip_comp_level http 1 5
server_tokens http on off
Значения ключевых директив nginx по умолчанию и рабочие
Лимит client_max_body_size в 1 МБ — самая частая причина ошибки 413

Ошибка 413 и client_max_body_size: почему не грузится файл

Директива client_max_body_size ограничивает размер тела запроса — то есть всего, что посетитель отправляет на сервер. По умолчанию это 1 МБ. Любая фотография с телефона весит больше, поэтому загрузка картинки в админку CMS обрывается с ошибкой 413 Request Entity Too Large — и это одна из самых частых жалоб после переезда на свой сервер.

Лечится строкой client_max_body_size 64m; внутри блока http или конкретного server. Значения 16 МБ хватает для обычного блога с фотографиями, 64 МБ — для каталога товаров, 256 МБ — если через сайт заливают видео или архивы. Ставить безлимит (0) не стоит: это открытая дверь для мусорных загрузок, которые забьют диск.

Вторая половина проблемы живёт не в nginx. Для сайтов на PHP тот же лимит дублируется в php.ini параметрами upload_max_filesize и post_max_size, а также max_execution_time — по умолчанию 30 секунд. Поднимать нужно все четыре значения согласованно, иначе файл пройдёт через веб-сервер и упрётся уже в интерпретатор.

Сжатие gzip: минус 60–80 % веса текстовых файлов

gzip сжимает ответ перед отправкой в браузер, а браузер распаковывает его на лету. Для HTML, CSS, JavaScript и JSON экономия составляет порядка 60–80 % объёма: страница на 300 КБ уезжает к посетителю как 70–90 КБ. Для JPEG, PNG и видео сжатие бесполезно — они уже сжаты, и повторная обработка только тратит процессор.

Минимальный набор строк для блока http: gzip on;, список типов в gzip_types, порог gzip_min_length 1024; и уровень gzip_comp_level 5;. Уровень задаётся от 1 до 9. Пятый — разумный баланс: относительно девятого он даёт примерно тот же результат по объёму при заметно меньшей нагрузке на процессор, что важно на тарифе с одним ядром.

Порог в 1024 байта отсекает мелочь: на ответе в 200 байт накладные расходы съедят выигрыш. Проверить сжатие можно командой curl -I -H "Accept-Encoding: gzip" https://example.ru — в ответе должен появиться заголовок Content-Encoding: gzip. Сжатие особенно заметно на медленных мобильных каналах, где каждые лишние 100 КБ добавляют секунду к загрузке.

Кэш статики: заголовок expires для картинок, CSS и скриптов

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

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

Директива expires 30d; добавляет к ответу срок годности в 30 дней. Строка access_log off; отключает запись обращений к статике в журнал — на сайте с сотней картинок это сокращает лог в разы и снимает лишние операции записи на диск. Для файлов, которые не меняются никогда, ставят expires 365d;.

Обратная сторона: обновив CSS, вы не увидите изменений, пока не истечёт срок или не очистите кэш браузера. Стандартное решение — добавлять к адресу файла версию: style.css?v=12. Для страниц, генерируемых CMS, кэш в браузере не включают — иначе посетитель увидит вчерашнюю корзину. Что ещё можно ускорить на уровне сервера, разобрано в материале про оптимизацию VPS.

HTTPS и редирект: как закрыть сайт сертификатом

HTTPS шифрует трафик между браузером и сервером и давно стал условием для нормального ранжирования и доверия посетителей. Бесплатный сертификат от Let’s Encrypt выдаётся на 90 дней и обновляется автоматически — утилита certbot ставит задачу в планировщик и продлевает сертификат за 30 дней до окончания срока.

После выпуска сертификата у сайта становится два server-блока. Первый слушает порт 80 и делает единственную вещь — отдаёт постоянный редирект: return 301 https://$host$request_uri;. Второй слушает 443 с параметрами ssl и http2, содержит пути к файлам сертификата и ключа и всю остальную конфигурацию сайта.

Включённый HTTP/2 добавляется одним словом в строке listen 443 ssl http2; и заметно ускоряет страницы с большим числом мелких файлов: браузер тянет их по одному соединению вместо шести. Пошаговый выпуск сертификата с командами certbot расписан в отдельной инструкции — как установить SSL Let’s Encrypt.

Оба server-блока certbot дописывает сам и не трогает ваши настройки gzip и кэша. Продление проверяют командой certbot renew --dry-run: она имитирует обновление и показывает, сработает ли оно автоматически через 60 дней.

Настройка nginx с нуля: семь шагов по порядку

Ниже — последовательность для чистого сервера на Ubuntu 22.04 или 24.04. Каждый шаг проверяем перед переходом к следующему: так ошибку видно сразу. Домен к моменту старта должен указывать A-записью на IP сервера, иначе сертификат не выпустится.

  1. Поставить пакет: apt update && apt install nginx — веб-сервер запустится на порту 80.
  2. Открыть в файрволе порты 80 и 443, проверить по IP, что отдаётся страница-заглушка.
  3. Создать каталог /var/www/example.ru и положить в него тестовый index.html.
  4. Написать файл в sites-available с listen, server_name, root, index и блоком location.
  5. Создать симлинк в sites-enabled, удалить ссылку default, выполнить nginx -t и nginx -s reload.
  6. Добавить в блок http gzip, client_max_body_size 64m и location для статики с expires 30d.
  7. Выпустить сертификат certbot и убедиться, что запрос по http отдаёт код 301 на https-адрес.

После седьмого шага сайт рабочий. Дальше идёт PHP-FPM или проксирование на приложение — в этой роли nginx работает как обратный прокси, передавая запросы внутреннему сервису на локальном порту.

Сколько ресурсов и денег нужно серверу под nginx

Сам nginx нетребователен: рабочий процесс занимает 2–10 МБ памяти, и на сайт-визитку хватает тарифа с 1 ядром и 1 ГБ RAM. Память съедает то, что стоит за ним: PHP-FPM на WordPress просит от 512 МБ, база MySQL — ещё 256–512 МБ. Отсюда правило: 2 ГБ RAM на один сайт с CMS, 4 ГБ — на три-четыре.

Тип диска важнее его объёма: на NVMe отдача статики и запросы к базе идут заметно быстрее, чем на HDD, а разница в цене тарифа редко превышает 100 ₽/мес. Стартовые цены провайдеров в разделе выглядят так.

Провайдер Цена от Стартовая конфигурация Тарифов
RuVDS 139 ₽/мес 1 ядро, 0,5 ГБ RAM, 10 ГБ HDD 440
Selectel 200 ₽/мес 1 ядро, 1 ГБ RAM, 10 ГБ NVMe 69
Aéza 593 ₽/мес 1 ядро, 2 ГБ RAM, 30 ГБ NVMe 151

Данные проверены 03.09.2026.

Тариф за 139–200 ₽/мес подходит для лендинга и небольшого блога. Под интернет-магазин или сайт с 1000+ посетителей в сутки берут 2 ядра и 4 ГБ RAM — это диапазон 600–1200 ₽/мес. Подборка тарифов, отобранных именно под сайты, лежит в разделе VPS для сайтов.

Частые ошибки при настройке nginx

Большинство проблем повторяются от сервера к серверу и решаются за минуту, если знать, куда смотреть. Первым делом всегда открывают /var/log/nginx/error.log — там записана точная причина, а не общая формулировка из браузера. Ниже — ошибки, которые встречаются чаще остальных.

  • Файл создан в sites-available, но симлинк в sites-enabled не сделан — сайт отдаёт чужую страницу-заглушку.
  • Не удалён конфиг default: он перехватывает запросы к любому домену, у которого нет своего server-блока.
  • Правки применили через reload без предварительного nginx -t — сервер остаётся на старом конфиге, а вы ищете ошибку в браузере.
  • Оставлен лимит client_max_body_size в 1 МБ — загрузка любого фото падает с ошибкой 413.
  • Каталог сайта недоступен пользователю www-data — в браузере ошибка 403, в логе строка Permission denied.
  • Порт 443 закрыт файрволом: сертификат выпущен, а сайт по HTTPS не открывается.

Отдельная категория — ошибка 502 Bad Gateway: nginx работает, но не достучался до бэкенда — программы, которая стоит за ним и готовит ответ. Причины три: не запущен PHP-FPM, неверный путь к сокету или приложение слушает другой порт.

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

Что выбрать новичку — nginx или Apache? Для типового сайта на CMS проще nginx: он экономнее расходует память на статике и держит больше одновременных соединений на том же железе. Apache гибче за счёт файлов .htaccess. Подробное сравнение — в материале nginx или Apache.

Нужно ли перезапускать сервер после каждой правки? Нет. Команда nginx -s reload перечитывает конфигурацию без разрыва открытых соединений — посетители ничего не заметят. Полный restart нужен только при смене портов в listen или после обновления пакета.

Почему после установки открывается страница «Welcome to nginx»? Работает конфиг по умолчанию: в sites-enabled лежит ссылка default. Удалите её, создайте свою и выполните nginx -t с последующим reload. Если страница осталась, проверьте в режиме инкогнито — дело в кэше браузера.

Сколько сайтов можно держать на одном сервере? Ограничение задаёт не nginx, а память под бэкенды: на 2 ГБ RAM живут 3–5 небольших сайтов на PHP, на 4 ГБ — до десяти. Каждому домену делают отдельный файл в sites-available.

Как проверить, что gzip действительно включился? Отправьте запрос командой curl -I -H "Accept-Encoding: gzip" https://example.ru и найдите в ответе строку Content-Encoding: gzip. Если её нет, проверьте, что тип файла перечислен в gzip_types, а размер ответа больше порога gzip_min_length — по умолчанию мы ставим 1024 байта.

Помогает ли nginx против наплыва запросов? Частично: директивы limit_req_zone и limit_conn ограничивают число запросов и соединений с одного адреса и гасят простой перебор. Против объёмной атаки нужна фильтрация на уровне канала — такие тарифы собраны в разделе защита от DDoS для nginx.

Что делать, если nginx -t ругается, а строку я не вижу? Команда печатает полный путь и номер строки, и ошибка часто оказывается в файле, подключённом через include. Чаще всего это пропущенная точка с запятой в конце предыдущей строки или лишняя скобка. Открывайте файл по указанному пути, а не тот, который правили последним.

Итог

Рабочая конфигурация собирается из шести вещей: server-блок с root и index, симлинк в sites-enabled, client_max_body_size вместо дефолтного 1 МБ, gzip пятого уровня, кэш статики на 30 дней и пара блоков под HTTPS с редиректом. Проверка nginx -t перед каждым reload экономит больше времени, чем любая другая привычка.

Для старта хватит тарифа с 1–2 ядрами и 2 ГБ RAM. Сравнить конфигурации, локации и цены 44 провайдеров можно в разделе VPS с nginx — фильтры по памяти, диску и стране включаются в один клик.

Поделиться:
👁 44 просмотров
Марина
Редактор · FREEHOSTING
Главный редактор FREEHOSTING. С 2020 года тестирует VDS, VPS и хостинг-провайдеров — арендует серверы, нагружает их реальными проектами и пишет честные обзоры по итогам. Помогает читателям выбирать хостинг под свои задачи: от Telegram-бота до production-сайта.