Nginx проверяем несколько условий


Оглавление (нажмите, чтобы открыть):

Полезные редиректы в nginx

В данной статье буду собирать все редиректы в nginx которыми пользуюсь

Рассматриваю на примере конфигурации веб-окружения BitrixVM, т.к. занимаюсь разработкой именно в данной среде, но правила одинаковые для любых систем, поэтому, это не принципиально.

Правила нужно прописывать в файле с описаниемм конфигурации конкретного хоста (для BitrixVM это
/etc/nginx/bx/site_avaliable/bx_ext_domain.conf — для сайта, работающего без ssl;
/etc/nginx/bx/site_avaliable/bx_ext_ssl_domain.conf — при работе по ssl);

Саму настройку на перенаправление в NGINX можно прописать двумя способами.

* $host — имя хоста из запроса, если отсутствует — имя в поле «Host» заголовка, если тоже отсутствует — имя сервера; $request_uri — первоначальный запрос с аргументами (все, что идет после доменного имени). ** где флаги могут быть следующие:

  • permanent — перенаправление с кодом 301.
  • redirect — перенаправить с кодом 302.
  • last — закончить обработку с переходом в новый location.
  • break — закончить обработку и остаться в текущем location.

Где коды могут использоваться любые, но чаще всего — 301, 302, 404.

Есть различные мнения, какой из методов лучше и безопаснее, поэтому каким воспользоваться — решать по ситуации. В сети в примерах используется чаще всего второй вариант.

Редирект с http: на https

Или, если вам повезло также как и мне и конфигурационные файлы для ssl и без ssl — разные, то в файле для без ssl можно прописать прямой редирект:

редирект с www на без www

Добавляем слеши в конце

Убираем слеш в конце

Убираем index.php в конце адреса

Если для определенных разделов данный редирект нужно отключить, то в маску добавляем разделы исключения:

Чтобы сохранить параметры в адресной строке, нужно задать:

Редирект для конкретной страницы

Обычный редирект в htaccess имеет вид:

В nginx примет вид:

Также, редирект конкретного файла можно сделать так:

Чтобы удалить из адреса часть строки, можно сделать так:

Редирект с одного домена на другой

Редирект с каждой страницы одного домена на такой же URL адрес другого домена

Редирект домена и всех его поддоменов:

Сложный анализ ЧПУ

Пример из сети по обработке api-запросов:

Пока не приходилось сталкиваться, но, может быть, кому-то будет полезным!

Перенаправление запросов для отсутствующих доменов (перенаправление по умолчанию)

Для этого, в основном конфигурационном файле (для bitrixVM это /etc/nginx/bx/site_available/s1.conf) пишем:

или независимо от протокола:

* $scheme позволяет перевести запрос на тот же протокол (http или https), по которому он был инициирован.
* если nginx должен слушать и обрабаывать запросы по https, необходимо указывать в настройках пути к сертификатам.

Редирект на особенную страницу по 404-му статусу

Если страница не найдена — будет выдан 404-й статус и показана соответствующая страница. Но иногда, для случая, когда при отсутствии того или иного файла должен быть выполнен редирект куда-то, можно воспользоваться конструкцией:

По этой логике можно определять любые конструкции, которые вам нужны. Сначала сервер попробует выполнить файл, и, если он не будет найден, он переместится в часть @missing. А второй блок, с @missing, перенаправит на нужную страницу.

Использование вложенных if

Вложенные if в конфигурации nginx запрещены, поскольку это вовсе не языковая конструкция nginx, а обычная директива из модуля rewrite, использование которой в ее же собственном контексте if не предусмотрено. Использование списка условий, разделенных логическими операторами «и» и «или» тоже не предусмотрено. Обычно для эмуляции вложенных условий с использованием директивы if предлагают использовать регулярные выражения. Например, проверить, что имя, указаное в HTTP хедере HOST, соответствует значению localhost, а в URI присутствует аргумент «a» (в этом случае переменная $arg_a будет не пустой), можно так:

К сожалению, условие в директиве if имеет ограничения. По крайней мере, это не выражение, и оно не может быть составлено в виде цепочки выражений, разделенных логическими операторами. Кроме того, в случае сравнения чего-то с регулярным выражением, это что-то может быть только именем переменной, именно поэтому пришлось ввести новую переменную $cond:

В данном примере мы соединили через произвольно выбранный нами разделитель :: три переменных $host, $goodhost и $arg_a и присвоили это значение переменной $cond. А регулярное выражение, с которым мы сопоставляем это значение, проверяет, что его первая часть (до разделителя ::) и вторая часть (до второго разделителя ::) равны, а последняя часть (после второго разделителя) не пуста.

В полном виде конструкция проверки примет вид:

Описание структуры работы с вложенными if взято отсюда .

Сложное условие и проксирование запросов

Если нужно выполнить проксирование запросов с помозью директивы proxy_pass только при соблюдении нескольких условий, то можно воспользоваться следующей конструкцией:

Пояснения:

Условие RewriteCond обозначает совпадение с которым будет выполнено правило RewriteRule. При этом, используются символы:
. – Точка — это любой символ (но только один!).
^ — Эта метка означает начала строки.
$ — Эта метка означает конец строки.
\ — Эта экранирующий слэш, позволяет считать следующий за ним символ, обычным символом.
() – Этот символ обозначает группировку.
! – Метка отрицания.
+ — Этот символ повторяется от 1 до 65536 раз.
? — Этот символ повторяется 0 или 1 раз.
* — А этот символ повторяется от 0 до 65536 раз.
Флаги определяют дополнительные опции.
R — (redirect) — По умолчанию останавливает процесс преобразования, возвращает результат в браузер клиента, как редирект на данную страницу 302, MOVED TEMPORARY. Например флагу можно указать другой код результата, R=301 и он возвратит редирект клиенту с кодом 301 MOVED PERMANENTLY.
NC — (nocase) — Этот флаг отключает проверку регистра символов.
L — (last) — Флаг останавливает процесс преобразования, текущая ссылка считается окончательной.

Чтобы изменения вступили в силу — не забудьде произвести рестарт nginx. Но для начала — проверьте, что ваша конфигурация в порядке. Для этого выполните команду:

Если выдаст «OK» — делаем смело перезагрузку:

Первый вариант — для устаревших систем Linux или FreeBSD. Второй — для новых систем Linux

Если же показывает ошибку — разбираемся с ней.

Проверяя редиректы в браузере, следует учесть, что настройки могут кэшироваться. Для обновления кэша используйте комбинацию Ctrl + F5. Если и это не помогает, закрывайте вкладку и открывайте новую.


Отличия между 301 и 302 редиректами:

В чем принципиальная разница между ответом с кодом 301 и 302? Для обычного посетителя сайта разницы нет. А вот для поискового робота разница огромная.

301-й редирект говорит о склеивании страниц. Это означает для поисковика то, что старая и новая страницы — это одно и тоже. Таким образом результаты ранжирования необходимо сохранить для новой страницы.

302-о перенаправление просто говорит о том, что нужно перейти по другому адресу. Поисковый робот не сохраняет результат выдачи для новой страницы, индексируя его с нуля.

P.S. Не забывайте, что внесение любых изменений в конфигурации сервера могут привести к тому, что самостоятельно вы можете и не восстановить. Поэтому не забывайте делать бекапы!

Благодарю за внимание! Делитесь вашими замечаниями в комментариях ниже.

unixforum.org

Форум для пользователей UNIX-подобных систем

  • Темы без ответов
  • Активные темы
  • Поиск
  • Статус форума

nginx и условия if

Модератор: SLEDopit

nginx и условия if

Сообщение bars » 23.06.2014 19:22

Re: nginx и условия if

Сообщение BigBrother » 23.06.2014 21:08

Re: nginx и условия if

Сообщение Bizdelnick » 24.06.2014 00:52

Примеры редиректов в NGINX

Настройка перенаправлений

Настройки необходимо вносить в файлах конфигураций виртуальных доменов. В Linux на основе RPM (CentOS, Red Hat), как правило, они расположены в директории /etc/nginx/conf.d/. В Linux на основе Deb (Ubuntu, Debian) — в директории /etc/nginx/sites-enabled/. Во FreeBSD все в одном файле — /usr/local/etc/nginx/nginx.conf.

Саму настройку на перенаправление в NGINX можно прописать несколькими способами.

* $host — имя хоста из запроса, если отсутствует — имя в поле «Host» заголовка, если тоже отсутствует — имя сервера; $request_uri — первоначальный запрос с аргументами (все, что идет после доменного имени).
** где флаги могут быть следующие:

  • permanent — перенаправление с кодом 301.
  • redirect — перенаправить с кодом 302.
  • last — закончить обработку с переходом в новый location.
  • break — закончить обработку и остаться в текущем location.

* где коды могут использоваться любые, но чаще всего — 301, 302, 404.

Есть различные мнения, какой из методов лучше и безопаснее, поэтому каким воспользоваться — решать по ситуации. В данных примерах используется второй вариант.

После внесения изменений, необходимо проверить их корректность:

И для их применения перезапустить веб-сервер:

systemctl restart nginx

service nginx restart

* в первом примере перезапуск выполняется на новых системах Linux. Второй пример — на устаревших или FreeBSD.

Проверяя редиректы в браузере, следует учесть, что настройки могут кэшироваться. Для обновления кэша используйте комбинацию Ctrl + F5. Если и это не помогает, закрывайте вкладку и открывайте новую.

С HTTP на HTTPS

server <
listen 80;
server_name domain.ru www.domain,ru;
return 301 https://$host$request_uri;
>

* в данном примере для всех обращений к сайту domain.ru по 80 порту (http) будет работать редирект на 443 порт (https) с кодом 301 (для склеивания доменов).

С одного домена на другой

server <
.
server_name domain1.ru;
return 302 http://domain2.ru$request_uri;
>

C домена без www на домен с www

server <
.
server_name domain.ru;
return 301 http://www.$host$request_uri;
>

С www на без www

^www\.(.*)$» ;
return 301 $scheme://$1$request_uri;
>

C index.php на /

server <
.
if ($request_uri

Перенаправление запросов для отсутствующих доменов (перенаправление по умолчанию)

Если обращение к веб-серверу идет по IP-адресу или домену, который не прописан в конфигурационном файле, можно перенаправить весь трафик на домен по умолчанию:


server <
listen 80 default_server;
return 302 https://welcome.domain.ru$request_uri;
>

или независимо от протокола:

server <
listen 80 default_server;
return 302 $scheme://welcome.domain.ru$request_uri;
>

server <
listen 443 default_server;
return 302 $scheme://welcome.domain.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, необходимо указывать в настройках пути к сертификатам.

На другой сервер

Пример внутреннего перенаправления http-запроса на другой веб-сервер:

.
location / <
proxy_pass $scheme://192.168.0.15:8080/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
>

* в данном случае, принимать запросы от браузера и отвечать на них будет NGINX, а сама обработка будет выполняться на сервере с IP-адресом 192.168.0.15 на порту 8080.

Использование NGINX в качестве http-прокси:

server <
.
server_name site1.ru www.site1.ru;
location / <
proxy_pass http://192.168.1.21/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
>
>

server <
.
server_name site2.ru www.site2.ru;
location / <
proxy_pass http://192.168.1.22/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
>
>

* в данном примере запросы на site1.ru будут перекинуты на сервер 192.168.1.21, а запросы на site2.ru192.168.1.22.

HTTP proxy с авторизацией (если удаленный веб-сервер требует аутентификации):

server <
.
location / <
proxy_pass http://10.10.10.10/page/;
proxy_set_header Authorization «Basic dGVzdDp0ZXN0»;
.
>

* где 10.10.10.10/page — страница, на которую будут перекинуты запросы; dGVzdDp0ZXN0 — логин:пароль test:test, закодированные в формате base64.

С IP-адреса на домен

В данном случае мы переводим все запросы по IP-адресу на конкретный домен:

server <
listen 80;
server_name 192.168.1.15;
return 301 http://site.ru$request_uri;
>

* при отправке http-запроса на сервер 192.168.1.15 по IP-адресу, ое будет переведен на домен site.ru.

Редирект домена и всех его поддоменов

server <
.
server_name domain domain.*;
return 301 https://$host$request_uri;
>

На другой файл

Это скорее не перенаправление, а алиас или rewrite. Позволяет по запросу одного из файлов, отдать другой:

server <
.
location = /robots.txt <
rewrite ^/robots.txt$ /robots2.txt;
>
>

* в данном примере по запросу robots.txt, сервер отдаст содержимое robots2.txt.

Часть url на другой сервер

Перенаправить запрос на жругой сервер при обращении по url page1:

Это позволит передать на обработку запроса по определенному url на другой сервер:

Удалить часть URL

Иногда нужно удалять часть url. Это можно сделать следующими способоми:

server <
.
rewrite /deleted-url/(.*) /$1 permanent;
>

server <
.
if ($request_uri

* в данном примере из url мы удалим deleted-url/.

Перенаправить запрос в случае обращения к несуществующим файлам

Предположим, что нам нужно обращаться к скриптам на сервере, но без прописывания в URL .php на конце. Запрос будет выглядеть, примерно, http://url/. Чтобы nginx перекинул запрос на url.php вставляем следующее:

* в данном примере мы проверяем наличие файла, к которому идет обращение. И если его нет, то происходит замена адреса на такоеже имя файла с .php на конце.

Немного о 301 и 302

В чем принципиальная разница между ответом с кодом 301 и 302? Для обычного посетителя сайта разницы нет. А вот для поискового робота разница огромная.

301-й редирект говорит о склеивании страниц. Это означает для поисковика то, что старая и новая страницы — это одно и тоже. Таким образом результаты ранжирования необходимо сохранить для новой страницы.

302-о перенаправление просто говорит о том, что нужно перейти по другому адресу. Поисковый робот не сохраняет результат выдачи для новой страницы, индексируя его с нуля.

Алгоритмы выбора блоков server и location в Nginx

Nginx – один из популярнейших веб-серверов в мире. Он может обрабатывать высокие нагрузки и большое количество одновременных подключений. Также Nginx можно использовать в качестве балансировщика, почтового сервера или обратного прокси.

Данный мануал расскажет, как Nginx обрабатывает клиентские запросы. Понимание этого механизма поможет вам оптимизировать обработку запросов.

Конфигурация блоков Nginx

Nginx логически делит конфигурации, предназначенные для обслуживания различного контента, на блоки, которые собираются в иерархическую структуру. Обработку каждого запроса клиента Nginx начинает с определения необходимых блоков конфигурации. Этот процесс принятия решений будет центральной темой данного мануала.

Основные блоки, которые мы обсудим, называются server и location.

Блок server – это подмножество конфигурации Nginx, которая определяет виртуальный сервер, используемый для обработки запросов определенного типа. Администраторы часто настраивают несколько блоков server, где каждый блок обрабатывает соединения на основе запрошенного домена, порта и IP-адреса.

Блок location находится в блоке server и используется для того, чтобы Nginx мог обрабатывать запросы для разных ресурсов и URI родительского сервера. С помощью этого блока администратор может разделить пространство URI требуемым образом. Это чрезвычайно гибкая модель.

Мастер Йода рекомендует:  Как использовать HTML-тег base


1: Поиск блока server

Nginx позволяет определять несколько блоков server, которые функционируют как отдельные экземпляры виртуальных веб-серверов. Потому Nginx необходима процедура определения того, какой из этих блоков будет использоваться для обработки запроса.

Для этого Nginx применяет определенную систему проверок, которые используются для поиска наилучшего совпадения. Основные директивы блока server, которые помогают Nginx определить требуемый блок, — это listen и server_name.

Директива listen

Сначала Nginx смотрит на IP-адрес и порт запроса. Он сопоставляет эти значения с директивой listen каждого блока server и создает список блоков, которые могут обслужить запрос.

Директива listen обычно определяет IP-адрес и порт блока server. По умолчанию любой блок server, в котором нет директивы listen, получает параметры 0.0.0.0:80 (или 0.0.0.0:8080, если Nginx запускается обычным пользователем без полномочий root). Это позволяет таким блокам отвечать на запросы на любом интерфейсе по порту 80. Но это стандартное значение не имеет большого веса в процессе выбора блока.

Директива listen может указывать:

  • IP-адрес и порт.
  • Только IP-адрес (тогда будет использоваться порт по умолчанию 80).
  • Только порт (тогда будут прослушиваться все интерфейсы).
  • Путь к Unix-сокету.

Последний вариант, как правило, используется только при передаче запросов между разными серверами.

Сначала Nginx попробует выбрать блок на основе директивы listen, используя следующие правила:

  • Nginx переводит все «неполные» директивы listen, заменяя отсутствующие значения значениями по умолчанию, чтобы затем оценить каждый блок по его IP-адресу и порту. Например:
    • Если в блоке нет директивы listen, блоку будет присвоено значение 0.0.0.0:80.
    • Если в блоке указан только IP-адрес 111.111.111.111, ему будет присвоен стандартный порт: 111.111.111.111:80.
    • Если в блоке указан только порт 8888, ему будет присвоен стандартный IP-адрес: 0.0.0.0:8888.
  • Затем Nginx пытается собрать список блоков server, которые соответствуют запросу, в частности, на основе IP-адреса и порта. Это означает, что любой блок, который использует IP-адрес 0.0.0.0, не будет выбран, если есть блоки, которые настроены на заданный IP-адрес. Порт должен совпадать точно.
  • Если веб-сервер находит всего одно совпадение, он просто использует этот блок server для обслуживания запроса. Если он найдет несколько блоков, которые отвечают всем требованиям, Nginx выберет один блок на основе директивы server_name.

Важно понимать, что Nginx будет оценивать директиву server_name только тогда, когда ему нужно выбрать один блок из списка блоков, отобранных по директиве listen. Например, если домен example.com размещен на порту 80 по адресу 192.168.1.10, запрос на example.com всегда будет обслуживаться первым блоком в пример ниже, несмотря на директиву server_name во втором блоке.

server <
listen 192.168.1.10;
. . .
>
server <
listen 80;
server_name example.com;
. . .
>

Если же Nginx отобрал несколько блоков с одинаковым уровнем специфичности, далее он проверит директиву server_name.

Директива server_name

Для дальнейшей оценки запросов, имеющих одинаковые определения директивы listen, Nginx проверяет заголовок Host запроса. Это значение содержит домен или IP-адрес, который запрашивает клиент.

Nginx ищет наилучшее совпадение этого значения в директиве server_name каждого блока, прошедшего предыдущий этап отбора. Nginx оценивает эту директиву по этой формуле:

  • Сначала Nginx пытается найти блок server, значение server_name которого точно соответствует значению в заголовке Host запроса. Если такой блок найдется, он будет использоваться для обслуживания запроса. Если Nginx найдет несколько точных совпадений, используется первый найденный блок.
  • Если Nginx не нашел точное совпадение, он попытается найти блок, директива server_name которого начинается со специального символа *. Если Nginx найден такой блок, этот блок будет использоваться для обслуживания запроса. Если Nginx найдет несколько совпадений, для обслуживания запроса будет использоваться наиболее точное совпадение.
  • Если Nginx не нашел совпадений по специальному символу в начале server_name, он будет искать блок, чье значение server_name заканчивается специальным символом *. Если такой блок найден, он используется для обслуживания запроса. Если Nginx найдет несколько совпадений, для обслуживания запроса будет использоваться наиболее точное из них.
  • Если Nginx не нашел совпадений по специальному символу в конце server_name, он оценивает блоки, чье значение server_name использует регулярные выражения (они определяются символом

перед именем). Для обслуживания запроса будет использоваться первый блок, который содержит в server_ name регулярное выражение, которое соответствует заголовку Host.

  • Если найти блок по регулярным выражениям не удалось, Nginx выбирает блок server по умолчанию для этого IP-адреса и порта.
  • Для каждой комбинации IP-адреса и порта существует блок server по умолчанию, который используется в случае, если веб-сервер не смог найти другой блок. Как правило, это либо первый блок в конфигурации, либо блок, который содержит параметр default_server как часть директивы listen (она переопределяет алгоритм поиска первого совпадения). Для каждой комбинации IP-адреса и порта может быть только одно объявление default_server.

    Примеры

    Если в конфигурации есть блок с директивой server_name, значение которой полностью совпадает с заголовком Host запроса, запрос передается на обработку этому блоку.

    К примеру, если заголовок Host запроса – host1.example.com, веб-сервер выберет для его обслуживания второй блок server:

    server <
    listen 80;
    server_name *.example.com;
    . . .
    >
    server <
    listen 80;
    server_name host1.example.com;
    . . .
    >

    Если Nginx не находит точных совпадений, он будет искать блок, в котором server_name начинается со специального символа. Если Nginx найдет несколько совпадений, для обслуживания запроса будет использоваться наиболее точное из них. Например, если в запросе указан заголовок Host www.example.org, Nginx выберет второй блок:

    server <
    listen 80;
    server_name www.example.*;
    . . .
    >
    server <
    listen 80;
    server_name *.example.org;
    . . .
    >
    server <
    listen 80;
    server_name *.org;
    . . .
    >

    Если найти блок по специальному символу в начале директивы не удалось, Nginx будет искать блок, значение server_name которого заканчивается специальным символом. Если он найдет несколько совпадений, он использует наиболее точное из них. К примеру, для обработки запроса с заголовком Host www.example.com веб-сервер использует третий блок server:

    server <
    listen 80;
    server_name host1.example.com;
    . . .
    >
    server <
    listen 80;
    server_name example.com;
    . . .
    >
    server <
    listen 80;
    server_name www.example.*;
    . . .
    >

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

    К примеру, для обслуживания запроса с заголовком Host www.example.com веб-сервер выберет второй блок server:

    server <
    listen 80;
    server_name example.com;
    . . .
    >
    server <
    listen 80;
    server_name

    ^(www|host1).*\.example\.com$;
    . . .
    >
    server <
    listen 80;
    server_name

    Если ни один из механизмов поиска не дал результатов, веб-сервер применит блок server по умолчанию.

    2: Поиск блока location

    Похожий алгоритм Nginx использует для поиска блока location.

    Синтаксис блока location

    Для начала следует ознакомиться с синтаксисом блока location. Блоки location находятся внутри блоков server (или других блоков location) и используются для определения способа обработки URI запроса (той части запроса, которая идет после имени домена или IP-адреса/порта).

    Как правило, блок location имеет такой вид:

    location optional_modifier location_match <
    . . .
    >

    location_match в приведенном выше примере указывает, что Nginx должен проверить URI запроса. Наличие или отсутствие модификатора в приведенном выше примере влияет на то, как Nginx будет искать блок location.


    Существуют такие модификаторы блоков location:

    • (нет): если в блоке нет модификатора, блок location интерпретируется как префикс. Это означает, что для определения соответствия указанный блок будет сравниваться с началом URI запроса.
    • =: этот блок будет выбран, если URI запроса точно соответствует указанному location-у.

    : такой блок будет интерпретироваться как совпадение по регулярному выражению с учетом регистра.

    *: такой блок будет интерпретироваться как совпадение по регулярному выражению без учета регистра.
    ^

    : если этот блок выбран как наиболее точное совпадение без регулярного выражения, то веб-сервер не будет проводить поиск по регулярному выражению.

    Примеры синтаксиса блока location

    В качестве примера поиска по префиксу можно использовать следующий блок location для ответа на запросы URI (/site, /site/page1/index.html, или /site/index.html).

    Ниже вы найдете пример точного совпадения URI. Такой блок всегда будет использоваться для обслуживания URI

    /page1. Он не будет отвечать на URI запроса /page1/index.html. Имейте в виду, что если выбран этот блок и запрос обслуживается индексной страницей, произойдет внутреннее перенаправление в другой блок location, который будет фактическим обработчиком запроса.

    Интерпретация блока location как регулярного выражения с учетом регистра происходит в следующем примере. Этот блок будет использован для обработки запросов для /tortoise.jpg, но не для /FLOWER.PNG:

    В следующем примере происходит интерпретация блока location как регулярного выражения без учета регистра. Такой блок сможет обработать запросы и для /tortoise.jpg, и для /FLOWER.PNG.

    Следующий блок отключит поиск по регулярному выражению, если он выбран как наилучшее совпадение без регулярных выражений. Он может обрабатывать запросы для /costumes/ninja.html:

    Как видите, модификаторы указывают, как следует интерпретировать блок location. Тем не менее, это не определяет алгоритм, который Nginx использует, чтобы решить, какому блоку location отправить запрос.

    Выбор блока location

    Nginx выбирает блок location аналогично тому, как он выбирает блок server. Он запускает процесс, который определяет лучший блок location для конкретного запроса. Понимание этого процесса является важнейшим требованием для надежной и точной настройки Nginx.

    Имея в виду типы объявлений, которые мы рассмотрели выше, Nginx оценивает возможные контексты location путем сравнения URI запроса с каждым из местоположений. Он делает это, используя следующий алгоритм:

    • Сначала Nginx проверяет все блоки location, заданные префиксными строками. Для этого location сравнивается с полной строкой URI.
    • Затем Nginx ищет точное совпадение. Если он находит location с модификатором =, он прекращает поиск и использует найденную конфигурацию.
    • Если точного совпадения не обнаружено, веб-сервер выполняет поиск по неточным совпадениям. Он ищет location с совпадающим префиксом максимальной длины для заданного URI, который затем оценивается таким образом:
      • Если location с совпадающим префиксом максимальной длины содержит модификатор ^

      , то Nginx немедленно прекратит поиск и выберет этот блок location для обслуживания запросов.
      Если location с совпадающим префиксом максимальной длины не содержит модификатора ^

      , то Nginx запомнит этот префикс и продолжит поиск.

  • После того, как Nginx нашел и запомнил location с совпадающим префиксом максимальной длины, он приступает к оценке регулярных выражений (с учетом и без учета регистра). Если в location с совпадающим префиксом максимальной длины есть какие-либо блоки location с регулярными выражениями, Nginx поместит их в начало списка регулярных выражений для проверки. Затем Nginx последовательно сравнит блоки с регулярными выражениями. Для обработки будет выбрано первое выражение, которое соответствует URI запроса.
  • Если совпадение с регулярным выражением не найдено, Nginx использует конфигурацию запомненного ранее префиксного location-а.
  • Важно понимать, что по умолчанию Nginx будет обслуживать регулярные выражения, отдавая предпочтение совпадениям по префиксам. Однако сначала он оценивает префиксные location-ы, позволяя администратору переопределять это поведение, указав location-ы с помощью модификаторов = и ^

    Также важно отметить, что, хотя префиксные location-ы обычно выбираются на основе префикса максимальной длины (наиболее точного совпадения), Nginx перестанет оценивать регулярные выражения при обнаружении первого подходящего location-а. Это означает, что расположение в конфигурации блоков location с регулярными выражениями имеет огромное значение.

    Оценка блоков location

    Теперь нужно разобраться, в каких случаях оценка блоков location переходит к другим location-ам.

    В целом, с того момента, как блок location выбран для обслуживания запроса, запрос обрабатывается целиком в этом контексте. Только выбранный блок location и унаследованные директивы определяют, как обрабатывается запрос, а соседние блоки location не могут вмешиваться в этот процесс.

    Это общее правило, которое позволит вам спроектировать блоки location предсказуемым образом. Но при этом важно понимать, что бывают случаи, когда определенные директивы запускают новый поиск location-а внутри выбранного блока location. Исключения из правила могут привести к появлению непредсказуемых результатов.

    Вот некоторые из директив, которые могут стать причиной такого поведения:

    Директива index всегда приводит ко внутреннему перенаправлению, если она используется для обработки запроса. Точные совпадения location-а часто используются для ускорения процесса выбора, потому что это немедленно прекратит выполнение алгоритма. Однако если точное соответствие location-а будет каталогом, есть вероятность, что для фактической обработки запрос будет перенаправлен в другое место.

    В этом примере первый location совпадает с URI запроса /exact, но директива index, унаследованная блоком, для обработки запроса инициирует внутреннее перенаправление ко второму блоку:

    index index.html;
    location = /exact <
    . . .
    >
    location / <
    . . .
    >

    Если вы хотите, чтобы в приведенном выше случае запрос обрабатывался первым блоком, вам придется придумать другой метод попадания запроса в каталог. Например, вы можете установить для этого блока неправильный index и включить autoindex:

    location = /exact <
    index nothing_will_match;
    autoindex on;
    >
    location / <
    . . .
    >

    Это один из способов предотвратить перенаправление запроса из первого контекста, но он, вероятно, не подходит для большинства конфигураций. В основном точное совпадение в каталогах может быть полезно для таких операций, как переписывание запроса (что также приводит к новому поиску блока location).

    Еще один случай, в котором может начаться новый поиск location-а – это использование директивы try_files. Эта директива говорит Nginx проверить наличие именованного набора файлов или каталогов. Последним параметром может быть URI, на который Nginx сделает внутреннее перенаправление.

    Рассмотрим такую конфигурацию:

    root /var/www/main;
    location / <
    try_files $uri $uri.html $uri/ /fallback/index.html;
    >
    location /fallback <
    root /var/www/another;
    >

    Если в приведенном выше примере запрос сделан для /blahblah, сначала получит запрос первый location. Он попытается найти файл с именем blahblah в каталоге /var/www/main. Если он не сможет найти его, он будет искать файл с именем blahblah.html. Затем он попытается узнать, есть ли в каталоге /var/www/main каталог blahblah/. Если все эти попытки не принесут результатов, запрос будет перенаправлен на /fallback/index.html. Это вызовет новый поиск location-а, и запрос перейдет второму блоку. Он обслужит файл /var/www/another/fallback/index.html.

    Также на поиск блоков влияет директива rewrite. Обрабатывая rewrite без параметров или с параметром last, Nginx будет искать новый блок location на основе результатов перезаписи.

    Например, если изменить последний пример и добавить в него перезапись, вы увидите, что запрос иногда передается непосредственно второму блоку location, не полагаясь на директиву try_files:

    root /var/www/main;
    location / <
    rewrite ^/rewriteme/(.*)$ /$1 last;
    try_files $uri $uri.html $uri/ /fallback/index.html;
    >
    location /fallback <
    root /var/www/another;
    >


    В приведенном выше примере запрос /rewriteme/hello будет сначала обрабатываться первым блоком location. Он будет переписан в /hello, и веб-сервер будет искать location. В этом случае он снова будет соответствовать первому location-у и обрабатываться директивой try_files (возможно, используя внутреннее перенаправление, чтобы вернуться к /fallback/index.html, если ничего не было найдено).

    Однако если запрос сделан для /rewriteme/fallback/hello, первый блок снова будет отвечать запросу. При этом снова применяется перезапись, на этот раз в результате получится /fallback/hello. Затем запрос будет обслуживаться вторым блоком.

    Похожая ситуация возникает с директивой return при отправке кодов состояния 301 или 302. Разница в этом случае заключается в том, что она приводит к совершенно новому запросу извне переадресации. Такая же ситуация может возникнуть с директивой rewrite при использовании флагов redirect или permanent.

    Директива error_page может привести к внутреннему перенаправлению аналогично тому, как это делает try_files. Эта директива используется для определения действий, которые выполняются при обнаружении определенных кодов состояния. Эти действия, вероятно, никогда не будут выполнены, если установлена директива try_files, так как эта директива обрабатывает весь жизненный цикл запроса.

    Рассмотрим такой пример:

    root /var/www/main;
    location / <
    error_page 404 /another/whoops.html;
    >
    location /another <
    root /var/www;
    >

    Каждый запрос (кроме тех, которые начинаются с /another) будет обрабатываться первым блоком, который будет обслуживать файлы из каталога /var/www/main. Однако если файл не найден (статус 404), произойдет внутреннее перенаправление на /another/whoops.html, что приведет к новому поиску блока location, который в конечном итоге окончится вторым блоком. Этот блок будет обслуживать файл /var/www/another/whoops.html.

    Как видите, понимание условий, при которых Nginx запускает новый поиск блока location, может помочь предсказать поведение веб-сервера при выполнении запросов.

    Что такое Nginx

    Содержание:

    Nginx — мощный инструмент для развертывания веб-сервера, который при правильной настройке превосходит Apache. Области применения Nginx весьма обширны — от кэширования HTTP до создания инвертированного прокси-сервера.

    Сейчас Nginx обслуживает примерно 30,8% всех существующих сайтов мира, о чьих веб-серверах есть информация в открытом доступе. Понимание, что из себя представляет Nginx и как этот программный продукт можно применять на практике, помогает эффективно решать задачи во многих областях IT-индустрии.

    В этой статье рассмотрим принцип работы Nginx, а также его функционал, отличия от Apache и способ установки на конкретную ОС.

    Что такое Nginx

    Nginx (NGINX, Engine-X, «Энжин-кс») — это бесплатный веб- и почтовый прокси-сервер с непоточной (асинхронной) архитектурой и открытым кодом.

    Разработку Nginx начал в 2002 году Игорь Сысоев для Rambler. А в 2004 году он стал доступен широкому кругу пользователей . С 2011 года серверное ПО начала выпускать уже собственная фирма Игоря, которая спустя 2 года запустила расширенную платную версию продукта (Nginx Plus). Весной 2020 года Nginx была выкуплена крупным американским девелопером F5 Networks.

    Nginx работает на ОС Unix-типа и был успешно протестирован на OpenBSD, FreeBSD, Linux, Mac OS X, Solaris. На ОС Windows он стал доступен после выпуска бинарной сборки 0,7.52.

    На данный момент функционалом пользуются такие известные платформы: Rambler, Begun, Yandex, SourceForge.net, WordPress.com, vkontakte.ru. Статистика показывает, что Nginx используют 22,3 млн веб-сайтов и 2,03 млн дополнительных активных сайтов.

    Как работает Nginx

    В отличие от обычного веб-сервера, Nginx не создаёт один поток под каждый запрос, а разделяет его на меньшие однотипные структуры, называемые рабочими соединениями. Каждое такое соединение обрабатывается отдельным рабочим процессом, а после выполнения они сливаются в единый блок, возвращающий результат в основной процесс обработки данных. Одно рабочее соединение может обрабатывать до 1024 запросов одного вида одновременно.

    Практическое применение

    1. Отдельный порт/IP. При наличии большого количества статичного контента или файлов для загрузки, можно настроить на отдельном порту или IP, чтобы осуществлять раздачу. При большом количестве запросов рекомендуется ставить отдельный сервер и подключать к нему Nginx.
    2. Акселерированное проксирование. В таком случае все пользовательские запросы на статичный контент (картинки, простой HTML, JavaScript, CSS-файлы) поступают сначала на Nginx, а он их обрабатывает самостоятельно. При этом никаких изменений исходного кода не требуется.
    3. Nginx и FastCGI. Если поддерживается технология FastCGI, Apache вообще можно не использовать. Но в таком случае может потребоваться модификация кодов скриптов.

    NGINX vs Apache

    Веб-сервер Nginx по сравнению с Apache быстрее работает при отдаче статики и потребляет меньше серверных ресурсов. Его использует вместо или с Apache для ускорения обработки запросов и уменьшения нагрузки. Это обуславливается тем, что большая часть тех возможностей, которые предлагает Apache, обычным пользователям не требуется.

    Поскольку с широким функционалом задействуется значительно больше ресурсов системы, использовать связку «Nginx + Apache» часто и полностью задействовать нецелесообразно. Достаточно часто оба веб-сервера используются в симбиозе — Nginx отдает статику и перенаправляет обработку скриптов Apache.

    Нужно, чтобы Nginx и Apache работали без сбоев? Мощный VPS от Eternalhost позволит сохранить оптимальную производительность, даже при пиковых нагрузках.

    Сильные и слабые стороны

    • Оба серверы хорошо работают на системах типа Unix, но производительность Nginx на Windows заметно ниже.
    • Для получения пользовательской поддержки можно обратиться на форум или почту компании, но у Apache Foundation есть с этим проблемы.
    • При одновременной работе Nginx оказывается в два раза быстрее Apache и использует меньше памяти, с динамическим контентом скорость равна.
    • Apache хорошо справляется с хостингом нескольких сайтов сразу, но Nginx показывает лучшую «гибкость» и эффективность работы с динамическим контентом.

    Архитектура и конфигурация Nginx

    Установка на Linux возможна двумя способами — из предварительно собранного бинарного файла (пакета) или с помощью исходного кода.

    Первый способ самый простой, но второй позволяет подключить различные дополнительные модули, расширяющие возможности сервера. Установка с помощью исходного кода применяется сравнительно редко, поэтому ее особенности рассматривать здесь не будем.

    Установка Nginx на Windows возможна с помощью интерфейса Win32 API. Однако, такой вариант будет гораздо менее эффективен, даже в серверных версиях и не может быть рекомендован для широкого применения.

    Установка из предварительно собранного файла

    1. Необходимо воспользоваться командой:
    2. Чтобы проверить, все ли прошло нормально, можно ввести команду, которая покажет установленную версию:

    Для конфигурации Nginx задействуется директория /etc/nginx/. При дальнейшей работе с сервером важны файл nginx.conf и папка sites-available.

    Основные настройки можно в файле nginx.conf. Благодаря этому файлу, все параметры можно настроить по своему усмотрению. Работать можно и с настройками по умолчанию.

    Важные элементы конфигурации


    • worker_processes — количество рабочих процессов, которые будет использовать сервер. Число должно соответствовать количеству ядер процессора.
    • worker_connections — это максимальное количество подключений каждого рабочего процесса. Чем выше показатель, тем больше человек обслуживается одновременно.
    • access_log & error_log — эти файлы используется для регистрации любой ошибки и попыток получения доступа. Журналы изучаются для устранения неполадок и при аварийном завершении работы.
    • gzip — это настройки для «сжатия» запросов Nginx. Включение параметра позволит повысить производительность. По умолчанию поднастройки закомментированы.
    • gzip_comp_level — уровень сжатия от 1 до 10. Этот показатель обычно не превышает 6.
    • gzip_types — это перечень типов ответов, к которым применяется сжатие.

    Сервер может обслуживать множество сайтов. Файлы, которые определяют какие именно, находятся в директории /etc/nginx/sites-available.

    Чтобы Nginx работал с сайтами, их необходимо слинковать с /etc/nginx/sites-enabled.

    Использования метода линкования позволяет быстро запускать сайты, не удаляя никакие файлы после их использования. Помимо этого, можно просто скопировать файлы прямо в первую директорию.

    Символьная ссылка — это путь к файлу. Общий синтаксис для неё выглядит так:

    Примеры ссылок для каталога и файла:

    • ln -s /usr/share/nginx/html/index.php /home/dmosk/ ;
    • ln -s /usr/share/nginx/html /home/dmosk/ .

    Директория sites-available содержит конфигурацию виртуальных хостов. Это позволяет веб-серверу настраиваться для множества сайтов с разной конфигурацией. Сайты в этой директории не задействуются и будут обслуживаться только, если сделать символьную ссылку на папку sites-enabled.

    Настройка конфигурации

    Root-каталог Nginx по умолчанию находится в директории /usr/share/nginx/html. Все файлы, которые размещаются в нем, автоматически обслуживаются веб-сервером. Место определяется файлом конфигурации, который можно найти в /etc/nginx/conf.d/default.conf.

    Новые блоки server создаются через конфигурационные файлы в /etc/nginx/conf.d. Они буду загружаться при запуске Nginx, если заканчиваются на .conf.

    Основной конфигурационный файл сервера находится в /etc/nginx/nginx.conf. Через него изменяются любые настройки.

    Запуск

    После настройки конфигурации, можно Nginx запустить с помощью команды sudo service nginx start .

    Любое изменение необходимо подтверждать перезагрузкой через service nginx reload . Проверка статуса осуществляется через команду service nginx status .

    Установка Nginx на CentOS

    Рассмотрим практически установку Nginx на Linux, взяв за основу один из самых популярных дистрибутивов данной операционной системы – CentOS.

    1. Добавляем yum-репозиторий Nginx на ОС с помощью команды:
    2. Для установки используем команду sudo yum install nginx . Подтверждаем появившееся извещение.
    3. Для запуска сервера используем команду:
    4. Проверить, успешна ли установка, можно, посетив общественный IP-адрес сервера. Узнать его можно через команду:
    5. Чтобы Nginx автоматически запускался при загрузке ОС, вводим:

    Заключение

    Nginx представляет собой практически готовое решение для множества задач, требующих развёртывания полноценного веб-сервера или прокси. По ряду параметров Nginx превосходит своего «старшего коллегу» Apache. Главные из них — отсутствие требовательности к ресурсам и способность обрабатывать большое число соединений одновременно.

    Понимание работы и принципа обработки запросов в Nginx позволяет грамотно масштабировать и балансировать нагрузку на современных сайтах, располагающих контентом разных категорий. А связка Nginx и Apache позволяет максимально расширить эффективность применения веб-сервера.

    Чтобы Nginx, Apache и другой сложный «софт» работал, как швейцарские часы, разверните их на виртуальном сервере от Eternalhost! Это мощный и надёжный инструмент для самых неординарных задач в области IT.

    Nginx: проверяем несколько условий

    Конфигурация Nginx и подводные камни

    • Root внутри блока Location
    • Повторяющиеся директивы Index
    • Ипсользование условия If — зло.
    • Server Name
    • Проверка что файл cуществует
    • Шаблон Front Controller и CMS движки, которые его используют
    • Перенаправление всех запросов в PHP
    • FastCGI путь в SCRIPT_FILENAME
    • Проверяем rewrite’ы
    • Перепрописываем пропущенные http://
    • Проксируем все подряд
    • Изменения в конфиге не работают
    • Пропущенные или пропавшие HTTP заголовки

    Не важно новичок вы или опытный профессионал в настройке nginx, рано или позно вы можете столкнутся с непонятными проблемами при написании конфигов. Это подводные камни конфигурции nginx и от них никуда не уйти. Далее в этой статье мы рассмотрим эти ситуации и способы их обхода.

    В интернете полно некорректных, зачастую неправильных, инструкций по настройке сервера nginx. Нельзя им слепо следовать не понимая, что делает та или иная директива. Множество инструкций и примеров конфигураций просто ужасны, написаны на коленки и не читабельны. Эта статья была написана как ответ на такие инструкции, которые направляют новичков по ложному пути, запутывая их окончательно и заставля задавать одни и теже вопросы на форумах и IRC каналах.

    Root внутри блока Location

    ПЛОХО:


    Это работает. Помещать директиву root внутри блока location это нормально и правильно. Что не правильно в данном случае, дак это то, что директива root повторяется в каждом блоке location , следовательно, если ни один из локейшенов не сработает, то у нас директива root вообще не будет задана.

    Правильным решение является вынос директивы root из блоков location в начало блока server . Ниже приведен пример как надо делать правильно:

    ХОРОШО:

    Повторяющиеся директивы Index

    ПЛОХО:

    Зачем повторять столько строчек кода. Просто используйте директиву index один раз. Ее необходимо задать всего один раз внутри блока http и она будет наследоваться всеми вложенными блоками.

    ХОРОШО:

    Ипсользование условий If — зло.

    Есть небольшая статья по применению условного оператора if , описывающая почему использование if крайне не рекомендуется. Статья называется if — это Зло. . Очень рекомендуем прочитать вам эту статью, и посмотреть на примерах почему оператор if это зло.

    ПЛОХО:

    На самом деле здесь несколько проблемных моментов. Первое это if (смотрим статью if — это Зло. ). Когда nginx получает запрос, не важно в какой поддомен он направлен, будь это www.domain.com или domain.com , условие if всегда сработает. В примере получается, что мы указываем, чтобы nginx проверял заголовок хоста (встроенную переменную $host ) при каждом запросе. Это крайне не эффективно. Вы должны избегать этого. Вместо неудачного условия if лучше использовать два блока с директивой server , как в примере ниже.

    ХОРОШО:

    В итоге мы получили читабельный конфиг. Так же, мы уменьшили затраты ресурсов nginx на обработку запросов. A еще мы избавились от условия if и использовали свтроенную переменную $scheme , которая позволяет не привязывать URI к определенному протоколу, будь то http или https .

    Проверка что файл cуществует

    Использовать if для проверки наличия файла это просто ужасно. В nginx для этого есть специальная директива try_files , которая делает жизнь на много проще.

    ПЛОХО:

    ХОРОШО:

    Использование директивы try_files подразумевает, что вы можете тестировать не одно условие, а последовательность (цепочку) из нескольких условий. Например, в данном примере проверяется существует-ли файл по указанному $uri , если файл не найден, то проверяется существует-ли директория $uri/ , если и ее нет, то проверка идет дальше по цепочке. Если ниодно условие так и не стработало, то по-умолчанию, nginx выполнит последнее условие в цепочке (в данном случае это /index.html ). Вот еще один повод, чтобы избавиться от использования директивы if .

    Шаблон Front Controller и CMS движки, которые его используют

    Шаблон Front Controller сейчас очень популярен и используется во многих CMS движках и современных фреймворках на PHP. Далее показан простой пример, применимый для CMS Drupal, Joomla и др.:

    ВНИМАНИЕ Названия параметров могут отличаться для разных CMS. Например:

    • q — используется в Drupal, Joomla, WordPress
    • page — используется в CMS Made Simple

    Некоторым движкам вообще не нужны параметры и они вытаскивают всю необходимую информацию из строки запроса REQUEST_URI (например WordPress):

    Конечно, эти параметры для других CMS и фреймворков могут отличаться, здесь приведен лишь общий пример. В некоторых ситуациях вам понадобится более комплексное решение, пробуйте и экспериментируйте.

    Также вы можете вообще убрать проверку на наличие директории $uri/ , если вам эта проверка не нужна.

    Перенаправление всех запросов в PHP

    Многие примеры конфигурации nginx рекомендуют все запросы оканчивающиеся на .php перенаправлять (проксировать) в интерпретатор PHP. Но это, вообще-то, потенциальная угроза безопасности на множестве конфигураций PHP, которая может привести к выполнению вредоносного кода на сервере.

    Проблемная секция обычно выглядит так:

    Здесь каждый запрос оканчивающийся на .php перенаправляется в бекэнд на FastCGI. Угроза безопасности здесь в том, что конфигурация PHP по-умолчанию всегда пытается выяснить какой файл вы хотите выполнить, даже если запрос идет на не существующий файл.

    Например, вот запрос к файлу /forum/avatar/1232.jpg/file.php которого на самом деле нет на сервере, но зато на сервере есть файл /forum/avatar/1232.jpg . В данном случае по-умолчанию PHP обработает этот файл /forum/avatar/1232.jpg . А теперь представьте, что в этом файле содержится вредоносный код для PHP? Соответсвенно он будет выполнен!

    Чтобы это исключить, необходимо:

    • Установить директиву cgi.fix_pathinfo=0 в php.ini. Это заставит интерпретатор PHP остановиться на выполнении первого запроса и при отсутствии запрашиваемого ресурса не идти далее по цепочке.
    • Убедится что nginx отправляет в PHP на обработку только определенные файлы, расчитанные на такую обработку. А не все подряд:
    • запретить обработку интерпретатором PHP всех файлов из директории куда пользователи загружают свои файлы:
    • Использовать директиву try_files чтобы отбросить запросы на не существующие файлы:
    • Использовать вложенные секции location , чтобы исключить проблемные условия:

    FastCGI путь в SCRIPT_FILENAME

    Во многих руководствах по настройке nginx используются абсолютные пути для указания корневой директории сайта. Это частая практика в PHP блоках конфигурации nginx. Но в подключаемых конфигах для настройки парметров FastCGI include fastcgi_params; этого делать не стоит, для этого есть встроенная переменная $document_root .

    ПЛОХО:

    ХОРОШО:

    Вы спросите, где задается переменная $document_root ? Она задается директивой root , которая должна присутствовать в блоке server . И если в вашем конфиге ее там нет, тогда вы наткнулись на первый подводный камень описанный нами в начале этой статьи: Root внутри блока Location , исправляйте ваш конфиг =)

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

    ПЛОХО:


    ХОРОШО:

    ЕЩЕ ЛУЧШЕ:

    Посмотрети, на первый вариант, потом на последний, потом опять на первый и опять на последний. Ну что? Первый реврайт запоминает полный путь без учета начального слеша и затем помещает этот путь вместо плейсхолдера $1 . Однако используя встроенную переменную $request_uri мы спокойно можем избавится от всей этой магии с регулярными выражениями.

    Перепрописываем пропущенные http://

    Все очень просто. Реврайты — относительны, даже если вы указываете nginx обратное. Чтобы сделать реврайты абсолютными, просто добавьте схему протокола http:// в начало адреса. Смотрим пример:

    BAD:

    ХОРОШО:

    В примере выше мы просто добавили в реврайт http://. Это очень просто и эффективно.

    Проксируем все подряд

    ПЛОХО:

    FFFUUU. В этом примере мы перенаправляем ВСЕ ПОДРЯД. в PHP. Зачем? Для Apache это простительно, но вам нет. Директива try_files придумана не просто так, она проверяет наличие запрашиваемого ресурса (файла) в определнной последовательности. Это значит, что nginx может проверить первое условие, потом второе и т.д. пока по цепочке не дойдет до конца. И если ничего не сработало, то по-умолчанию выполнится последннее условие в цепочке проверок. А это значит, что интерепретатор PHP будет вызываться не каждый раз, а только тогда, кода это действительно необходимо. Обработка запросов при этом ускорится многократно!

    Представьте, что идет несколько однотипных запросов на получение файла картинки размеров 1Мб и в примере выше каждый такой запрос будет перенаправлен в PHP.

    Ниже показано как избавиться от этого безобразия:

    ХОРОШО:

    ТОЖЕ ХОРОШО:

    Просто, не правда-ли? Мы видим что, если запрашиваемый URI существует, то он будет отработан nginx. Если нет, то проверяется существует ли вообще такая директория $uri/ . Если нет, то уже тогда, по-умолчанию, запрос будет направлен в /index.php и обработан PHP.

    Теперь представьте сколько на вашем сайте статического контента (картинок, css-стилей, js-скриптов и т.д.), сколько лишних запросов вы отсекли от обработки через PHP?

    Изменения в конфиге не работают

    Браузер кеширует запросы! Ваша конфигурация может быть идельной и без единой ошибки, но вы по-прежнему бъетесь головой об стену и пытаетесь понять почему у вас ничего не работает? Что не так? Ответ на этот вопрос: кеш браузера. Когда вы загружаете что-либо, браузер сохраняет это в своем кеше. Он также сохраняет то, как был обработан скачанный файл. Если вы в конфигурации nginx играетесь с блоками <> , скорее всего вы столкнетесь с проблемами кеширования запросов браузером.

    • [Вариант 1] в Firefox нажмите Ctrl+Shift+Delete, проерьте кешь, нажмите кнопку Очистить. Если у вас другой браузер, то погуглите как очищается кеш в нем.
    • [Варинт 2] Используйте для тестирования curl.

    Если действия выше не помогают, и вы запускаете nginx на виртуальной машине, причина может быть в sendfile . Просто закомментируйте директиву или установите ее в значение в off . Эта директива может располагаться где-то в вашем конфиге nginx в файле nginx.conf :

    Пропущенные или пропавшие HTTP заголовки

    Если вы явно не задали директиву underscores_in_headers в значение on , то nginx по-умолчанию будет тихо и незаметно пропускать HTTP заголовки, содержащие символы нижнего подчеркивания (которые на самом деле, с точки зрения описания протокола HTTP, вполне допустимы). Nginx делает это только для исключения неоднозначности при маппинге заголовков в переменные при передаче в CGI скрипты, и преобразует символы — и _ в символы нижнего подчеркивания _ .

    Более подробно на эту тему смотрите в официальной документации по nginx.

    Nginx. Не срабатывает условие в фигурных скобках регулярного выражения

    Всем привет! Что-то замаялся я…

    Пишу в location / вот такое условие:

    * «/products/detail.php\? > <
    access_log /var/log/nginx.error_log;
    return 403;
    >

    После чего, nginx начинает блокировать и запросы вида:

    /products/detail.php? >
    То есть, не работает условие «если символов после = больше или равно 7».

    • Вопрос задан более трёх лет назад
    • 4585 просмотров

    Всё, уже сам нашел решение:

    нужно было использовать $request_uri

    Спасибо. Такой вариант почему-то не получилось сделать рабочим и я сделал так:

    в «location /» прописал:
    # Block product page hacking

    * ‘/products/detail.php\? > <
    set $id $1;
    >

    if ($block = ‘yes’)
    <
    access_log /var/log/nginx.error_log;
    return 403;
    >
    # end of Block product page hacking

    Минимальный работающий пример. Он требует адаптации под ваши условия.

    А я свой пример упростил до двух «if»:

    * ‘/products/detail.php\? > <
    set $id $1;
    >

    * ‘^\d+$’)
    <
    access_log /var/log/nginx.error_log;
    return 403;
    >

    А вот более правильный код, который будет работать даже если есть и другие параметры помимо ID:

    * ‘/products/detail.php\? > <
    set $id $arg_id;
    >
    if ($id !

    * ‘^\d+$’)
    <
    access_log /var/log/nginx.error_log;
    return 403;
    >


    Вышел казус: года 3 на сайте этом не было в данном скрипте никаких параметров GET кроме ID, а стоило мне написать такую регулярку для nginx, как на следующий день в обновлении программисты добавили еще один параметр. 🙂

    Полный тюнинг движка: Делаем из nginx непробиваемый Web-сервер

    Содержание статьи

    Выделенный Web-сервер на основе nginx – отличный способ повышения производительности Web-сайтов. В скорости обработки статического контента ему просто нет равных: он легко выдерживает несколько тысяч одновременных соединений и может быть легко оптимизирован и подогнан под любую конфигурацию. Однако? выступая в качестве фронт-энда для Apache, nginx оказывается наиболее уязвимым местом всей Web-инфраструктуры, поэтому безопасности nginx необходимо уделить особое внимание.

    Эта статья – своего рода ликбез, или, если хочешь, резюме всех техник повышения безопасности nginx. В ней не будет теории, описания основ настройки Web-сервера и прочей воды. Вместо этого ты получишь исчерпывающий практический материал, описывающий все основные шаги, которые необходимо проделать для того, чтобы получить по-настоящему защищенный Web-сервер.

    Установка

    Пакет nginx доступен в прекомпилированном виде для любого дистрибутива. Однако собрав сервер самостоятельно, ты сможешь сделать его более компактным и надежным, а также получишь возможность изменить строку приветствия Web-сервера, чтобы отбить несмышленых скрипт-кидди.

    Измени строку приветствия Web-сервера

    Скачай исходники nginx, открой файл src/http/ngx_http_header_filter_module.c и найди следующие две строки:

    static char ngx_http_server_string[] = «Server: nginx» CRLF;
    static char ngx_http_server_full_string[] = «Server: » NGINX_VER CRLF;

    Замени их на что-то вроде этого:

    static char ngx_http_server_string[] = «Server: ][ Web Server» CRLF;
    static char ngx_http_server_full_string[] = «Server: ][ Web Server» CRLF;

    Удали все неиспользуемые тобой nginx-модули

    Некоторая часть модулей nginx подключается к Web-серверу прямо во время компиляции, и любой из них таит в себе потенциальную опасность. Возможно, в будущем в одном из них будет найдена уязвимость, и твой сервер окажется под угрозой. Отключив ненужные модули, ты сможешь значительно снизить риск возникновения такой ситуации.

    Выполни сборку с помощью следующих команд:

    # ./configure —without-http_autoindex_module —without-http_ssi_module
    # make
    # make install

    Так ты получишь nginx с заранее отключенными (и в большинстве случаев бесполезными) модулями SSI (Server Side Includes) и Autoindex. Чтобы узнать, какие модули можно безболезненно выбросить из Web-сервера, запусти скрипт configure с флагом ‘—help’.

    Препарируем nginx.conf

    После установки nginx следует настроить. На страницах журнала уже был материал, описывающий этот процесс, мы же будем придерживаться темы статьи и поговорим о способах повышения безопасности сервера.

    Отключи показ версии сервера на всех ошибочных страницах

    Добавь в файл nginx.conf строку «server_tokens off». Это заставит nginx скрывать информацию о типе и версии Web-сервера на страницах, генерируемых в ответ на ошибочный запрос клиента.

    Настрой защиту от срыва стека

    Добавь в секцию server следующие строки:

    # Максимальный размер буфера для хранения тела запроса клиента
    client_body_buffer_size 1K;
    # Максимальный размер буфера для хранения заголовков запроса клиента
    client_header_buffer_size 1k;
    # Максимальный размер тела запроса клиента, прописанный в поле Content-Length заголовка. Если сервер должен поддерживать загрузку файлов, это значение необходимо увеличить
    client_max_body_size 1k;
    # Количество и размер буферов для чтения большого заголовка запроса клиента
    large_client_header_buffers 2 1k;

    Обрати внимание на директиву large_client_header_buffers. По умолчанию, для хранения строки URI nginx выделяет четыре буфера, размер каждого из которых равен размеру страницы памяти (для x86 это 4 Кб). Буферы освобождаются каждый раз, когда по окончанию обработки запроса соединение переходит в состояние keep-alive. Два буфера по 1 Кб могут хранить URI длиной только 2 Кб, что позволяет бороться с ботами и DoS-атаками.

    Для повышения производительности добавь следующие строки:

    # Таймаут при чтении тела запроса клиента
    client_body_timeout 10;
    # Таймаут при чтении заголовка запроса клиента
    client_header_timeout 10;
    # Таймаут, по истечению которого keep-alive соединение с клиентом не будет закрыто со стороны сервера
    keepalive_timeout 5 5;
    # Таймаут при передаче ответа клиенту
    send_timeout 10;

    Контролируй количество одновременных соединений

    Для защиты Web-сервера от перегрузки и попыток осуществить DoS-атаку добавь в конфиг следующие строки:

    # Описываем зону (slimits), в которой будут храниться состояния сессий. Зона размером 1 Мб может хранить около 32000 состояний, мы устанавливаем ее размер равным 5 Мб
    limit_zone slimits $binary_remote_addr 5m;
    # Задаем максимальное количество одновременных соединений для одной сессии. По сути, это число задает максимальное количество соединений с одного IP
    limit_conn slimits 5;

    Первая директива должна находиться в секции HTTP, вторая – в секции location. Когда количество соединений выйдет за пределы лимитов, клиент получит сообщение «Service unavailable» с кодом 503.

    Разреши коннекты только к своему домену

    Взломщики могут использовать ботов для сканирования подсетей и поиска уязвимых Web-серверов. Обычно боты просто перебирают диапазоны IP-адресов в поисках открытых 80 портов и посылают запрос HEAD для получения информации о веб-сервере (или главной странице). Ты можешь легко предотвратить такой скан, запретив обращение к серверу по IP-адресу (добавить в подсекцию location):

    ^(host.com|www.host.com)$ ) <
    return 444;
    >

    Ограничь количество доступных методов обращения к Web-серверу

    Некоторые боты используют различные методы обращения к серверу для попытки определения его типа и/или проникновения, однако в документе RFC 2616 четко сказано, что Web-сервер не обязан реализовывать их все, и неподдерживаемые методы могут просто не обрабатываться. Сегодня используемыми остаются только методы GET (запрос документа), HEAD (запрос заголовков сервера) и POST (запрос на публикацию документа), поэтому все остальные можно безболезненно отключить с помощью помещения следующих строк в секцию server конфигурационного файла:

    Отшивай ботов

    Другой способ блокирования ботов, сканеров и прочей нечисти основан на определении типа клиента (user-agent). Он не слишком эффективен, потому как большинство ботов косят под вполне легитимные браузеры, но в ряде случаев остается полезным:

    # Блокируем менеджеры загрузки
    if ($http_user_agent

    * LWP::Simple|BBBike|wget) <
    return 403;
    >
    # Блокируем некоторые типы ботов
    if ($http_user_agent

    * msnbot|scrapbot) <
    return 403;
    >

    Блокируй Referrer-спам

    Если твой сайт публикует Web-логи в общедоступном виде, ты легко можешь стать жертвой Referrer-спама (когда спам-боты обращаются к твоему серверу, указывая в заголовке referrer – адрес рекламируемого сайта). Такой вид спама может легко испортить SEO-рейтинги интернет-страницы, поэтому его необходимо блокировать в обязательном порядке. Один из способов сделать это – занести наиболее частые слова, встречающиеся в адресах рекламируемых сайтов, в черный список.

    # Секция server
    if ( $http_referer

    * (babes|forsale|girl|jewelry|love|nudit|organic|poker|porn|sex|teen) )
    <
    return 403;
    >

    Блокируй хотлинк

    Хотлинк – это включение в страницу изображения (или иного контента) с другого сайта. По сути, это воровство, потому как изображение, на которое ты потратил не один час своего свободного времени, не только свободно используется другими, но и создает нагрузку на твой Web-сервер, не приводя на него посетителей. Для борьбы с хотлинками достаточно сделать так, чтобы изображения отдавались клиенту только в том случае, если он запросил их, уже находясь на сайте (другими словами, заголовок referrer-запроса должен содержать имя твоего сайта). Добавь в секцию server конфигурационного файла nginx.conf следующие строки (host.com – это адрес твоего сайта):

    location /images/ <
    valid_referers none blocked www.host.com host.com;
    if ($invalid_referer) <
    return 403;
    >
    >

    В качестве альтернативы ты можешь настроить сервер на отдачу специального баннера с сообщением о воровстве вместо запрашиваемого изображения. Для этого замени строку «return 403» на строку:

    rewrite ^/images/uploads.*\.(gif|jpg|jpeg|png)$ http://www.host.com/banned.jpg last

    Защищай важные каталоги от посторонних

    Как и любой другой Web-сервер, nginx позволяет регулировать доступ к каталогам на основе IP-адресов и паролей. Эту возможность можно использовать для закрытия некоторых частей сайта от посторонних глаз. Например, для отрезания URI от внешнего мира:

    location /uploads/ <
    # Разрешаем доступ только машинам локальной сети
    allow 192.168.1.0/24;
    # Отшиваем всех остальных
    deny all;
    >

    Теперь к документам каталога uploads будут иметь доступ только пользователи локальной сети. Для установки пароля придется проделать более сложные действия. Сначала необходимо создать приватный для nginx-файл паролей и добавить в него необходимых пользователей (в качестве примера добавим пользователя admin):

    # mkdir /etc/nginx/.htpasswd
    # htpasswd -c /etc/nginx/.htpasswd/passwd admin

    Далее открой файл nginx.conf и впиши в него следующие строки:

    location /admin/ <
    auth_basic «Restricted»;
    auth_basic_user_file /etc/nginx/.htpasswd/passwd;
    >

    Новых пользователей можно добавить с помощью следующей команды:

    # htpasswd -s /etc/nginx/.htpasswd/passwd пользователь

    Используй SSL

    Если твой сайт работает с приватными данными пользователей, такими как номера кредитных карт, пароли от других сервисов, или же предоставляет доступ к другой важной информации, которая может стать лакомым кусочком для третьих лиц, позаботься о шифровании. Nginx хорошо работает с SSL, и этой возможностью нельзя пренебрегать.

    Для настройки SSL-шифрования средствами nginx достаточно выполнить несколько простых шагов. Сначала ты должен создать сертификат с помощью следующей последовательности команд:

    # cd /etc/nginx
    # openssl genrsa -des3 -out server.key 1024
    # openssl req -new -key server.key -out server.csr
    # cp server.key server.key.org
    # openssl rsa -in server.key.org -out server.key
    # openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

    Затем описать сертификат в конфигурационном файле nginx:

    server <
    server_name host.com;
    listen 443;
    ssl on;
    ssl_certificate /etc/nginx/server.crt;
    ssl_certificate_key /etc/nginx/server.key;
    access_log /etc/nginx/logs/ssl.access.log;
    error_log /etc/nginx/logs/ssl.error.log;
    >

    После этого можно перезагрузить Web-сервер:

    Естественно, без поддержки со стороны самого Web-сайта это делать бессмысленно.

    Другие способы

    Установи правильные значения системных переменных

    Открой файл /etc/sysctl.conf и помести в него следующие строки:

    # Защита от smurf-атак
    net.ipv4.icmp_echo_ignore_broadcasts = 1
    # Защита от неправильных ICMP-сообщений
    net.ipv4.icmp_ignore_bogus_error_responses = 1
    # Защита от SYN-флуда
    net.ipv4.tcp_syncookies = 1
    # Запрещаем маршрутизацию от источника
    net.ipv4.conf.all.accept_source_route = 0
    net.ipv4.conf.default.accept_source_route = 0
    # Защита от спуфинга
    net.ipv4.conf.all.rp_filter = 1
    net.ipv4.conf.default.rp_filter = 1
    # Мы не маршрутизатор
    net.ipv4.ip_forward = 0
    net.ipv4.conf.all.send_redirects = 0
    net.ipv4.conf.default.send_redirects = 0
    # Включаем ExecShield
    kernel.exec-shield = 1
    kernel.randomize_va_space = 1
    # Расширяем диапазон доступных портов
    net.ipv4.ip_local_port_range = 2000 65000
    # Увеличиваем максимальный размер TCP-буферов
    net.ipv4.tcp_rmem = 4096 87380 8388608
    net.ipv4.tcp_wmem = 4096 87380 8388608
    net.core.rmem_max = 8388608
    net.core.wmem_max = 8388608
    net.core.netdev_max_backlog = 5000
    net.ipv4.tcp_window_scaling = 1

    Размести корневой каталог Web-сервера на выделенном разделе

    Поместив корневой каталог Web-сервера в выделенный раздел и запретив на нем размещение любых исполняемых файлов и файлов-устройств, ты обезопасишь остальную часть системы от тех, кто сможет получить доступ к корню Web-сервера. При этом запись в файле /etc/fstab должна иметь примерно такой вид:

    /dev/sda5 /nginx ext4 defaults,nosuid,noexec,nodev 1 2

    Помести nginx в chroot/jail-окружение

    Любая современная *nix-система позволяет запереть приложение в изолированной среде исполнения. В Linux для этого можно использовать технологии KVM, Xen, OpenVZ и VServer, во FreeBSD – Jail, в Solaris – Zones. Если ни одна из этих технологий не доступна, ты можешь поместить nginx в классический chroot, который хоть и намного более хрупок, но большинство взломщиков остановить сможет.

    Установи правила SELinux для защиты nginx

    Хорошей альтернативой изолированным средам исполнения являются локальные системы обнаружения и предотвращения вторжений, такие как SELinux или AppArmor. Будучи правильно настроенными, они смогут предотвратить попытки взлома Web-сервера. По дефолту ни одна из них не настроена для работы в связке с nginx, однако в рамках проекта SELinuxNginx (http://sf.net/projects/selinuxnginx/) были созданы правила для SELinux, которые может использовать любой желающий. Остается только скачать и установить:

    # tar -zxvf se-ngix_1_0_10.tar.gz
    # cd se-ngix_1_0_10/nginx
    # make
    # /usr/sbin/semodule -i nginx.pp

    Настрой брандмауэр

    Обычно nginx устанавливают на выделенных машинах, готовых к высокой нагрузке, поэтому зачастую он остается единственным сетевым сервисом, работающим на сервере. Чтобы обезопасить сервер, достаточно создать совсем небольшой набор правил, которые будут открывать 80, 110 и 143-й порты (если, конечно, nginx должен работать еще и как IMAP/POP3-прокси) и закрывать от внешнего мира все остальное.

    Ограничь количество соединений с помощью брандмауэра

    Для не слишком нагруженного Web-сайта хорошей идеей будет ограничить количество попыток соединений с одного IP-адреса в минуту. Это сможет уберечь тебя от некоторых типов DoS-атак и брутфорса. В Linux это можно сделать с помощью стандартного iptables/netfilter-модуля state:

    # iptables -A INPUT -p tcp —dport 80 -i eth0 \
    -m state —state NEW -m recent —set
    # iptables -A INPUT -p tcp —dport 80 -i eth0 \
    -m state —state NEW -m recent —update \
    —seconds 60 —hitcount 15 -j DROP

    Правила урезают лимит на количество подключений с одного IP в минуту до 15. То же можно сделать и с помощью pf:

    Кроме лимита на количество последовательных подключений (15 в минуту), данное правило устанавливает дополнительный лимит на количество одновременных подключений равный 100.

    Настрой PHP

    Если ты используешь nginx в связке с PHP, не забудь настроить и его. Вот как должен выглядеть конфигурационный файл /etc/php/php.ini защищенного сервера:

    # Отключаем опасные функции
    disable_functions = phpinfo, system, mail, exec
    # Максимальное время исполнения скрипта
    max_execution_time = 30
    # Максимальное время, которое может потратить скрипт на обработку данных запроса
    max_input_time = 60
    # Максимальное количество памяти, выделяемое каждому скрипту
    memory_limit = 8M
    # Максимальный размер данных, отсылаемых скрипту с помощью метода POST
    post_max_size = 8M
    # Максимальный размер загружаемых файлов
    upload_max_filesize = 2M
    # Не показывать ошибки PHP-скриптов пользователям
    display_errors = Off
    # Включаем Safe Mode
    safe_mode = On
    # Включаем SQL Safe Mode
    sql.safe_mode = On
    # Позволяем выполнять внешние команды только в этом каталоге
    safe_mode_exec_dir = /путь/к/защищенному/каталогу
    # Защищаемся от утечки информации о PHP
    expose_php = Off
    # Ведем логи
    log_errors = On
    # Запрещаем открытие удаленных файлов
    allow_url_fopen = Off

    Выводы

    Применив описанные в статье рекомендации, ты получишь гораздо более защищенный Web-сервер. Но имей в виду, что не все техники подойдут к твоей конфигурации. Например, защита от брутфорса, основанная на урезании размеров буферов, выделяемых nginx под обработку запросов клиентов, может привести к падению производительности, а в некоторых случаях и к сбоям в обработке запросов. Ограничение на количество подключений нанесет сильный удар по производительности даже средненагруженного Web-сайта, но принесет пользу, если страница имеет низкий поток посетителей. Всегда проверяй, как внесенные тобой изменения повлияли на производительность и общую работоспособность Web-страницы.

    Nginx несколько условий карты для одной переменной

    Я пытаюсь исключить как IP-адрес, так и агент пользователя из любого из журналов моего vhost. Каждый vhost имеет свой собственный файл журнала, настроенный в соответствующем файле. Я приложил $if=$variable к каждому описанию файла журнала и добавил его в nginx.conf:

    Это работает. Теперь я хочу добавить условия, например. IP-адрес этой переменной (без необходимости изменения каждой конфигурации одного vhost снова).

    Если это можно настроить глобально, сохраняя при этом различные местоположения лог-файлов, которые также были бы приемлемым решением.

    Nginx.conf перенаправляет несколько условий

    Я хочу перенаправить запросы на два условия, используя nginx.

    Это не работает:

    Каков правильный способ сделать это?

    У меня была такая же проблема раньше. Поскольку nginx не может выполнять сложные условия или вложенные операторы if, вам необходимо оценить более двух разных выражений.

    установите переменную в какое-то двоичное значение, затем включите, если любое условие истинно в двух разных операторах if:

    Правильный способ — использовать выделенный сервер для перенаправления:

    Мастер Йода рекомендует:  Как оптимизировать контент под Google Discover (и почему это важно)
    Добавить комментарий