В данной статье я расскажу про опыт настройки Nginx в качестве прокси-сервера для сервера с bitrixVM. При типовой настройке сервера с bitrix и последующего конфигурирования Nginx в качестве прокси для него, где, казалось бы, все параметры типовые и нужно ли лишь минимально настроить proxy_pass до нужного адреса, часто могут возникать ошибки, которые всплывают в процессе эксплуатации.
400 Bad Request, The plain HTTP request was sent to HTTPS port
При перенаправлении с http на https на стороне Nginx proxy и обращении к имени сайта https://domain.ru/bitrix без слэша в конце, в URL подставлялся 443 порт и протокол менялся на http.
Суть ошибки понятна из её содержимого. Такое бывает из-за того, что терминация TLS-трафика происходит на стороне прокси (Nginx), т.е. запросы пользователей приходят на 443 порт, а backend с самим сайтом работает на http – обычно 80 или иной другой порт, а потому от прокси до бэкенда трафик идёт уже незашифрованный. Сам apache, который является конечной точкой в схеме при проксировании, должен понимать, что сайт работает с использованием протокола https, т.е. при выводе информации в phpinfo значение переменной $_SERVER[‘SERVER_PORT’] должно быть 443, а не 80, и в таком случае никакой некорректной подстановки осуществляться не будет. В противном случае, если где-то происходит рассинхрон, и возникают подобного рода “приколы” с появлением то 80 порта в URL, то 443 при открытии некоторых страниц.
Самым простым решением является использовать 80 или 443 порт в зависимости от используемого протокола – реализация взята с сайта битрикс и настраивается через конструкцию map. Например, на сервере с битрикс создается файл /etc/nginx/bx/settings/schema.conf со следующим содержимым:
map $http_x_forwarded_proto $balancer_port {
default 80;
"https" 443;
}
map $http_x_forwarded_proto $balancer_https {
default "NO";
"https" "YES";
}
Если переменная $http_x_forwarded_proto в Nginx содержит в себе https, то в новые переменные $balancer_port и $balancer_https записывается значение 443 и YES соответственно.
А в используемом сайте по пути, например, /etc/nginx/bx/site_enabled/bx_ext_test.example.org.conf заменить конфигурацию по умолчанию:
proxy_set_header Host $host:80;
На следующую:
proxy_set_header Host $host:$balancer_port;
proxy_set_header HTTPS $balancer_https;
Таким образом, при работе сайта по https или http, всегда будет подставляться корректный порт в зависимости от используемого протокола.
В своё время по этой проблеме я также писал в поддержку битрикса и тогда они ещё предложили такое костыльное решение, как мне кажется. Но оно имеет право на жизнь, т.к. работает. В dbconn.php надо добавить:
if (($pos = strpos($_SERVER['HTTP_HOST'], ':')) !== false)
{
$HTTP_HOST = $_SERVER['HTTP_HOST'] = substr($_SERVER['HTTP_HOST'],0,$pos);
}
$_SERVER["HTTPS"] = "On";
$_SERVER['SERVER_PORT'] = 443;
По сути будет выполнено тоже самое, что и описанное ранее выше, только средствами PHP, и Apache будет понимать, что сайт работает через https.
Ещё одна известная ошибка, которая возникает при работе сайта на битриксе через прокси – это не работает модуль Push&Pull. Точнее, не работает проверка системы, хотя казалось бы, что всё настроено: из menu.sh bx-push-server 2.0 установлен корректно штатными средствами, redis запущен, в логах ошибок нет. Но на сайте может быть красная полоса “Отсутствует соединение с сервером” и проваливается проверка системы, если обращаться через прокси-сервер.
Проблема в том, что Push server работает через wss, т.е. веб сокеты, а для этого со стороны прокси сервера необходимо проксировать дополнительные заголовки до backend, указывая явно, что клиент может сменить протокол на wss. “Upgrade” и “Connection” не передаются от клиента к проксируемому серверу, поэтому, для того чтобы проксируемый сервер узнал о намерении клиента сменить протокол на WebSocket, эти заголовки следует передать явно.
Для реализации необходимо добавить отдельный location:
location ~* ^/bitrix/subws/ {
access_log off;
proxy_pass http://BACKEND;
proxy_max_temp_file_size 0;
proxy_read_timeout 43800;
proxy_http_version 1.1;
proxy_set_header Upgrade $replace_upgrade;
proxy_set_header Connection $connection_upgrade;
Таким образом будут решены основные проблемы. Ниже приведен пример конфигурационного файла nginx proxy для сервера с битрикс:
server {
server_name {DOMAIN};
listen 80;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name {DOMAIN};
ssl_certificate "/etc/nginx/ssl/cert.crt";
ssl_certificate_key "/etc/nginx/ssl/key.key";
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/{DOMAIN}.access.log;
location / {
proxy_ignore_client_abort on;
proxy_pass http://{NODE-IP}:80;
proxy_redirect http://{NODE-IP}:80 /;
proxy_read_timeout 300;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header HTTPS YES;
# for Push&Pull
location /bitrix/subws {
proxy_pass http://{NODE-IP}:80;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect http://{NODE-IP}:80 /;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header HTTPS YES;
}
}