Перенаправление Yii2 с прокси-сервером OpenShift

Я развернул приложение Yii2 на основе PHP на OpenShift. По сути, Yii2 работает в контейнере на основе alpine с установленными PHP и Nginx. Контейнер предоставляет port 8080, который затем привязывается к сервису OpenShift, где, в свою очередь, создается защищенный маршрут с Edge encryption.

Большая часть приложения работает нормально, однако при создании сообщения HTTP, а затем в контроллере, выполняющем перенаправление, Yii2 перенаправляет на http://<sitename> вместо того, чтобы оставаться на https, что приводит к тому, что приложение больше не работает. Сам запрос POST работает, так как впоследствии в БД вносятся изменения, это перенаправление обратно к обзору, которое не работает в этом контексте.

Действие контроллера очень простое и стандартное:

public function actionUpdate($id)
{
    $model = $this->findModel($id);

    if ($model->load(Yii::$app->request->post()) && $model->save()) {
        return $this->redirect(['index']);
    }

    return $this->render('update', [
        'model' => $model,
    ]);
}

Немного информации о конфигурации OpenShift:

~ oc get routes 
NAME       HOST/PORT                PATH   SERVICES  PORT     TERMINATION   WILDCARD
backend    backend.apps.<instance>         backend   backend  edge          None
frontend   frontend.apps.<instance>        frontend  frontend edge          None

~ oc describe route backend
Name:           backend
Namespace:      <project>
Created:        10 hours ago
Annotations:        openshift.io/host.generated=true
Requested Host:     backend.apps.<instance> 
                    exposed on router router 10 hours ago
Path:           <none>
TLS Termination:    edge
Insecure Policy:    <none>
Endpoint Port:      backend

Service:    backend
Weight:     100 (100%)
Endpoints:  <ip>:8080

Dockerfile для создания приложения не очень впечатляющий, он в основном устанавливает PHP, Nginx и устанавливает некоторые разрешения. Конфигурация Nginx на самом деле может быть частью проблемы, поэтому мы публикуем очищенную версию ниже.

worker_processes  1;
error_log stderr warn;
pid /run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main_timed  '$remote_addr - $remote_user [$time_local] "$request" '
                            '$status $body_bytes_sent "$http_referer" '
                            '"$http_user_agent" "$http_x_forwarded_for" '
                            '$request_time $upstream_response_time $pipe $upstream_cache_status';

    access_log /dev/stdout main_timed;
    error_log /dev/stderr notice;

    keepalive_timeout  65;

    server {
        listen [::]:8080 default_server;
        listen 8080 default_server;
        server_name _;

        sendfile off;

        root /var/www/html/backend/web/;
        index index.php index.html;

        location / {
            # First attempt to serve request as file, then
            # as directory, then fall back to index.php
            try_files $uri $uri/ /index.php?q=$uri&$args;
        }

        # redirect server error pages to the static page /50x.html
        #
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
            root /var/lib/nginx/html;
        }

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ \.php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass  127.0.0.1:9000;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param SCRIPT_NAME $fastcgi_script_name;
            fastcgi_index index.php;
            include fastcgi_params;
        }

        location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
            expires 5d;
        }

        # deny access to . files, for security
        #
        location ~ /\. {
            log_not_found off;
            deny all;
        }

        # allow fpm ping and status from localhost
        #
        location ~ ^/(fpm-status|fpm-ping)$ {
            access_log off;
            allow 127.0.0.1;
            deny all;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
            fastcgi_pass 127.0.0.1:9000;
        }
    }
}

Редактировать 1:

Добавление следующей строки в конфигурацию Nginx каким-то образом заставляет его работать, однако это не очень хорошее решение:

location ~ \.php$ {
    [...]
    fastcgi_param HTTPS on;

Однако это предполагает, что всегда используется HTTP. Однако это зависит от конфигурации маршрута OpenShift. Есть ли лучшее (более универсальное) решение?

Ваше приложение должно учитывать заголовок X-Proxy-Scheme, установленный haproxy, который используется для маршрутизации. Значение скажет вам, использовал ли исходный запрос http или https. Вы должны использовать это в любых URL-адресах, которые создает ваше приложение.

Graham Dumpleton 07.07.2019 13:15

@GrahamDumpleton спасибо за ваш комментарий! Мой главный вопрос заключается в том, где устанавливается заголовок (возможно, с помощью прокси-сервера OpenShift/lb)? Как указать Nginx пересылать этот заголовок с помощью fastcgi?

waza-ari 07.07.2019 13:16

@waza-ari, вы можете попробовать следующее fastcgi_pass_header X-Proxy-Scheme;nginx.org/ru/docs/http/… или fastcgi_pass_request_headers on;nginx.org/ru/docs/http/…

Aleksandar 17.07.2019 20:55

@Александр, если я правильно понял руководство, fastcgi_pass_request_headers включен по умолчанию.

waza-ari 21.07.2019 15:19
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
4
336
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Маршрутизатор OpenShift (который предоставляет защищенный маршрут, который вы создали) установит число заголовки в запросе к бэкэнд-модулю, на котором запущено ваше приложение Yii2.

Первое, что нам нужно сделать, — это доверить эти заголовки Nginx, чтобы он передал их серверному приложению Yii2.

location ~ \.php$ {
    proxy_pass_header   X-Forwarded-Proto;
    proxy_pass_header   X-Forwarded-Host;
    proxy_pass_header   X-Forwarded-Port;
    [...]

X-Forwarded-Proto будет установлено на https, и похоже, что Yii2 будет правильно обрабатывать заголовок, но я раньше не использовал эту PHP-инфраструктуру. Это будет второй шаг, если потребуется, который будет заключаться в том, чтобы получить URL-адрес ответа фреймворка с протоколом, который находится в заголовке x-forwarded-proto.

Здесь следует отметить, что доверять этим заголовкам на уровне Nginx может быть опасно, если ненадежные пользователи могут получить прямой доступ к Nginx. В этом сценарии они смогут подделывать запросы и устанавливать эти заголовки такими, какие они хотят.

Ответ принят как подходящий

Благодаря всем комментариям и ответам, я смог понять это. Я не использую Nginx в качестве прокси здесь, но я использую FastCGI для PHP, поэтому я не уверен, что ответ, предложенный Джейсоном, сработает. Следующие решения работают для меня:

location ~ \.php$ {

    set $my_https 'off';
    if ($http_x_forwarded_proto = 'https') {
        set $my_https 'on';
    }

    fastcgi_param HTTPS $my_https;

Может быть более элегантное решение для этого, но это работает для меня.

Другие вопросы по теме