К основному содержимому

Настройка Nginx для веб-сайта на VDS

VDS / VPS · 20.02.2025 · 4 мин чтения
Иллюстрация к статье «Настройка Nginx для веб-сайта на VDS»

Виртуальный хост Nginx — это блок server, который связывает доменное имя, корень сайта и обработчик PHP в один конфиг. На VDS с несколькими сайтами именно эти блоки определяют, какой запрос куда попадёт.

Настройка виртуального хоста Nginx

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

nano /etc/nginx/sites-available/yourdomain.com

Содержимое файла — минимальный рабочий блок для сайта на PHP:

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    root /var/www/yourdomain.com;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }
}

Активируйте конфигурацию симлинком в sites-enabled — Nginx читает конфиги именно из этой папки, а sites-available служит только хранилищем:

ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx

Несколько сайтов на одном IP

Nginx выбирает нужный блок по заголовку Host из запроса, сверяя его со списком в server_name. Если ни один блок не совпал, срабатывает блок с default_server в директиве listen — без него первый по порядку чтения файлов конфиг становится дефолтным неявно, что иногда приводит к неожиданному результату при добавлении нового сайта.

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

Такой блок-заглушка с return 444; обрывает соединение для запросов с любым доменом, который не настроен явно, — полезная защита от ботов, сканирующих IP-адреса напрямую, в обход DNS.

Gzip-сжатие ответов

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

gzip_min_length отсекает сжатие совсем маленьких файлов, где выигрыш меньше накладных расходов на упаковку, а gzip_comp_level в диапазоне 5–6 — разумный баланс между экономией трафика и нагрузкой на CPU; уровень 9 почти не выигрывает в размере, но заметно дороже по процессору.

Кэширование статики браузером

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

Разбор типичных ошибок

Ошибка nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) означает, что порт 80 уже занят другим процессом — чаще всего это Apache, оставшийся включённым, или второй запущенный экземпляр Nginx. Проверьте занятые порты командой ss -tulpn | grep :80 и остановите лишний процесс.

502 Bad Gateway — Nginx не получил ответ от бэкенда, указанного в fastcgi_pass или proxy_pass. Точная причина всегда в /var/log/nginx/error.log: строка connect() to unix:/run/php/php8.2-fpm.sock failed (13: Permission denied) указывает на права доступа к сокету, а (111: Connection refused) — на то, что PHP-FPM попросту не запущен.

404 на всех страницах, кроме главной в проектах с «красивыми» URL обычно значит, что директива try_files не настроена на передачу запроса в index.php — Nginx честно ищет файл на диске с именем маршрута и не находит его.

Сравнение способов маршрутизации в Nginx

ПодходГде задаётсяГибкостьТипичный случай
try_filesВ location /Средняя, порядок фиксированОтдача статики с фолбэком на index.php
rewriteВ server или locationВысокая, регулярные выраженияСтарые ссылки, ЧПУ без фреймворка
returnВ server или locationНизкая, прямой ответРедиректы, обрыв соединения (444)
proxy_passВ locationВысокая, полный проброс на бэкендNode.js, Python, обратный прокси

Более глубокий разбор приоритета типов location и того, какой блок сработает при пересечении правил, — в статье про приоритет location в Nginx (там же разобраны примеры конфликтов конфигурации).

Когда голого Nginx-конфига недостаточно

  • Сайту нужен HTTPS — сертификат и редирект с HTTP добавляются отдельно, это описано в статье про установку SSL через Certbot.
  • Много одинаковых сайтов на одном сервере — вместо копирования конфига под каждый домен удобнее вынести общие блоки в include-файлы.
  • Нужна защита от перебора или DDoS на уровне запросов — здесь стандартный server-блок не поможет, нужны limit_req, limit_conn или внешний WAF.
  • Бэкенд — не PHP-FPM, а отдельное приложение на своём порту (Node.js, Python, Go) — вместо fastcgi_pass используется proxy_pass с отдельным набором заголовков.

Проверка результата

  1. Проверьте синтаксис перед каждым изменением: nginx -t должен вернуть syntax is ok и test is successful.
  2. Откройте сайт по домену и по IP отдельно — если по домену работает, а по IP видно чужой сайт, значит верно настроен server_name, а если по IP видно этот же сайт без default_server, стоит это проверить.
  3. Проверьте заголовки ответа: curl -I http://yourdomain.com — заголовок Content-Encoding: gzip подтвердит, что сжатие реально работает, а не просто включено в конфиге.
  4. Просмотрите access-лог на предмет 404 и 502 сразу после деплоя: tail -f /var/log/nginx/access.log покажет реальные запросы пользователей, а не только тестовые из терминала.
Статья помогла?
← Назад в базу знаний Задать вопрос поддержке