- Как предотвратить обработку запросов без имени сервера
- Определение виртуального сервера по имени и IP-адресу
- Конфигурация простого сайта PHP
- Nginx index php file
- Root внутри секции location
- Несколько директив index
- Использование if
- Имя сервера
- Проверка наличия файла
- Передача запросов на PHP
- Путь FastCGI
- Перезапись (rewrite)
- Отсутствующий http://
- Проксирование
- Самое главное
nginx вначале решает, какой из серверов должен обработать запрос. Рассмотрим простую конфигурацию, где все три виртуальных сервера слушают на порту *:80:
В этой конфигурации, чтобы определить, какому серверу следует направить запрос, nginx проверяет только поле “Host” заголовка запроса. Если его значение не соответствует ни одному из имён серверов или в заголовке запроса нет этого поля вовсе, nginx направит запрос в сервер по умолчанию для этого порта. В вышеприведённой конфигурации сервером по умолчанию будет первый сервер, что соответствует стандартному поведению nginx по умолчанию. Сервер по умолчанию можно задать явно с помощью параметра default_server в директиве listen:
Параметр default_server появился в версии 0.8.21. В более ранних версиях вместо него следует использовать параметр default .
Следует иметь в виду, что сервер по умолчанию является свойством слушающего порта, а не имени сервера. Подробнее это обсуждается ниже.
Как предотвратить обработку запросов без имени сервера
Если запросы без поля “Host” в заголовке не должны обрабатываться, можно определить сервер, который будет их отклонять:
Здесь в качестве имени сервера указана пустая строка, которая соответствует запросам без поля “Host” в заголовке, и возвращается специальный для nginx код 444, который закрывает соединение.
Начиная с версии 0.8.48 настройка server_name «» является стандартной и может явно не указываться. В более ранних версиях в качестве стандартного имени сервера выступало имя машины (hostname).
Определение виртуального сервера по имени и IP-адресу
Рассмотрим более сложную конфигурацию, в которой некоторые виртуальные серверы слушают на разных адресах:
В этой конфигурации nginx вначале сопоставляет IP-адрес и порт запроса с директивами listen в блоках server. Затем он сопоставляет значение поля “Host” заголовка запроса с директивами server_name в блоках server, которые соответствуют IP-адресу и порту. Если имя сервера не найдено, запрос будет обработан в сервере по умолчанию. Например, запрос www.example.com , пришедший на порт 192.168.1.1:80, будет обработан сервером по умолчанию для порта 192.168.1.1:80, т.е. первым сервером, т.к. для этого порта www.example.com не указан в списке имён серверов.
Как уже говорилось, сервер по умолчанию является свойством слушающего порта, поэтому у разных портов могут быть определены свои серверы по умолчанию:
Конфигурация простого сайта PHP
Теперь посмотрим на то, как nginx выбирает location для обработки запроса на примере обычного простого PHP-сайта:
server < listen 80; server_name example.org www.example.org; root /data/www; location / < index index.html index.php; >location ~* \.(gif|jpg|png)$ < expires 30d; >location ~ \.php$ < fastcgi_pass localhost:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; >>
nginx вначале ищет среди всех префиксных location’ов, заданных строками, максимально совпадающий. В вышеприведённой конфигурации указан только один префиксный location “ / ”, и поскольку он подходит под любой запрос, он и будет использован, если других совпадений не будет найдено. Затем nginx проверяет location’ы, заданные регулярными выражениями, в порядке их следования в конфигурационном файле. При первом же совпадении поиск прекращается и nginx использует совпавший location. Если запросу не соответствует ни одно из регулярных выражений, nginx использует максимально совпавший префиксный location, найденный ранее.
Следует иметь в виду, что location’ы всех типов сопоставляются только с URI-частью строки запроса без аргументов. Так делается потому, что аргументы в строке запроса могут быть заданы различными способами, например:
/index.php?user=john&page=1 /index.php?page=1&user=john
Кроме того, в строке запроса можно запросить что угодно:
/index.php?page=1&something+else&user=john
Теперь посмотрим, как бы обрабатывались запросы в вышеприведённой конфигурации:
- Запросу “ /logo.gif ” во-первых соответствует префиксный location “ / ”, а во-вторых — регулярное выражение “ \.(gif|jpg|png)$ ”, поэтому он обрабатывается location’ом регулярного выражения. Согласно директиве “ root /data/www ” запрос отображается в файл /data/www/logo.gif , который и посылается клиенту.
- Запросу “ /index.php ” также во-первых соответствует префиксный location “ / ”, а во-вторых — регулярное выражение “ \.(php)$ ”. Следовательно, он обрабатывается location’ом регулярного выражения и запрос передаётся FastCGI-серверу, слушающему на localhost:9000. Директива fastcgi_param устанавливает FastCGI-параметр SCRIPT_FILENAME в “ /data/www/index.php ”, и сервер FastCGI выполняет указанный файл. Переменная $document_root равна значению директивы root, а переменная $fastcgi_script_name равна URI запроса, т.е. “ /index.php ”.
- Запросу “ /about.html ” соответствует только префиксный location “ / ”, поэтому запрос обрабатывается в нём. Согласно директиве “ root /data/www ” запрос отображается в файл /data/www/about.html , который и посылается клиенту.
- Обработка запроса “ / ” более сложная. Ему соответствует только префиксный location “ / ”, поэтому запрос обрабатывается в нём. Затем директива index проверяет существование индексных файлов согласно своих параметров и директиве “ root /data/www ”. Если файл /data/www/index.html не существует, а файл /data/www/index.php существует, то директива делает внутреннее перенаправление на “ /index.php ” и nginx снова сопоставляет его с location’ами, как если бы такой запрос был послан клиентом. Как мы видели ранее, перенаправленный запрос будет в конечном итоге обработан сервером FastCGI.
автор: Игорь Сысоев редактор: Brian Mercer |
Nginx index php file
Наткнуться на подводные камни в конфигурации и работе веб-сервера очень легко. Но трудно понять причину некорректной или не всегда корректной/ошибочной работы, если все правила соблюдаются.
Root внутри секции location
Нет ничего плохого в размещении root-директории внутри location. Но если location не соответствует, то у нее не будет доступа к корневому каталогу. Правильнее делать так:
server < server_name www.somesite.com; root /var/www/nginx-default/; location / < # [. ] > location /foo < # [. ] > location /bar < # [. ] > >
# Указание root внутри секции server
Несколько директив index
Не нужно плодить большое количество директив index. Пропишите ее один раз в блоке http :
http < index index.php index.htm index.html; server < server_name www.somesite.com; location / < # [. ] > > server < server_name somesite.com; location / < # [. ] > location /foo < # [. ] > > >
# Index будет автоматически наследоваться в всех секциях
Использование if
Вы же в курсе, что if = зло? При использовании директивы нужно быть осторожным, ошибиться несложно. Так что по возможности избегайте использования if.
Имя сервера
Предположим, ваш сайт лежит на домене somesite.com и вы перенаправляете на него пользователей, которые идут на www.somesite.com:
# Проверяет и перенаправляет хост
Здесь несколько проблем. Главная — if. Вне зависимости от запроса хоста (с www или без), Nginx все равно проверяет if. Для каждого запроса. Взамен можно сделать так:
# Используется $scheme, которая подходит для http и https
Проверка наличия файла
Не используйте if для проверки наличия файла:
# Подход как минимум не эффективен
Взамен у Nginx есть директива try_files :
# Проверка последовательности на наличие файла, если не существует, то отправляет на index.html
Примечательно, что директиву также можно использовать для защиты веб-сервера от несанкционированного доступа.
Передача запросов на PHP
Если Nginx перенаправляет все запросы, заканчивающиеся на .php , напрямую на интерпретатор PHP, то для злоумышленников открываются возможности для выполнения стороннего кода. PHP по умолчанию пытается догадаться, куда должен вести неправильный запрос. Так что в первую очередь необходимо подправить php.ini , указав:
# Интерпретатор будет обрабатывать только корректные запросы
Обратите внимание на правильную конфигурацию Nginx:
# Перенаправляет запросы только для указанных файлов location ~* (file_a|file_b|file_c)\.php$ < fastcgi_pass backend; # [. ] > # Отключить выполнение скриптов в пользовательских загрузках location /uploaddir < location ~ \.php$ # [. ] > # Фильтрация при помощи try_files location ~* \.php$ < try_files $uri =404; fastcgi_pass backend; # [. ] > # Использует вложенное расположение для фильтрации location ~* \.php$ < location ~ \..*/.*\.php$ fastcgi_pass backend; # [. ] >
# Параметры можно комбинировать
Путь FastCGI
Неправильное указание путей размещения скриптов FastCGI часть приводит к ошибке “Primary script unknown”, которая легко решается.
Перезапись (rewrite)
Используйте переменную $request_uri для изменения URI запроса:
rewrite ^ http://somesite.com$request_uri? permanent; # Или так return 301 http://somesite.com$request_uri;
# Перенаправляет на страницу 301
Отсутствующий http://
Добавить отсутствующий http:// очень просто:
rewrite ^ http://somesite.com permanent;
# Автоматически дополняет запрос
Проксирование
Не перенаправляйте все запросы на PHP в таком виде:
# Передает все на phpcgi.socket
Используйте все те же директиву try_files :
# Передает только нужные запросы на proxy
# Если Nginx не может обработать запрашиваемый URI самостоятельно, то проверяет директории на наличие, затем передает на proxy
Самое главное
Основная причина ошибочной работы системы (не только Nginx) — бездумный копипаст. Проверяйте конфиги, тестируйте приложение перед выкаткой, читайте документацию.