X-Accel-Redirect, похоже, не соблюдает правила и прецеденты конфигурации блоков nginx.
рассмотрим этот пример:
server {
...
limit_conn limitedIP 10;
location ^~ /files/ {
internal
alias /var/www/files/;
limit_conn limitedIP 20;
}
location ~ \.php$ {
...
limit_conn limitedIP 30;
}
}
Если я обращаюсь к / файлам напрямую (при удалении внутреннего курса), используется правило limit_conn 20, что нормально.
но если я использую X-Accel-Redirect в php-скрипте для / files, то используется правило limit_conn 30. даже если я удаляю эту строку из блока местоположения php, используется правило limit_conn 10 из блока сервера, что очень странно. наконец, если я удаляю limit_conn 10 из серверного блока, используется правило limit_conn 20, которое я ожидал сначала.
Я проверил это на nginx версии 1.6.2.
limit_conn — просто пример, и несколько директив ведут себя так. есть идеи?
Так работают модули limit_conn и limit_req. Эти модули имеют дело с соединениями между пользователями и сервером, и поскольку внутренние перенаправления не открывают какие-либо новые такие соединения, Nginx проверяет ограничения только один раз на запрос и не считает необходимым проверять их снова.
В вашем примере запрос пользователя сначала совпадает со вторым местоположением, которое запускает вызов обработчика limit_conn для первого вызова. Вот почему используется правило limit_conn 30. Обработчик будет вызван второй раз после внутреннего перенаправления, но он почти сразу завершит свою работу, ничего не проверяя (вернуть NGX_DECLINED).
Если вы прокомментируете правило limit_conn 30 во втором расположении, правило limit_conn 10 будет унаследовано от контекста сервера, что является совершенно нормальным поведением для Nginx. В этом случае опять-таки сначала будет вызван обработчик limit_conn для основного запроса, а следующий вызов (после внутреннего перенаправления) ничего не сделает.
Наконец, когда вы комментируете все строки limit_conn за исключением правила limit_conn 20, обработчик limit_conn сначала будет вызываться после внутреннего перенаправления, и, таким образом, это правило в конечном итоге будет использовано.
ОБНОВИТЬ:
Поскольку правило limit_conn проверяется при установлении нового соединения, открытие нового соединения решит вашу проблему. Концептуально конфигурация будет выглядеть так:
limit_conn_zone $binary_remote_addr zone=limitedIP:10m;
server {
# You can use any random unused non-system port
listen 127.0.0.1:8889;
server_name internal.server;
set_real_ip_from 127.0.0.1/32;
real_ip_header X-Forwarded-For;
location ^~ /files/ {
limit_conn limitedIP 20;
alias /var/www/files/;
}
}
server {
...
location ^~ /files/ {
internal;
proxy_set_header Host "internal.server";
proxy_set_header X-Forwarded-For $remote_addr;
# Make sure you specify the same port as above
proxy_pass http://127.0.0.1:8889;
}
location ~ \.php$ {
...
limit_conn limitedIP 30;
}
}
Однако такой подход приведет к заметному снижению производительности, особенно если ваши файлы имеют большой размер. Поэтому я не рекомендовал бы использовать этот обходной путь.
К сожалению, я не могу представить какой-либо другой способ решить проблему только с Nginx.
Других решений пока нет …