До основного вмісту

Налаштування 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 покаже реальні запити користувачів, а не лише тестові з термінала.
Чи була стаття корисною?
← Назад до бази знань Поставити питання підтримці