Апа́чевский обратный прокси не работает и выдает ошибку 404.

Вопрос или проблема

У меня установлена Shibboleth, которая работает на Jetty 9. Через Apache у меня есть обратный прокси на порт 8080 Jetty, который обслуживает экземпляр Shibboleth.

Когда я выполняю curl http://localhost:8080/idp/shibboleth в консоли, ответ экземпляра генерируется корректно.

Однако, когда я делаю то же самое в своем браузере https://idp.example.com/idp/shibboleth, я получаю ошибку 404.

Это указывает на то, что обратный прокси работает неправильно?

Это моя конфигурация Apache

SSLUseStapling on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
SSLStaplingCache shmcb:/var/run/ocsp(128000)

<VirtualHost *:80>
ServerName "idp.spectrum.com.cy"
Redirect permanent "/" "https://idp.spectrum.com.cy/"
</VirtualHost>

<IfModule mod_ssl.c>
<VirtualHost _default_:443>
 ServerName idp.spectrum.com.cy:443
 ServerAdmin [email protected]
 # Debian
 CustomLog /var/log/apache2/idp.spectrum.com.cy.log combined
 ErrorLog /var/log/apache2/idp.spectrum.com.cy.org-error.log
 # Centos
 #CustomLog /var/log/httpd/idp.example.org.log combined
 #ErrorLog /var/log/httpd/idp.example.org-error.log
 
 DocumentRoot /var/www/html/idp.spectrum.com.cy
 
 SSLEngine On
 SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
 SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4"

 SSLHonorCipherOrder on
 
 # Запретить встраивание страницы входа вашего IdP в iframe и
 # Включить строгую транспортную безопасность HTTP с длительностью 2 года
 <IfModule headers_module>
    Header set X-Frame-Options DENY
    Header set Strict-Transport-Security "max-age=63072000 ; includeSubDomains ; preload"
 </IfModule>
 
 # Debian
 SSLCertificateFile /etc/ssl/certs/idp.spectrum.com.cy.crt
 SSLCertificateKeyFile /etc/ssl/private/idp.spectrum.com.cy.key

 # ACME-CA или GEANT_OV_RSA_CA_4 (для пользователей, которые используют GARR TCS/Sectigo RSA Organization Validation Secure Server CA)
 #SSLCACertificateFile /etc/ssl/certs/ACME-CA.pem
 #SSLCACertificateFile /etc/ssl/certs/GEANT_OV_RSA_CA_4.pem


 # Centos
 #SSLCertificateFile /etc/pki/tls/certs/idp.example.org.crt
 #SSLCertificateKeyFile /etc/pki/tls/private/idp.example.org.key

 # ACME-CA или GEANT_OV_RSA_CA_4 (для пользователей, которые используют GARR TCS/Sectigo RSA Organization Validation Secure Server CA)
 #SSLCACertificateFile /etc/pki/tls/certs/ACME-CA.pem
 #SSLCACertificateFile /etc/pki/tls/certs/GEANT_OV_RSA_CA_4.pem

 <IfModule mod_proxy.c>
    ProxyPreserveHost On
    RequestHeader set X-Forwarded-Proto "https"
    ProxyPass /idp http://localhost:8080/idp/ retry=5
    ProxyPassReverse /idp http://localhost:8080/idp/ retry=5

    <Location /idp>
       Require all granted
    </Location>
 </IfModule>
</VirtualHost>
</IfModule>

<VirtualHost 127.0.0.1:80>
  ProxyPass /idp  http://localhost:8080/idp/ retry=5
  ProxyPassReverse /idp http://localhost:8080/idp/ retry=5
  <Location /idp>
   Require all granted
  </Location>
</VirtualHost>

Я упростил свой конфигурационный файл, чтобы убрать https. Ниже представленная конфигурация работает нормально, но только с http. Я буду расследовать, почему конфигурация https генерирует ошибку 404.

<VirtualHost *:80>
ServerName idp.spectrum.com.cy

 <IfModule mod_proxy.c>
    ProxyPreserveHost On
    ProxyPass /idp/ http://localhost:8080/idp/ retry=5
    ProxyPassReverse /idp/ http://localhost:8080/idp/ retry=5

    <Location /idp>
       Require all granted
    </Location>
 </IfModule>


</VirtualHost>

    # Этот виртуальный хост создан только для обработки административных команд 
    для Shibboleth, выполняемых с localhost
    <VirtualHost 127.0.0.1:80>
      ProxyPass /idp  http://localhost:8080/idp/ retry=5
      ProxyPassReverse /idp http://localhost:8080/idp/ retry=5
      <Location /idp>
        Require all granted
      </Location>
    </VirtualHost>

Обычно это должно быть

ProxyPass /idp/ http://localhost:8080/idp/

Обратите внимание на завершающий слэш в первом аргументе команды ProxyPass. Всегда согласовывайте завершающие слэш в обоих аргументах.

Мои декларации VirtualHost довольно просты и содержат только минимально необходимое для работы:

<VirtualHost *:80>
    DocumentRoot /var/www/html

    ServerName idp.example.com
    ServerAlias idp
    ErrorLog  logs/error_log
    CustomLog logs/access_log    
</VirtualHost>
<VirtualHost *:443>
    DocumentRoot /var/www/html

    SSLEngine on
    SSLProxyEngine on
    SSLCertificateKeyFile /etc/pki/tls/private/idp.example.com.key
    SSLCertificateFile /etc/pki/tls/certs/idp.example.com.crt
    SSLCertificateChainFile /etc/pki/tls/certs/chain.crt

    ServerName idp.example.com
    ServerAlias idp
    ErrorLog  logs/ssl-error_log
    CustomLog logs/ssl-access_log combined
</VirtualHost>

Вот мой /etc/httpd/conf.d/idp.conf для IDP:

ProxyPass /idp/ http://localhost:8080/idp/ retry=5
ProxyPassReverse /idp/ http://localhost:8080/idp/

<Proxy http://localhost:8080>
       Require all granted
       RequestHeader set X-Forwarded-Proto https
       RequestHeader set X-Proxied-Https on
       RequestHeader set Proxy-ssl-id %{SSL_SESSION_ID}s
</Proxy>

Попробуйте удалить порт из директивы ServerName. Т.е.,

ServerName idp.spectrum.com.cy

Согласно https://httpd.apache.org/docs/2.4/mod/core.html#servername, порт является необязательным и допускается, но далее в документации упоминается, что это может быть причиной того, что эта конфигурация VirtualHost не срабатывает (браузеры не отправляют номер порта в заголовке Host:).

Если вы используете виртуальные хосты на основе имени, ServerName внутри секции
<VirtualHost> указывает, какому имени хоста должно соответствовать содержимое заголовка Host: в запросе для совпадения с этим виртуальным хостом.

Ответ или решение

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

Проблема: Ошибка 404 при доступе через Apache Reverse Proxy

  1. Проверка конфигурации Apache: Первым делом нужно удостовериться, что конфигурация Apache правильно установлена для обратного прокси. В вашем конфигурационном файле вы используете модули mod_proxy и mod_ssl, что корректно для работы с HTTPS и проксированием.

    <IfModule mod_proxy.c>
       ProxyPreserveHost On
       ProxyPass /idp http://localhost:8080/idp/ retry=5
       ProxyPassReverse /idp http://localhost:8080/idp/ retry=5
    </IfModule>

    Обратите внимание на:

    • Трасировка слешей. Вам следует убедиться, что у вас стоит слеш на конце строки. Например, менять ProxyPass /idp http://localhost:8080/idp/ на ProxyPass /idp/ http://localhost:8080/idp/, а также указывать ProxyPassReverse /idp/ http://localhost:8080/idp/.
    • Контекст Location. Убедитесь, что у вас есть блок <Location>, позволяющий доступ к /idp, и что права на доступ установлены корректно.
    <Location /idp>
       Require all granted
    </Location>
  2. Проверка виртуальных хостов: Вы указали несколько блоков <VirtualHost>. Чтобы избежать путаницы, рекомендуется проверить, правильно ли вы настраиваете свои виртуальные хосты. Не включайте порт в директиву ServerName, как это указано в документации Apache, так как браузеры обычно не отправляют номер порта в заголовках Host.

    ServerName idp.spectrum.com.cy
  3. Проверка логов: Логи ошибок Apache могут дать ценную информацию о том, что происходит. Если вы настроили отдельный лог для этого виртуального хоста:

    ErrorLog /var/log/apache2/idp.spectrum.com.cy.org-error.log

    Просмотрите логи после попытки доступа к URL, чтобы определить, сообщает ли сервер конкретные причины ошибки 404.

  4. Проверка настройки SSL: Поскольку вы используете HTTPS, необходимо убедиться, что SSL настроен правильно, и что Apache может обрабатывать запросы через защищенное соединение. Возможно, стоит отключить проверки сертификатов на начальном этапе для диагностики.

  5. Проблемы с кэшированием: Убедитесь, что кэширование не вызывает проблему. Попробуйте очистить кэш браузера или протестировать доступ через режим инкогнито.

  6. Firewall и SELinux: Если ваш сервер работает под управлением Linux, проверьте настройки брандмауэра (iptables или firewalld) и SELinux, чтобы удостовериться, что они не блокируют трафик.

Заключение

Для устранения ошибки 404, возникающей при работе обраного прокси с Apache, необходимо внимательно проверить конфигурацию. Убедитесь в правильности слешей в ProxyPass, настройке виртуальных хостов, доступности логов, а также в корректности SSL-установок. Проверка всех этих аспектов поможет быстрее найти и устранить причину проблемы.

Регулярное ведение логов и их анализ помогут оперативно выявлять и исправлять подобные проблемы в будущем.

Оцените материал
Добавить комментарий

Капча загружается...

  1. Гость

    Здравствуйте! Судя по вашему описанию, проблема может заключаться в конфигурации Apache при работе с HTTPS и обратным прокси на Jetty. Ошибка 404 при доступе через https://idp.example.com/idp/shibboleth указывает на то, что запросы не перенаправляются корректно.

    Обращаю ваше внимание на несколько моментов, которые могут помочь решить проблему:

    Включите SSLProxyEngine: Для проксирования HTTPS-запросов Apache требует явного включения SSLProxyEngine. Добавьте следующую строку внутри вашего блока <VirtualHost _default_:443>:

    SSLProxyEngine On

    Удалите номер порта из ServerName: Указание порта в директиве ServerName может привести к некорректному сопоставлению виртуального хоста, поскольку браузеры не включают номер порта в заголовке Host. Измените:

    ServerName idp.spectrum.com.cy:443

    на

    ServerName idp.spectrum.com.cy

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

    ProxyPass /idp/ http://localhost:8080/idp/ retry=5
    ProxyPassReverse /idp/ http://localhost:8080/idp/ retry=5

    Добавьте необходимые заголовки для проксирования HTTPS: Это поможет Jetty корректно обрабатывать исходные HTTPS-запросы. Внутри блока <VirtualHost _default_:443> добавьте:

    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Proxied-Https "on"

    Проверьте логи Apache: Логи часто содержат подробную информацию о причинах ошибок. Просмотрите файлы логов, указанные в директивах ErrorLog и CustomLog, чтобы найти дополнительные подсказки.

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

    Удачи в решении проблемы!

    Ответить