Рейтинг:0

Использование обратного прокси-сервера apache для отправки всех запросов /blog на внутренний сервер wordpress

флаг cn

У меня есть веб-сайт, написанный на React, и теперь я хотел добавить на сайт раздел блога. Блог будет основан на wordpress.

Приложение React работает в контейнере докеров, и я использую контейнер докеров WordPress для запуска блога WordPress.

Чтобы получить доступ к веб-сайту, я использую другой контейнер, работающий под управлением apache и выступающий в качестве обратного прокси-сервера.

Внутри httpd.conf файл для контейнера Apache, у меня есть следующий раздел:

<VirtualHost *:80>
    <Location "/">
        ProxyPreserveHost On
        ProxyPass "${REACT_SERVER}/"
        ProxyPassReverse "${REACT_SERVER}/"
    </Location>

    <Location /blog>
        ProxyPreserveHost On
        ProxyPass "${BLOG_SERVER}/"
        ProxyPassReverse "${BLOG_SERVER}/"
        ProxyPassReverseCookiePath  "/"  "/blog"
    </Location>

    # more config for handling websockets
</VirtualHost>

Переменные REACT_SERVER и БЛОГ_СЕРВЕР исходить из окружающей среды.

У меня проблема в том, что когда я пытаюсь получить доступ к блогу, apache успешно перенаправляет мой запрос на внутренний сайт wordpress, но когда wordpress выполняет собственное перенаправление, он использует тот же хост, что и apache, но путь не начинается с /блог, поэтому мое приложение для реагирования пытается обработать запрос, но в конце концов сдается и выполняет собственное перенаправление на домашнюю страницу.

Вот пример использования завиток:

➤ curl -v http://localhost:3005/blog/
* Попытка 127.0.0.1:3005...
* Подключен к локальному хосту (127.0.0.1), порт 3005 (#0)
> ПОЛУЧИТЬ /блог/ HTTP/1.1
> Хост: локальный: 3005
> Пользовательский агент: curl/7.74.0
> Принять: */*
>
* Отметить пакет как не поддерживающий многоразовое использование
< HTTP/1.1 302 Найдено
< Дата: пятница, 20 августа 2021 г., 16:27:32 по Гринвичу
< Сервер: Apache/2.4.48 (Debian)
< X-Powered-By: PHP/7.4.22
< Истекает: среда, 11 января 1984 г., 05:00:00 по Гринвичу.
< Cache-Control: без кэша, необходимо перепроверить, max-age=0
< X-Redirect-By: WordPress
<Расположение: http://localhost:3005/wp-admin/install.php
< Длина содержимого: 0
< Тип содержимого: текст/html; кодировка = UTF-8
<
* Соединение №0 с хостом localhost осталось нетронутым

Как видите, после X-Redirected-By раздел, Место расположения начинается с /wp-админ вместо /блог/wp-admin.

От документы на ПроксиПассРеверс:

Например, предположим, что локальный сервер имеет адрес http://example.com/; тогда

ProxyPass "/mirror/foo/" "http://backend.example.com/"
ProxyPassReverse "/mirror/foo/" "http://backend.example.com/"
ProxyPassReverseCookieDomain "backend.example.com" "public.example.com"
ProxyPassReverseCookiePath "/" "/mirror/foo/"

вызовет не только локальный запрос на http://example.com/mirror/foo/bar внутренне преобразовать в прокси-запрос на http://backend.example.com/бар (функциональность который ProxyPass предоставляет здесь). Он также заботится о редиректах, которые сервер backend.example.com отправляет при перенаправлении http://backend.example.com/бар к http://backend.example.com/quux . Apache httpd настраивает это на http://example.com/mirror/foo/quux перед перенаправление ответа перенаправления HTTP клиенту. Обратите внимание, что имя хоста, используемое для построения URL-адреса, выбирается с учетом параметр директивы UseCanonicalName.

и кажется, что это все, что требуется для того, чтобы это работало, но это все еще не так.

И если вам интересно, да Я пробовал равнину (без Место расположения директива):

ProxyPass "/блог/" "${BLOG_SERVER}/"
ProxyPassReverse "/блог/" "${BLOG_SERVER}/"
ProxyPassReverseCookiePath "/" "/blog"

# и т.д...

И я также получаю те же результаты.

Что мне не хватает?

Рейтинг:2
флаг in

Эта проблема больше похожа на Wordpress, чем на неправильную конфигурацию. Вам нужно сообщить WordPress, что он находится внутри подкаталога, потому что прямо сейчас файл wordpress .htaccess по умолчанию перенаправляет вас на http://localhost:3005/wp-admin/install.php, потому что он не знает, что он находится в каталоге называется блог.

Опция 1. Один из способов решить эту проблему — сообщить WordPress, что у него есть новый базовый URL-адрес в файле wp-config.php.

определить('WP_HOME','http://example.com/blog');
определить('WP_SITEURL','http://example.com/blog');

Вариант 2. Другой способ попытаться справиться с этим - отредактировать файл htaccess WordPress.

Ваш файл htaccess в wordpress должен выглядеть примерно так

<IfModule mod_rewrite.c>
RewriteEngine включен
RewriteBase /блог/
Правило перезаписи ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
Правило перезаписи. /блог/index.php [L]

Это будет htaccess, который существует внутри док-контейнера wordpress.

smac89 avatar
флаг cn
Спасибо за Ваш ответ. Действительно, использование `WP_HOME` и `WP_SITEURL` было бы одним из способов решить эту проблему, но я хотел посмотреть, можно ли это сделать, используя только apache, mod_proxy, поэтому мой [ответ](https://serverfault.com /a/1075300/257206) также существует.
Рейтинг:0
флаг cn

Хорошо, я думаю, что понял проблему.

Wordpress использует две переменные для определения:

  1. Какой URL-адрес ведет к местоположению вашего сайта WordPress (WP_HOME)
  2. Какой URL-адрес используется для загрузки ресурсов для вашего сайта WordPress (WP_SITEURL)

Первое, что мне нужно было сделать для контейнера WordPress, это убедиться, что эти URL-адреса соответствуют внутреннему URL-адресу контейнера, т.е. $БЛОГ_СЕРВЕР. Поскольку я использую docker-compose, было легко ввести этот URL-адрес, используя переменные среды через WORDPRESS_CONFIG_EXTRA аргумент.

wordpress-блог:
  изображение: вордпресс: 5
  зависит от:
    - блог-БД
  среда:
    WORDPRESS_DB_HOST: БД блога
    WORDPRESS_DB_NAME: блог
    WORDPRESS_DB_USER: вордпресс
    WORDPRESS_DB_PASSWORD: вордпресс
    WORDPRESS_CONFIG_EXTRA: |
      определить('WP_HOME', 'http://wordpress-blog');
      определить('WP_SITEURL', 'http://wordpress-blog');
  тома:
    - вордпресс:/var/www/html

Теперь, когда это сделано, мы можем сосредоточиться на прокси.

Прежде чем я пошел по пути полного обратного прокси-сервера, я предполагал, что прокси-сервер каким-то образом возьмет на себя каждый запрос на /блог/ и возвращать страницы с прокси-сайта, которые будут выглядеть так, как будто они обслуживаются непосредственно из WordPress. Одна вещь, которую я не учел, заключалась в том, что это предположение также предполагало страницы, отображаемые на стороне сервера.

Начиная с нового Виртуальный хост конфигурации, теперь это выглядит так:

<VirtualHost *:80>
    ProxyPass "/blog/" "${BLOG_SERVER}/"
    ProxyPass "/" "${REACT_SERVER}/"

    <Location "/">
        ProxyPreserveHost On
        ProxyErrorOverride On
        ProxyPassReverse "${DEV_SERVER}/"
    </Location>

    <Location "/blog/">
        ProxyPreserveHost Off
        ProxyPassReverse "${BLOG_SERVER}/"
        ProxyPassReverseCookiePath  "/"  "/blog/"
        ProxyErrorOverride On

        ProxyHTMLEnable On
        ProxyHTMLExtended On
        ProxyHTMLURLMap "${BLOG_SERVER}/"
        SetOutputFilter INFLATE;proxy-html;DEFLATE
        # ProxyPassReverseCookieDomain "%{HTTP_HOST:${BLOG_SERVER}}" %{HTTP_HOST}
    </Location>
</VirtualHost>

Следующее, что мне нужно было сделать, чтобы этот прокси начал вести себя как прокси, это добавить эту строку:

ProxyPreserveHost выключен

Это гарантирует, что все ответы/запросы, которые мы получаем от wordpress, не будут выглядеть так, как будто они пришли от нас (прокси). Причина этого скоро станет очевидной, когда мы начнем разбираться с проксированием html.


Далее ПроксиПасс директивы были выведены из Место расположения емкость и непосредственно в Виртуальный хост.

ProxyPass "/блог/" "${BLOG_SERVER}/"
ProxyPass "/" "${REACT_SERVER}/"

Причина этого в том, что Место расположения блоки очень поздно соответствовали запросам, а иногда / путь побеждает /блог/ дорожка. Мне нужно было, чтобы было надежнее, поэтому я решил пойти с указанием прокси самостоятельно (я видел пример здесь), затем изменив пути внутри Место расположения контейнер.


На данный момент обратный прокси теперь за работой! Однако в html на страницах были ссылки, которые указывали на внутренний URL-адрес сайта WordPress. Вот где mod_proxy_html входит. Его можно использовать для перезаписи всех ссылок в html, чтобы они указывали на обратный прокси. Везде, где он находит ссылку, указывающую на внутренний сайт блога, эта ссылка заменяется ссылкой, использующей обратный прокси-сервер.

ProxyHTMLEnable Вкл.
ProxyHTMLExtended On
ПроксиHTMLURLMap "${BLOG_SERVER}/"
SetOutputFilter INFLATE; прокси-html; DEFLATE

Последняя строка может стать узким местом, потому что она, по сути, распаковывает полезную нагрузку с сайта блога, переписывает все URL-адреса, чтобы они указывали на обратный прокси-сервер, а затем снова их сжимает. Если вы этого не хотите, другой способ сделать это - использовать:

RequestHeader не установлен Accept-Encoding

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

Одним из решений этого было бы пойти с первым решением, предложенным текущий ответ по этому вопросу и изменить WP_SITEURL чтобы указать на обратный прокси напрямую.

Еще одно решение заключается в использовании Сервисный работник к перехватывать сетевые запросы. Мне нравится это решение, потому что оно не связывает сайт блога с обратным прокси-сервером. Я мог представить, что это не будет слишком надуманной (хе-хе) идея внедрить работника службы в любые html-страницы, запрошенные с прокси-сервера, и заставить этого работника службы перехватывать все запросы, которые соответствуют внутреннему URL-адресу сайта блога, и заменить их с обратным URL-адресом прокси-сервера.

Я не пошел ни с одним из них. После долгих размышлений я думаю, что хостинг wordpress в поддомене будет лучше для моих нужд. Что-то вроде blog.example.com — это то, на что я мог бы пойти, но это будет работа для другого дня.


В заключение отметим, что обратные прокси трудно правильно реализовать с помощью Apache. Я не знаю, зеленее ли трава на стороне nginx, но, может быть, когда-нибудь мы это проверим. Решение, которое я выбрал, предполагало контент только на стороне сервера, который оказался бы идеальным кандидатом для проксирования, но, увы, динамически загружаемый контент потребует больше работы.

Источники

Модули Apache включены для проксирования html

Модули загрузки deflate_module modules/mod_deflate.so
LoadModule xml2enc_module modules/mod_xml2enc.so
LoadModule proxy_html_module modules/mod_proxy_html.so

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.