Nginx reverse-proxy для Bitrix VM

В данной статье я расскажу про опыт настройки 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;
                }
        }

Используемые источники

Понравилась статья? Поделиться с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: