Рейтинг:0

502 при перенаправлении с http на https на GCP

флаг fr

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

Требования довольно просты: перенаправить пользователей с сайта через порт 80 на тот же сайт через порт 443.

Мы сказали сайт с Apache в качестве фронта и с экземплярами Tomcat для наших реальных услуг. Эти сервисы размещены на двух разных машинах, одна виртуальная на GCP Compute Engine, а другая на «голом железе», от которого мы в конечном итоге откажемся.

У нас есть домен example.com, который содержит индекс служб. Он обслуживается статически Apache 2.4. Мы можем получить к нему доступ либо с Http, либо с Https. Из этого индекса мы перенаправляем с помощью proxy_mod на app1, app2 и app3. App2 и App3 находятся на сервере baremetal. Мы используем DNS, чтобы направлять пользователей к ним по их поддоменам app2.example.com/app2 и app3.example.com/app3. Я рассмотрю избыточность в будущем. Из-за определенных ограничений и того факта, что приложения app2 и app3 еще не опубликованы, мы получаем к ним доступ только по протоколу Http.

App1 имеет тот же SSL-сертификат, что и сервер Apache, поскольку они размещены на одной виртуальной машине. Опять же, мы можем получить доступ как к example.com, так и к example.com/app1 с помощью Http и Https.

Теперь проблемы:

Как указано в заголовке, у меня возникают проблемы с ошибками 502 всякий раз, когда я использую конфигурацию, которую я уже пробовал раньше, и которая работает в другой среде. Указанный конфиг примерно такой:

<VirtualHost *:80>
    Redirect permanent /  https://bar.com/
</VirtualHost>
<VirtualHost *:443>
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
 
        #SSL stuff
        SSLEngine On
        SSLCertificateFile /file.pem
        SSLCertificateKeyFile /file.key
        SSLVerifyClient none

        #Proxies
        ProxyRequests Off
        SSLProxyEngine on
        SSLProxyVerify none
        SSLProxyCheckPeerCN off
        SSLProxyCheckPeerName off
        SSLProxyCheckPeerExpire off
        ProxyPass        /api/          https://localhost:8443/api/
        ProxyPassReverse /api/          https://localhost:8443/api/
</VirtualHost>

bar.com был моей тестовой средой. Я взял эту конфигурацию и настроил ее следующим образом для example.com

<VirtualHost *:80>
    Redirect permanent /  https://example.com/
</VirtualHost>

<VirtualHost *:443>
        
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
 
        #SSL stuff
        SSLEngine On
        SSLCertificateFile      /etc/letsencrypt/live/example.com/fullchain.pem
        SSLCertificateKeyFile   /etc/letsencrypt/live/example.com/privkey.pem
        SSLVerifyClient none

        #Proxies
        SSLProxyEngine on
        SSLProxyVerify none
        SSLProxyCheckPeerCN on
        SSLProxyCheckPeerExpire on

        Redirect permanent      /app2      http://app2.example.com/app2
        Redirect permanent      /app3      http://app3.example.com/app3

        <Location /app1>
                ProxyPass               https://localhost:8443/app1
                ProxyPassReverse        https://localhost:8443/app1
        </Location>

</VirtualHost>

Но это приводит к 502 ошибкам. Опять же, я понимаю, что vhost на порту 80 в порядке. Я даже читал, что это рекомендуемый способ (сейчас смотрю, где я это читал). Я не пробовал с mod_rewrite, так как считаю, что ошибка связана не с самой конфигурацией, а с сочетанием модов SSL и прокси с GCP.

На стороне GCP у нас есть основные правила брандмауэра, и, поскольку мы можем получить доступ к Https или Http с базовой конфигурацией (то есть виртуальный хост, который у меня есть для 443, но прослушивающий порт 80, без первого виртуального хоста). Я настроил балансировщик нагрузки, но в основном для использования CDN Google. У него есть одна серверная группа с виртуальной машиной, на которой размещены Apache и app1. Для внешнего интерфейса у меня есть правила как для порта 80, так и для порта 443, что означает, что у меня есть еще один сертификат SSL специально для балансировщика нагрузки, которым управляет Google. Я настроил средства проверки работоспособности для обоих портов, отключив и включив внешние интерфейсы, чтобы убедиться, что это не связано с самими портами, и пока это не похоже на проблему.

Я все еще обдумываю всю экосистему GCP, поэтому я думаю, что я что-то упустил в этой части уравнения, поскольку сама конфигурация Apache кажется мне приемлемой.

Что мне еще предстоит попробовать:

  • Снял балансировщик, поставь ВМ без статического IP и попробуй там.
  • Используйте один и тот же сертификат во внешнем интерфейсе и на виртуальной машине.
  • Отключите порт 80 во внешнем интерфейсе и настройте Apache для прослушивания порта 443 (я не хочу этого делать, так как это скорее хак; сам конфиг будет работать как если бы он был http)

Почему я еще не пробовал эти штуки? Ну, как вы могли догадаться, ковыряться в конфигурации нашего живого сервера на самом деле не вариант. У меня нет доступа к bar.com, поэтому я не могу пробовать то, что мне хотелось бы, а использование WSL, хотя и полезное, оказалось не таким близким к реальному (это также может быть что-то на моей машине .). Поскольку я могу работать только около полуночи, я не могу пробовать многое так, как мне бы хотелось.

Кто-нибудь знает, что может вызывать ошибку 502?

Если вы поняли идею, но вам нужна дополнительная информация, пожалуйста, спросите. Я буду максимально подробным, но имейте в виду, что я все еще изучаю, как работает IaaS.

РЕДАКТИРОВАТЬ:

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

В ответ на @John Hanley (обратите внимание, я изменил домен и IP-адреса на «общие» значения):

С использованием завиток -l -v к домену, я получаю следующее:

* Попытка 1.1.1.1:80...
* Установлен TCP_NODELAY
* Подключен к example.com (1.1.1.1), порт 80 (#0)
> ПОЛУЧИТЬ/HTTP/1.1
> Хост: examplepole.com
> Пользовательский агент: curl/7.68.0
> Принять: */*
>
* Отметить пакет как не поддерживающий многоразовое использование
< HTTP/1.1 502 Неверный шлюз
< Тип содержимого: текст/html; кодировка = UTF-8
< Политика реферера: нет реферера
< Длина содержимого: 332
< Дата: воскресенье, 21 ноября 2021 г., 08:57:31 по Гринвичу
<

<html><заголовок>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>502 Ошибка сервера</title>
</голова>
<основной текст=#000000 bgcolor=#ffffff>
<h1>Ошибка: Ошибка сервера</h1>
<h2>Сервер обнаружил временную ошибку и не смог выполнить ваш запрос.<p>Повторите попытку через 30 секунд.</h2>
<h2></h2>
</тело></html>
* Соединение №0 с хостом example.com осталось нетронутым

и

* Попытка 1.1.1.1:443...
* Установлен TCP_NODELAY
* Подключен к example.com (1.1.1.1), порт 443 (#0)
* ALPN, предлагая h2
* ALPN, предлагающий http/1.1
* успешно установить места проверки сертификата:
* CA-файл: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), рукопожатие TLS, приветствие клиента (1):
* TLSv1.3 (IN), рукопожатие TLS, приветствие сервера (2):
* TLSv1.3 (IN), рукопожатие TLS, зашифрованные расширения (8):
* TLSv1.3 (IN), рукопожатие TLS, сертификат (11):
* TLSv1.3 (IN), рукопожатие TLS, проверка CERT (15):
* TLSv1.3 (IN), рукопожатие TLS, Готово (20):
* TLSv1.3 (OUT), изменение шифрования TLS, изменение спецификации шифрования (1):
* TLSv1.3 (OUT), рукопожатие TLS, Готово (20):
* SSL-соединение с использованием TLSv1.3/TLS_AES_256_GCM_SHA384
* ALPN, сервер принят для использования h2
*Сертификат сервера:
* тема: CN=example.com
* дата начала: 4 октября 13:25:53 2021 по Гринвичу
* срок действия: 2 января 13:25:52 2022 по Гринвичу
* subjectAltName: хост "example.com" соответствует сертификату "example.com"
* эмитент: C=US; O = Google Trust Services LLC; CN = ГТС СА 1D4
* Проверка сертификата SSL в порядке.
* Используя HTTP2, сервер поддерживает многократное использование
* Состояние соединения изменено (HTTP/2 подтверждено)
* Копирование данных HTTP/2 из буфера потока в буфер соединения после обновления: len=0
* Использование идентификатора потока: 1 (простой дескриптор 0x55b622463820)
> ПОЛУЧИТЬ/HTTP/2
> Хост: example.com
> пользовательский агент: curl/7.68.0
> принять: */*
>
* TLSv1.3 (IN), рукопожатие TLS, билет на выпуск новостей (4):
* TLSv1.3 (IN), рукопожатие TLS, билет на выпуск новостей (4):
* старый идентификатор сеанса SSL устарел, удаление
* Состояние соединения изменено (MAX_CONCURRENT_STREAMS == 100)!
< HTTP/2 502
<тип содержимого: текст/html; кодировка = UTF-8
< referrer-policy: без реферера
<длина содержимого: 332
< дата: воскресенье, 21 ноября 2021 г., 08:57:56 по Гринвичу
< alt-svc: очистить
<

<html><заголовок>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>502 Ошибка сервера</title>
</голова>
<основной текст=#000000 bgcolor=#ffffff>
<h1>Ошибка: Ошибка сервера</h1>
<h2>Сервер обнаружил временную ошибку и не смог выполнить ваш запрос.<p>Повторите попытку через 30 секунд.</h2>
<h2></h2>
</тело></html>
* Соединение №0 с хостом example.com осталось нетронутым

Я думаю, что запрос https здесь не работает из-за отсутствия заголовков, так как я могу получить доступ к сайту в своем браузере. Из этого я вижу, что запрос правильно обрабатывается LoadBalancer (или, по крайней мере, это то, что я понимаю), но это Стадия подключения изменена сообщение меня глючит, СПЕЦИАЛЬНО потому что там проходит пару секунд, как будто ждешь ответа.

От апачектл -S

Конфигурация виртуального хоста:
*:80 vm-name.region.gcp-project.internal (/etc/apache2/sites-enabled/0080-default.conf:1)
*:443 example.com (/etc/apache2/sites-enabled/0443-secured.conf:6)
Корневой сервер: "/etc/apache2"
Основной корневой документ: "/var/www/html"
Основной журнал ошибок: "/var/log/apache2/error.log"
Обратный вызов сторожевого таймера Mutex: using_defaults
Mutex ssl-stapling-refresh: using_defaults
Сшивание Mutex ssl: using_defaults
Прокси-сервер Mutex: using_defaults
SSL-кэш Mutex: using_defaults
Мьютекс по умолчанию: dir="/var/run/apache2/" механизм=по умолчанию 
PidFile: "/var/run/apache2/apache2.pid"
Определить: DUMP_VHOSTS
Определить: DUMP_RUN_CFG
Пользователь: name="www-data" id=33
Группа: name="www-data" id=33

Это интересно. В то время как виртуальный хост для порта 80 ссылается на экземпляр виртуальной машины самого GCP, виртуальный хост для порта 443 — нет. Я не уверен, что из этого извлечь... Я попытался получить доступ к виртуальной машине по ее внешнему IP-адресу с помощью curl. Http показывает правильный статус для постоянного перенаправления, тогда как HTTPs выдает ошибку из-за несоответствия CN и SAN (что имеет смысл, поскольку сертификат предназначен для домена, а не для IP). При этом я в некоторой степени уверен, что изменение IP-адреса виртуальной машины на статический IP-адрес, который у нас есть, и разрешение Apache выполнять балансировку нагрузки удовлетворят мое требование, но мы добавим по крайней мере еще одну виртуальную машину в довольно ближайшем будущем, поэтому делаем это в этот момент кажется... плохим. Я все еще думаю, что CDN — это хорошая функция, и в конце концов ее следует использовать.

О балансировщике нагрузки:

Это несколько сложно объяснить, поэтому я постараюсь быть как можно более подробным, но прямым (есть ли что-то в GCP CLI для отображения этой конфигурации? CLI еще не пробовал):

Сам балансировщик нагрузки:

Интерфейсы:

Протокол Порт Сертификат SSL-политика
HTTP 80 - -
HTTPS 443 например.com, управляемый GCP По умолчанию

Бэкенды |Протокол конечной точки|Именованный порт|Тайм-аут|проверка работоспособности| |-|-|-|-| |HTTP|http|30 секунд| hc-1 (провал)| |HTTP/2|https|30 секунд| hc-2 (Проходной)|

*Оба сервера указывают на одну и ту же группу, но на разные порты. Эта группа содержит нашу единственную виртуальную машину.

Правила хостов/путей:

Все неповрежденные переходят на серверную часть HTTP.Запрос на /* переход к серверной части HTTPS.

Хотя hc-1 терпит неудачу, он на самом деле разрешается на главную страницу. Но когда я пытаюсь получить доступ к app1, это не удается (что имеет смысл, поскольку этот VHost не содержит прокси-сопоставления с app1 для начала). С другой стороны, hc-2 проходит, но доступ к сайту как https://example.com выдает ошибку 502.

Наконец, что касается того, как я активировал сайты, я использовал a2ensite для 0080-default.conf и 0443-secured.conf.

О, и еще, на этой неделе наш сайт не работал. Кажется, это было во вторник, в тот же день, когда у Spotify были проблемы. Мне пришлось открыть балансировщик нагрузки, внести какие-либо изменения, сохранить, отменить указанное изменение и сохранить снова, чтобы он снова заработал, но с тех пор hc-1 дает сбой.

Я пробовал много перестановок моей конфигурации, начиная с той, которая, как я знаю, работает (то есть только один балансировщик нагрузки для HTTP и один VHost на порту 80).

John Hanley avatar
флаг cn
Ваш вопрос было бы легче понять, если бы вы: а) показывали запрос, используя **curl -I -v** и ответ; б) показать точную конфигурацию балансировщика нагрузки и серверной части; в) конфигурацию Apache **apachectl -S**. Ключевым моментом является то, кто сообщает об ошибке 502, балансировщик нагрузки или серверная часть? Как вы настроили/включили виртуальный хост Apache? У вас включены проверки работоспособности?
Jetto Martínez avatar
флаг fr
Спасибо. Я постараюсь получить эту информацию, как только смогу. Чтобы получить «неправильную» информацию, мне нужно на мгновение отключить наши услуги, поэтому мне нужно дождаться часов с низким трафиком.

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

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