# rewrite і return у Nginx: редиректи без помилок

> Різниця між rewrite і return у Nginx, прапорці last і break, коди 301 і 302, приклади редиректів www, https і старих URL.

Редиректи у Nginx налаштовують двома способами: директивою return або директивою rewrite. Обидві задаються всередині server block або location, описаних у статті про [пріоритет location у Nginx](https://www.zevshost.net/uk/kb/nginx-location-prioritet/), але працюють по-різному і однаково легко ламають сайт за недбалого налаштування.

## return і rewrite: у чому різниця

Директива return одразу зупиняє обробку запиту і віддає клієнту код відповіді і, за потреби, адресу для редиректу. Це найшвидший і найпередбачуваніший спосіб зробити редирект: один рядок, мінімум навантаження на CPU.

Директива rewrite змінює сам URI запиту за регулярним виразом і, залежно від прапорця, або продовжує обробку з новим URI всередині Nginx, або надсилає клієнту HTTP-редирект. Rewrite гнучкіший, але саме через цю гнучкість частіше стає причиною циклів і несподіваної поведінки.

## Коли застосовувати return для простого редиректу

Якщо завдання — просто відправити клієнта на іншу адресу без модифікації шляху, return завжди кращий за rewrite. Офіційна документація nginx.org прямо рекомендує return для редиректів, де не потрібна підстановка за регулярним виразом.

```
server {
    listen 80;
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}
```

Тут $request\_uri зберігає початковий шлях і query-параметри, тому example.com/page?id=5 залишається example.com/page?id=5, а не перетворюється на редирект на головну сторінку.

## Синтаксис rewrite: прапорці last, break, redirect, permanent

Директива rewrite приймає регулярний вираз, заміну і необов'язковий прапорець:

- last — зупиняє обробку поточного location і заново шукає location для нового URI.
- break — зупиняє обробку rewrite, але залишається у тому самому location.
- redirect — надсилає клієнту HTTP 302 з новою адресою замість внутрішньої обробки.
- permanent — надсилає клієнту HTTP 301 з новою адресою.

Без прапорця redirect чи permanent rewrite не створює видимий браузеру редирект: новий URI обробляється всередині Nginx, а в адресному рядку клієнта залишається стара адреса.

## Часта помилка: нескінченний цикл rewrite

Прапорець last всередині location, який сам підходить під той самий шаблон rewrite, породжує нескінченний цикл: Nginx переписує URI, заново шукає location, потрапляє у той самий блок, знову переписує URI. Результат — помилка rewrite or internal redirection cycle в error\_log і 500-та помилка на сайті.

Щоб уникнути циклу, перевіряйте умовою if ($uri !~ ...), що URI ще не переписаний, або використовуйте break замість last там, де перехід у новий location не потрібен. Під час проксування на backend через [reverse proxy на Nginx](https://www.zevshost.net/uk/kb/nginx-reverse-proxy/) зайвий rewrite часто взагалі не потрібен — proxy\_pass справляється сам.

## Коди 301 і 302: коли який застосовувати

| Код | Значення | Коли застосовувати |
| --- | --- | --- |
| 301 Moved Permanently | Постійний редирект | Зміна домену, протоколу, остаточне перенесення URL |
| 302 Found | Тимчасовий редирект | Технічні роботи, A/B-тест, тимчасова посадкова сторінка |
| 307 Temporary Redirect | Тимчасовий редирект зі збереженням методу | POST-запити, які не можна перетворювати на GET |

Пошукові системи передають вагу сторінки через 301, але кешують його агресивно: зміна 301 на нову адресу пізніше потребуватиме часу на переіндексацію. 302 пошуковики не запам'ятовують надовго, тому для остаточних переїздів застосовують 301.

## Практичні приклади редиректів

Три часті сценарії редиректів на сайті, які також варто звірити зі статтею про [SSL і Certbot у Nginx](https://www.zevshost.net/uk/kb/ssl-nginx-certbot/) під час переходу на HTTPS:

```
# редирект з www на домен без www
server {
    listen 80;
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}

# редирект з http на https
server {
    listen 80;
    server_name example.com;
    return 301 https://example.com$request_uri;
}

# редирект старого URL на новий зі збереженням параметрів
rewrite ^/old-page$ /new-page permanent;
```

## Чек-лист перед викладенням редиректів

1. Застосовуйте return замість rewrite, якщо не потрібна підстановка за регулярним виразом.
2. Вказуйте $request\_uri, щоб не втратити шлях і query-параметри під час редиректу.
3. Перевіряйте на нескінченний цикл: nginx -t не завжди знаходить цю помилку, тестуйте curl -I.
4. Обирайте 301 для постійних переїздів і 302 для тимчасових.

Return і rewrite розв'язують одне завдання — перенаправлення трафіку — але з різною ціною: return швидший і надійніший для прямих редиректів, rewrite потрібен там, де шлях запиту справді змінюється за шаблоном. Тестуйте кожен новий редирект командою curl -I перед тим, як викладати його у production.

---

Джерело: https://www.zevshost.net/uk/kb/nginx-rewrite-return-redirect/
