Я хотел бы начать с того, что я знаю, что есть буквально сотни тем по этому поводу, за которыми я следил раньше, чтобы все заработало. Тем не менее, эта конфигурация, с которой я работал несколько месяцев, не работает в другой среде.
Требования довольно просты: перенаправить пользователей с сайта через порт 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).