Сложность в том, что некоторым скриптам необходимо знать через какую схему они работают, http, или https. Таким образом они формируют ссылки, а иногда принудительно перенаправляют клиентов куда нужно. Из-за не верной настройки серверного ПО переадресация не может завершиться и браузер покажет нам ошибку 'too many redirects'.

В статье рассмотрим две схемы:
nginx (front1, server2) -> nginx (front2, server1) -> php-fpm (back, server1)
nginx (front1, server2) -> nginx (front2, server1) -> apache (back, server1)

Первой рассмотрим схему с php-fpm:

nginx (front1, server2) -> nginx (front2, server1) -> php-fpm (back, server1)

На сервере 'nginx (front1, server2)' у нас обязательно должны быть строки
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded_For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

среди которых нам важна последняя.

На сервере 'nginx (front2, server1)' в секцию http добавляем
http {
...
map $http_x_forwarded_proto $fastcgi_https {
default off;
https on;
}
...
}

Если его добавить в любое другое место - получите следующую ошибку при перезапуске nginx:
nginx: [emerg] "map" directive is not allowed here

Если прописать просто $https вместо $fastcgi_https - получите следующую ошибку:
nginx: [emerg] the duplicate "https" variable in /etc/nginx/nginx.conf

Дело в том, что начиная с какой-то бородатой версии NginX имеет встроенную переменную $https, поэтому ее повторно использовать не получится.

Редактируем /etc/nginx/fastcgi_params:

Комментируем/удаляем:
fastcgi_param HTTPS $https if_not_empty;

Добавляем:
fastcgi_param HTTPS $fastcgi_https if_not_empty;

Проверяем конфигурацию nginx
service nginx configtest

перезагружаем конфигурацию
service nginx reload

Проверяем с помощью phpinfo, если видим в выводе
_SERVER["HTTP_X_FORWARDED_PROTO"] => https
_SERVER["HTTPS"] => on

значит всё в порядке, скрипты будут работать корректно.

Рассмотрим вторую схему, когда вместо php-fpm используется apache:

nginx (front1, server2) -> nginx (front2, server1) -> apache (back, server1)
В таком случае конфигурация сервера 'nginx (front1, server2)' идентична конфигурации выше, т.е. нам важно присутствие параметра
proxy_set_header X-Forwarded-Proto $scheme;

В конфигурации сервера 'nginx (front2, server1)' у нас скорее всего будут строки
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

здесь комментируем, или удаляем последнюю строку, а вместо неё пишем
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;

После этого в phpinfo уже сейчас можно будет увидеть параметр
[HTTP_X_FORWARDED_PROTO] => https

Добавляем в конфигурацию apache (back, server1) следующие строки
<IfModule setenvif_module>
SetEnvIf X-Forwarded-Proto https HTTPS=on
</IfModule>

должен быть подключен модуль 'setenvif_module', посмотреть можно с помощью 'apache2ctl -M'.
К моему удивлению, после этого в phpinfo ничего не изменилось, я всё так же видел
[REQUEST_SCHEME] => http

долго возился, но, как оказалось, скриптам этот параметр всё же передаётся и ссылки формируются правильно. Я на всякий случай убрал конструкцию из конфигурации apache, изменений в phpinfo не увидел, а вот скрипт стал формировать ссылки не правильно.

Ещё думал над параметром X-Forwarded-Port, но, как оказалось, nginx не умеет передавать динамически используемый клиентом порт, он может передавать только тот порт, по которому соединяется со следующим сервером (бэкэндом).

Использованы материалы:
www.tech-notes.net
eurohoster.org
www.sonassi.com
forge.typo3.org
Добавить комментарий