Debian.pro

Блог для пользователей и администраторов Debian


Большой мануал: часть 21. Учимся делать редиректы в nginx.

Эта статья — часть Большого Мануала по настройке lamp-сервера на debian.

Предыдущая часть цикла — Создаём конфиг для нашего сайта в nginx.

Следующая часть цикла — Not yet published

В этой статье мы поговорим о том, как в nginx нынче модно делать редиректы. Точнее, цель даже не в том, чтобы научить делать редиректы (это всё мелочи), а в том, чтобы вы после прочтения статьи точно поняли, что вы написали только что в конфиге (и зачем).

Для начала нужно узнать, как nginx выбирает нужный server{} для обработки запроса. Первым делом, разберемся с важным моментом в районе listen. Дело в том, что в nginx можно написать по-разному:

  • listen 80;
  • listen 192.168.0.1:80;

Так вот. Очень важно знать, что если вы где-то в конфиге написали listen ip:80, то для этой связки IP+порта ни один server{} с listen 80 уже работать не будет (ну только если написать 2 параметра listen =)).
Переводя для таких же тупых, как я. Если у вас на сервере много хостов и все они с listen 80, то не вздумайте писать хоть в одном конфиге listen ip:80. Nginx начнет отвечать на все запросы к этому ip на 80м порту одним вхостом. То есть на все запросы станет показывать один и тот же сайт. Я так продакшн большой ломал, ага

Так вот. Имея на руках ip и порт, nginx выбирает все server{} с максимально совпадающим listen. Дальше по server_name начинает выбирать конкретный server{} из списка. server_name может быть записан в трех видах:

  • т.н. «exact name», (server_name www.example.com;)
  • wildcard (server_name *.example.com;, отдельной группой обрабатываются имена со звездочкой на конце, а не в начале).
  • регулярки (server_name ~^(?.+)\.example\.com$;)

Regex-ы, кстати, приятны тем, что при помощи них из Host можно сразу выделить кусочек и использовать его как переменную (собственно, в примере это и показано, ну или поищите в блоге по слову evhost).
Но важно на самом деле другое. Все эти 3 группы server_name обрабатываются отдельно. То есть, если у вас имя хоста указано явным образом в одном из конфигов (exact name), то nginx не будет пытаться искать то же самое в остальных именах (в wildcard-ах или regex-ах). То бишь, www.example.com (прописанный в одном конфиге) уже исключен из *.example.com в другом конфиге. И то же самое с регэкспами — в регэкспы уже точно не попадают те хосты, которые записаны в виде wildcard или точного совпадения.

Вот. Когда nginx исходя из listen и server_name уже выберет конкретный server{} для обработки запроса — то запрос будет обрабатываться именно в нём. В лайти, например, можно было написать конфиг так, что концов не сыщешь %).

Теперь стоит узнать об основных переменных, которые могут быть полезны в простейших манипуляциях с конфигом. В первую очередь, нам тут интересны те переменные, в которые попадают различные части URL запроса:

  • $scheme — протокол запроса (http/https)
  • $host — заумно описанная переменная в документации, не используйте её, в неё может оказаться ЁНХ (кстати, она ещё и не эскейпится, что чревато багами в нашем конфиге)
  • $http_host — это значение http-заголовка Host: , её и рекомендую использовать в конфигах.
  • $uri — это часть URL после корня (после хост, то бишь) без аргументов. Именно эта часть URL-а матчится с location-ами.
  • $args — это переменная, содержащая всю строку аргументов (всё, что после ? в URL).
  • $arg_x — это переменная, содержащая значение url-аргумента x (для ?x=bla, $arg_x будет содержать bla).
  • $request_uri — переменная, содержащая и $uri, и $args (то есть весь урл, кроме хоста и прото).

Теперь о том, как лучше делать редиректы. Если есть возможность — то используйте return, а не rewrite (все примеры ниже будут именно про return). Стоит помнить, что 301й кода ответа кешируется браузером (то есть браузер запомнит, что по этому URL был такой редирект и сразу пройдет по редиректу из кеша). 302й код ответа браузерам кешировать запрещено (в семье не без урода, конечно, но вообще это достаточно надежное условие). Везде в примерах я использую 302й редирект, чтобы вы случайно копипастя не сделали «вечный» редирект. И вообще я советую все редиректы писать именно 302-е, а менять на 301-е только после того, как вы убедитесь, что всё работает верно (ну и если вы уверены, что этот редирект навсегда).

Вот. Теперь, вооружившись этими знаниями, мы понапишем всяких странных и не очень редиректов.
Первый пример. Хост www.example.com редиректим на example.com, сохраняя URL.

server {
    listen 80;
    server_name www.example.com;
    location / { return 302 http://example.com$request_uri; }
}



Второй пример. Хост www.example.com редиректим на example.com, сохраняя протокол запроса, но не сохраняя URL (ну то есть всегда на морду example.com в том же протоколе).

server {
    include listen;
    include listen_ssl;
    server_name www.example.com
    location / { return 302 $scheme://example.com/ ; }
}



Третий пример. Все хосты *.example.com редиректим на https (на всякий случай, такой конфиг будет работать только если нет другого конфига для хостов вида *.example.com (в том числе и отдельно описанных, например www.example.com), в которых было бы прописано listen 80). URL сохраняем.

server {
    listen 80;
    server_name *.example.com;
    location / { return 302 https://$http_host$request_uri; }
}



Четвертый пример. Если в URL есть аргумент lang и его значение равно en, то редиректить нужно на en.example.com, сохранив URL без аргументов.

server {
    listen 80;
    server_name example.com;
    location / {
        if ($arg_lang = en) { return 302 http://en.example.com$uri ; }
    }
}



Да, если вам нужно сделать rewrite, исходя из наличия аргумента — то без if-а не обойтись. В остальных случаях лучше пользоваться приёмом из первых примеров — отделяем запрос в отдельный location внутри конкретного server{} и внутри него делаем return.
Ах да, лучше писать location / с редиректом внутри, даже если другой конфигурации в этом server{} сейчас не будет. Если потом вы решите дописать что-то, а return прописан у вас прямо в server{} — то потом можно поседеть.

Большой мануал: часть 20. Создаём конфиг для нашего сайта в nginx.

Эта статья — часть Большого Мануала по настройке lamp-сервера на debian. Предыдущая часть цикла — Создаём конфиг для нашего сайта в apache2. Следующая часть цикла — Учимся делать редиректы в nginx. Уххххрррр. Часть 20. Сегодня этот сайт наконец-то заработает %). Мы тут где-то когда-то ставили nginx, а я забыл рассказать, для чего. Попробуем исправить это [...]

Традиционный новогодний оффтоп: Делай дерьмо, живи в шоколаде!

Что меня заставило написать (впервые нытьё в блоге главного нытика Всея Руси! 5 лет держался!)? Да хрен знает. Может быть то, что я не могу найти новый телефон. Может быть то, что в моей машине случилась третья поломка за её жизнь, и она снова не связана с тем, что в машину положили на заводе. Может [...]

Ubuntu 16.04+, глюки с капсом (точнее, с переключением раскладок по капсу).

Собственно, в 16.04 появился прикольный баг у тех, кто переключает раскладки по капсу. Если вы печатаете быстро на двух языках, то при переключении раскладок у вас будет получаться Takaya Хуйня. То бишь лишние буквы в верхнем регистре (как я понял это от того, что я начинаю печатать быстрее, чем отпускаю капс. При этом раскладка переключается [...]

Ubuntu, опция «запоминать раскладку для каждого окна».

По традиции в бубунте в очередном релизе поломали половину галочек в гуёвом конфигураторе. Но нам-то что. Вообще фича очень удобная, чтобы не переключать раскладку, когда постоянно переключаешься между жаббером и терминалом. Включается (к слову в любом gtk-based поделии) так: user@server:~$ dconf write /org/gnome/libgnomekbd/desktop/group-per-window true

Большой мануал: часть 19. Создаём конфиг для нашего сайта в apache2.

Эта статья — часть Большого Мануала по настройке lamp-сервера на debian. Предыдущая часть цикла — Подготавливаем apache2. Следующая часть цикла — Создаём конфиг для нашего сайта в nginx. Вот и подошло время (блеать, спустя 18(!) частей), когда мы начинаем «запускать» наш сайт. Для начала немного экскурса в терминологию, чтобы не путаться дальше. — У вебсерверов [...]

Большой мануал: часть 18. Подготавливаем apache2.

Эта статья — часть Большого Мануала по настройке lamp-сервера на debian. Предыдущая часть цикла — Настраиваем SSL в nginx и получаем A-rate. Следующая часть цикла — Создаём конфиг для нашего сайта в apache2. Для того, чтобы apache мог работать вместе с nginx, его нужно немного настроить. Ну и заодно немного пооптимизируем его работу в плане [...]

Большой мануал: часть 17. Настраиваем SSL в nginx и получаем A-rate.

Эта статья — часть Большого Мануала по настройке lamp-сервера на debian. Предыдущая часть цикла — Подготавливаем nginx. Следующая часть цикла — Подготавливаем apache2. Сейчас, когда у нас есть сертификат и более-менее подготовленный к реальной жизни nginx, мы можем настроить ssl (и подготовиться к тому, чтобы заводить сайты с SSL). Первым делом, я напоминаю, что нельзя [...]

Большой мануал: часть 16. Подготавливаем nginx.

Эта статья — часть Большого Мануала по настройке lamp-сервера на debian. Предыдущая часть цикла — Ставим пакеты для lamp+nginx. Следующая часть цикла — Настраиваем SSL в nginx и получаем A-rate. В этой статье мы поговорим о некоторых настройках nginx, с которыми нам проще будет дальше жить. Вообще nginx очень гибок и настроить там можно хоть [...]