Вопрос или проблема
Я пытаюсь настроить виртуальный хост для работы с прокси, но только если запрос не предназначен для статического файла – в этом случае я хотел бы, чтобы Apache его обслуживал. Вот что я использую:
<VirtualHost *:80>
ServerName app.local
DocumentRoot "/app/static"
# Обслуживание статических файлов
<Directory "/app/static">
Require all granted
Options Indexes FollowSymLinks
AllowOverride None
</Directory>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/(.*) http://localhost:8000/$1 [P,L,QSA]
ProxyPreserveHost On
ProxyPass / http://localhost:8000/
ProxyPassReverse / http://localhost:8000/
</VirtualHost>
Тем не менее, если я пытаюсь получить app.local/style.css
, этот запрос все равно перенаправляется (я вижу это в логе прокси-сервера), несмотря на то, что файл /app/static/style.css
существует. Как мне сделать так, чтобы эти файлы обслуживались?
RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^/(.*) http://localhost:8000/$1 [P,L,QSA]
Когда вы используете директивы mod_rewrite в контексте виртуального хоста, они обрабатываются до того, как запрос был сопоставлен с файловой системой. Следовательно, переменная сервера REQUEST_FILENAME
еще не была оценена и просто содержит корневой относительный путь URL, а не абсолютный путь к файлу. Поэтому условие в вашем первом правиле всегда будет выполняться неудачно, а отрицательное условие выше будет всегда успешным (если только у вас случайно нет абсолютного пути к файлу, который совпадает с путем URL – маловероятно).
Вместо этого вы можете использовать предвосхищение (например, %{LA-U:REQUEST_FILENAME}
) или вручную сконструировать абсолютное имя файла, используя переменные сервера DOCUMENT_ROOT
и REQUEST_URI
(путь URL). Например:
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule ^/(.*) http://localhost:8000/$1 [P]
Кстати, вам не нужно ваше первое правило, когда у вас есть второе, поскольку они взаимоисключают друг друга.
Флаги L
и QSA
также избыточны здесь, поскольку P
подразумевает L
, а строка запроса автоматически добавляется, когда вы явно не включаете строку запроса в замену.
ProxyPass / http://localhost:8000/
Вам также следует удалить директиву ProxyPass
, поскольку это приведет к тому, что каждый URL будет проксироваться. Вы используете mod_rewrite (с флагом P
) вместо этого, чтобы проксировать запрос.
Ответ или решение
Конфигурация виртуального хоста Apache для обслуживания статических файлов с последующим проксированием запросов, если файлы не найдены, представляет собой типичный сценарий, который может быть использован для повышения производительности веб-сайта. Ниже рассмотрим, как корректно настроить Apache для выполнения этой задачи.
Теория
Основная идея настройки заключается в том, чтобы отделить обработку статических файлов от динамических запросов. Статические файлы, такие как изображения, стили CSS и скрипты JavaScript, могут быть обслужены непосредственно Apache, что гораздо быстрее, чем проксирование через обратный прокси-сервер. Если запрашиваемый файл не является статическим или вообще отсутствует, запрос должен быть перенаправлен на backend сервер через прокси.
Чтобы реализовать это в Apache, настраиваются модули mod_rewrite
и mod_proxy
. Использование модуля mod_rewrite
позволяет задавать условия и правила для маршрутизации URI, основываясь на наличию запрашиваемого файла в файловой системе. Модуль mod_proxy
, в свою очередь, используемый для перенаправления запросов на другой сервер, позволяет реализовать проксирование.
Пример
Рассмотрим предоставленный конфигурационный файл Apache:
<VirtualHost *:80>
ServerName app.local
DocumentRoot "/app/static"
# Serve static files
<Directory "/app/static">
Require all granted
Options Indexes FollowSymLinks
AllowOverride None
</Directory>
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f
RewriteRule ^ - [L]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule ^/(.*) http://localhost:8000/$1 [P]
ProxyPreserveHost On
</VirtualHost>
Применение
-
Настройка DocumentRoot и Directory: Убедитесь, что
DocumentRoot
указывает на корневой каталог статических файлов, а директива<Directory>
настроена на предоставление доступа к этому каталогу. Эти настройки гарантируют, что Apache будет искать файлы в указанной директории. -
Использование mod_rewrite:
- Включите
mod_rewrite
с помощьюRewriteEngine On
. - Первое RewriteCond проверяет, существует ли файл на диске, используя комбинацию
%{DOCUMENT_ROOT}
и%{REQUEST_URI}
. Условие-f
проверяет наличие файла. - Если файл существует, правило
RewriteRule ^ - [L]
останавливает дальнейшую обработку правил, возвратив управление Apache для обслуживания файла. - Второе RewriteCond проверяет отсутствие файла. Если файл не найден, правило
RewriteRule ^/(.*) http://localhost:8000/$1 [P]
перенаправляет запрос на backend сервер через прокси. ФлагP
указывает на выполнение проксирования.
- Включите
-
Удаление избыточных директив: Убедитесь, что
ProxyPass
директивы удалены, так как использованиеmod_rewrite
с флагомP
для проксирования является достаточным и более гибким. -
Оптимизация и наладка: После настройки необходимо протестировать конфигурацию, чтобы убедиться, что статические файлы обслуживаются корректно. Используйте инструменты журналирования Apache и proxy-сервера для диагностики возможных проблем.
Таким образом, данная конфигурация позволяет эффективно разделять обработку статических и динамических запросов, обеспечивая быструю доставку статического контента и корректное проксирование остальных запросов. Кроме того, это способствует уменьшению нагрузки на сервер приложений, поскольку статические файлы не требуют его участия. В конечном итоге, такая настройка улучшает производительность веб-приложения и его отклик для конечных пользователей.