В данной статье буду собирать все редиректы в nginx которыми пользуюсь:
- 1. Редирект с http: на https
- 2. Редирект с www на без www
- 3. Добавляем слеши в конце
- 4. Убираем слеш в конце
- 5. Убираем index.php в конце адреса
- 6. Редирект для конкретной страницы
- 7. Редирект с одного домена на другой
- 8. Редирект с каждой страницы одного домена на такой же URL адрес другого домена
- 9. Редирект домена и всех его поддоменов:
- 10. Сложный анализ ЧПУ
- 11. Перенаправление запросов для отсутствующих доменов (перенаправление по умолчанию)
- 12. Редирект на особенную страницу по 404-му статусу
- 13. Использование вложенных if
- 14. Сложное условие и проксирование запросов
- 15. Пояснения:
- 16. Отличия между 301 и 302 редиректами:
Правила нужно прописывать в файле с описанием конфигурации конкретного хоста. У меня установлена панель VestaCP. Все файлы конфигурации расположены по адресу /home/admin/conf/web/ваш_домен.ru.nginx.conf
(без ssl); /home/admin/conf/web/ваш_домен.ru.nginx.ssl.conf
(с ssl).
Если же Вы устанавливали nginx сами, то путь до директории с настройками для сайтов будет /etc/nginx/site-enabled/ваш_сайт.conf
Саму настройку на перенаправление в NGINX можно прописать двумя способами.
Первый:
rewrite ^ https://$host$request_uri? <флаг>;
- $host — имя хоста из запроса, если отсутствует — имя в поле «Host» заголовка, если тоже отсутствует — имя сервера;
- $request_uri — первоначальный запрос с аргументами (все, что идет после доменного имени).
- <флаг> где флаги могут быть следующие:
- permanent — перенаправление с кодом 301.
- redirect — перенаправить с кодом 302.
- last — закончить обработку с переходом в новый location.
- break — закончить обработку и остаться в текущем location.
Второй:
return <код> https://$host$request_uri;
Где коды могут использоваться любые, но чаще всего — 301, 302, 404.
Есть различные мнения, какой из методов лучше и безопаснее, поэтому каким воспользоваться — решать по ситуации. В сети в примерах используется чаще всего второй вариант.
Редирект с http: на https
listen server_ip:80;
server_name mydomen.com;
return 301 https://$server_name$request_uri;
Или, если вам повезло также как и мне и конфигурационные файлы для ssl и без ssl — разные, то в файле для без ssl можно прописать прямой редирект:
server {
listen server_ip:80;
server_name mydomen.com;
rewrite ^ https://www.mydomen.com$request_uri? permanent;
}
Редирект с www на без www
if ($host ~* www\.(.*)) {
set $host_without_www $1;
rewrite ^(.*)$ http://$host_without_www$1 permanent;
}
Добавляем слеши в конце
if (!-f $request_filename) {
rewrite [^/]$ $uri/ permanent;
}
Убираем слеш в конце
if (!-f $request_filename) {
rewrite ^/(.*)/$ /$1 permanent;
}
Убираем index.php в конце адреса
if ($request_uri ~ "^(.*)index\.(?:php|html)") {
return 301 $1;
}
Если для определенных разделов данный редирект нужно отключить, то в маску добавляем разделы исключения:
if ($request_uri ~ "^(/(?!personal|catalog).*)index\.(?:php|html)") {
return 301 $1;
}
Чтобы сохранить параметры в адресной строке, нужно задать:
if ($request_uri ~ "^(.*)index\.(?:php|html)") {
return 301 $1$is_args$args; break;
}
break нужен в том случае, если происходит склейка нескольких редиректов одновременно
Редирект для конкретной страницы
Обычный редирект в htaccess имеет вид:
Redirect 301 /catalog/section_1/section_1_1/ /catalog/section_1_1/
В nginx примет вид:
rewrite /catalog/section_1/section_1_1/ /catalog/section_1_1/ permanent;
Также, редирект конкретного файла можно сделать так:
location = /robots.txt {
rewrite ^/robots.txt$ /robots2.txt;
}
Чтобы удалить из адреса часть строки, можно сделать так:
rewrite /deleted-url/(.*) /$1 permanent;
или так:
if ($request_uri ~ "/deleted-url/(.*)") {
return 301 $1;
}
Редирект с одного домена на другой
server {
server_name mydomen.com www.mydomen.com;
rewrite ^ $scheme://www.new-mydomen.com;
}
Редирект с каждой страницы одного домена на такой же URL адрес другого домена
server {
server_name mydomen.com www.mydomen.com;
rewrite ^ $scheme://www.new-mydomen.com$request_uri permanent;
}
Редирект домена и всех его поддоменов:
server {
...
server_name domain domain.*;
return 301 https://$host$request_uri;
}
Сложный анализ ЧПУ
Пример из сети по обработке api-запросов:
location ~* api/ {
rewrite ^/api/(.*)$ /api.php?_d=$1&ajax_custom=1&$args last;
}
Пока не приходилось сталкиваться, но, может быть, кому-то будет полезным!
Перенаправление запросов для отсутствующих доменов (перенаправление по умолчанию)
Для этого, в основном конфигурационном файле пишем:
server {
listen 80 default_server;
return 302 https://welcome.mydomain.ru$request_uri;
}
или независимо от протокола:
server {
listen 80 default_server;
return 302 $scheme://welcome.mydomain.ru$request_uri;
}
server {
listen 443 default_server;
return 302 $scheme://welcome.mydomain.ru$request_uri;
ssl on;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/cert.key;
}
$scheme — позволяет перевести запрос на тот же протокол (http или https), по которому он был инициирован.
* если nginx должен слушать и обрабатывать запросы по https, необходимо указывать в настройках пути к сертификатам.
Редирект на особенную страницу по 404-му статусу
Если страница не найдена — будет выдан 404-й статус и показана соответствующая страница. Но иногда, для случая, когда при отсутствии того или иного файла должен быть выполнен редирект куда-то, можно воспользоваться конструкцией:
location ~ \.php$ {
....
try_files = $uri @missing;
}
location @missing {
rewrite ^ $scheme://$host/some_file.php permanent;
}
По этой логике можно определять любые конструкции, которые вам нужны. Сначала сервер попробует выполнить файл, и, если он не будет найден, он переместится в часть @missing. А второй блок, с @missing, перенаправит на нужную страницу.
Использование вложенных if
Вложенные if в конфигурации nginx запрещены, поскольку это вовсе не языковая конструкция nginx, а обычная директива из модуля rewrite, использование которой в ее же собственном контексте if не предусмотрено. Использование списка условий, разделенных логическими операторами «и» и «или» тоже не предусмотрено. Обычно для эмуляции вложенных условий с использованием директивы if предлагают использовать регулярные выражения. Например, проверить, что имя, указаное в HTTP хедере HOST, соответствует значению localhost, а в URI присутствует аргумент «a» (в этом случае переменная $arg_a будет не пустой), можно так:
location /test_if.html {
set $cond $host::$arg_a;
if ($cond ~* '^localhost::.+') {
echo "Matched: host = '$host', a = '$arg_a'";
break;
}
echo "Not matched: host = '$host', a = '$arg_a'";
}
К сожалению, условие в директиве if имеет ограничения. По крайней мере, это не выражение, и оно не может быть составлено в виде цепочки выражений, разделенных логическими операторами. Кроме того, в случае сравнения чего-то с регулярным выражением, это что-то может быть только именем переменной, именно поэтому пришлось ввести новую переменную $cond:
location /test_if.html {
set $goodhost 'localhost';
set $cond $host::$goodhost::$arg_a;
if ($cond ~* '^(.*)::\1::.+') {
echo "Matched: host = '$host', a = '$arg_a'";
break;
}
echo "Not matched: host = '$host', a = '$arg_a'";
}
В данном примере мы соединили через произвольно выбранный нами разделитель :: три переменных $host, $goodhost и $arg_a и присвоили это значение переменной $cond. А регулярное выражение, с которым мы сопоставляем это значение, проверяет, что его первая часть (до разделителя ::) и вторая часть (до второго разделителя ::) равны, а последняя часть (после второго разделителя) не пуста.
В полном виде конструкция проверки примет вид:
location /test_if.html {
set $goodhost 'localhost';
set $cond $host::$goodhost::$arg_a;
if ($cond ~* '^(.*)::\1::ok$') {
echo "Matched: host = '$host', a is Ok";
break;
}
if ($cond ~* '^(.*)::\1::.+$') {
echo "Matched: host = '$host', a = '$arg_a'";
break;
}
echo "Not matched: host = '$host', a = '$arg_a'";
}
Сложное условие и проксирование запросов
Если нужно выполнить проксирование запросов с помощью директивы proxy_pass только при соблюдении нескольких условий, то можно воспользоваться следующей конструкцией:
if ($request_uri = /) {
set $test A;
}
if ($host ~* domain.com) {
set $test "${test}B";
}
if ($http_cookie !~* "auth_token") {
set $test "${test}C";
}
if ($test = ABC) {
proxy_pass http://domain-new.com;
break;
}
Пояснения:
Условие RewriteCond обозначает совпадение с которым будет выполнено правило RewriteRule. При этом, используются символы:
. – Точка — это любой символ (но только один!).
^ — Эта метка означает начала строки.
$ — Эта метка означает конец строки.
\ — Эта экранирующий слэш, позволяет считать следующий за ним символ, обычным символом.
() – Этот символ обозначает группировку.
! – Метка отрицания.
+ — Этот символ повторяется от 1 до 65536 раз.
? — Этот символ повторяется 0 или 1 раз.
* — А этот символ повторяется от 0 до 65536 раз.
Флаги определяют дополнительные опции.
R — (redirect) — По умолчанию останавливает процесс преобразования, возвращает результат в браузер клиента, как редирект на данную страницу 302, MOVED TEMPORARY. Например флагу можно указать другой код результата, R=301 и он возвратит редирект клиенту с кодом 301 MOVED PERMANENTLY.
NC — (nocase) — Этот флаг отключает проверку регистра символов.
L — (last) — Флаг останавливает процесс преобразования, текущая ссылка считается окончательной.
Чтобы изменения вступили в силу — не забудьде произвести рестарт nginx. Но для начала — проверьте, что ваша конфигурация в порядке. Для этого выполните команду:
nginx -t
Если выдаст «OK» — делаем смело перезагрузку:
service nginx restart
или
systemctl restart nginx
Первый вариант — для устаревших систем Linux или FreeBSD. Второй — для новых систем Linux
Если же показывает ошибку — разбираемся с ней.
Проверяя редиректы в браузере, следует учесть, что настройки могут кэшироваться. Для обновления кэша используйте комбинацию Ctrl + F5. Если и это не помогает, закрывайте вкладку и открывайте новую.
Отличия между 301 и 302 редиректами:
В чем принципиальная разница между ответом с кодом 301 и 302? Для обычного посетителя сайта разницы нет. А вот для поискового робота разница огромная.
301-й редирект говорит о склеивании страниц. Это означает для поисковика то, что старая и новая страницы — это одно и тоже. Таким образом результаты ранжирования необходимо сохранить для новой страницы.
302-о перенаправление просто говорит о том, что нужно перейти по другому адресу. Поисковый робот не сохраняет результат выдачи для новой страницы, индексируя его с нуля.
P.S. Не забывайте, что внесение любых изменений в конфигурации сервера могут привести к тому, что самостоятельно вы можете и не восстановить. Поэтому не забывайте делать бекапы!
[endtxt]