Вопрос или проблема
У меня есть самая простая настройка Apache-прокси, которую я не могу заставить работать.
На сервере CentOS я запускаю обычную настройку Apache/httpd, которая обслуживает несколько веб-сайтов. Apache слушает на портах 80 и 443.
SELinux отключен, и порты 80 и 8080 разрешены на всех интерфейсах в файерволе iptables.
Мне было поручено настроить дополнительный веб-сайт, но этот веб-сайт упакован как приложение LAMP с использованием Docker Compose, которое также использует Apache внутри.
Это должно быть просто, верно? Все, что мне нужно сделать, это использовать внешний Apache для проксирования входящего трафика с порта 80 на любой порт, который открывает Docker (например, 8080):
[Интернет] -> Внешний Apache (:80) -> ProxyPass -> Docker (:8080) -> Внутренний Apache (:80) -> [Контент]
Но что бы я ни делал, это просто не работает. Внешний Apache-прокси слушает на порту 80 нормально, и я вижу входящие запросы к нему. Но проксируемые запросы просто не могут достичь сервера, открытого Docker.
Ошибка, которую я вижу в логах внешнего Apache:
[proxy_http:error] [pid 11669] (70007)Время ожидания истекло: [client xxx:59517] AH01102: ошибка чтения строки статуса с удаленного сервера localhost:8080
В логах внутреннего Apache Docker ничего нет.
Примечание: Я пытался временно остановить мой внешний экземпляр Apache и позволить стеку Docker выходить напрямую на сервер с использованием ports: 80:80
, и он был доступен – так что я знаю, что стек Docker работает. Это связано что-то с сопоставлением портов и/или прокси, что вызывает проблему.
Странно то, что я знаю, что Docker правильно открывает порт, потому что он отвечает на запросы:
# nc -zv localhost 8080
Ncat: Версия 7.50 ( https://nmap.org/ncat )
Ncat: Подключено к 127.0.0.1:8080.
Ncat: 0 байт отправлено, 0 байт получено за 0.01 секунд.
Я полагаю, это исключает файервол как причину, потому что если бы он был заблокирован, я ожидал бы, что Ncat будет отклонен.
Вот как выглядит мой файл docker-compose.yml
:
# docker-compose.yml
version: '3'
services:
php:
image: php:7.2-apache
ports:
- 8080:80
volumes:
- ./html:/var/www/html # Содержит index.php
Вот файл конфигурации внешнего Apache-прокси:
# apache2 работающий вне Docker
# test.local-vhost.conf
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
<VirtualHost *:80>
ServerName example.com
ProxyPreserveHost On
ProxyPass / http://localhost:8080
ProxyPassReverse / http://localhost:8080
</VirtualHost>
Интересно, когда я обращаюсь к порту 8080 со своего домашнего компьютера, все работает отлично. Но когда я обращаюсь к порту 80, это не работает. Возможно, что-то связано с тем, что прокси не может достичь порта 8080 на той же машине.
Оказалось, что это происходило из-за внутреннего трафика, заблокированного слишком строгим набором правил.
Вот что потребовалось, чтобы решить проблему:
iptables -A INPUT -p tcp -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
Ответ или решение
Вопрос: Apache Proxy не может достучаться до Docker-контейнера, несмотря на то, что порт открыт и доступен
Введение
Проблема, с которой вы столкнулись, достаточно распространена среди администраторов систем, использующих Apache в качестве прокси-сервера для Docker-контейнеров. Несмотря на то, что все порты настроены и работают, могут возникать неожиданные ситуации, когда прокси-служба не может связаться с целевым контейнером. Рассмотрим основные аспекты и решения вашей проблемы.
Текущая конфигурация
Вы настроили Apache на CentOS для проксирования запросов на Docker-контейнер, использующий LAMP-стек. Ваша конфигурация включает следующие ключевые моменты:
- Apache на CentOS прослушивает порты 80 и 443.
- SELinux отключен, что исключает влияние политик безопасности.
- iptables настроен для разрешения трафика на портах 80 и 8080.
- docker-compose.yml файл корректно указывает на проброс порта 8080.
Проблема
Несмотря на правильную настройку, Apache не может достать до контейнера на порту 8080, что приводит к ошибке:
[proxy_http:error] [pid 11669] (70007)The timeout specified has expired: [client xxx:59517] AH01102: error reading status line from remote server localhost:8080
Анализ
Исходя из вашего описание, вы можете исключить следующие возможные причины проблемы:
-
Работа Docker: Как Вы отметили, удаление Apache из цепочки и доступ к контейнеру через порт 8080 работает без каких-либо ошибок. Это подтверждает правильную работу самого контейнера.
-
Проброс портов: Тестирование с использованием
nc -zv localhost 8080
показывает, что порт открыт. Это также указывает на то, что iptables не блокируют подключения. -
Ошибка в конфигурации Apache: Конфигурация Apache кажется корректной и также исключена как источник проблемы.
Решение
При более детальном взгляде на вашу конфигурацию и логирование становится ясным, что вероятная причина заключается в правилах iptables, которые могут блокировать внутренние соединения.
Вы обнаружили, что необходимо добавить следующее правило в iptables:
iptables -A INPUT -p tcp -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
Это правило позволяет внутреннему трафику, связанному с установленными соединениями, проходить, что и решает вашу проблему.
Заключение
Ваш случай демонстрирует важность понимания взаимодействия между разными уровнями сети и программного обеспечения. Несмотря на корректные настройки и открытые порты, изголодавшаяся блокировка может оставить нас в недоумении. Использование правильных правил в iptables обеспечит стабильную работу прокси. В будущем рекомендуется также мониторить логи как Apache, так и Docker для быстрого выявления и устранения проблем.