gunicorn через mod_proxy перенаправляется за пределы проекта, несмотря на ProxyPassReverse

У меня есть WSGI-приложение (проект Django), работающее под gunicorn на 127.0.0.1:18731, и я использую Apache с mod_proxy для перенаправления запросов с http://example.com/my-project/* на http://127.0.0.1:18731/*. Статические файлы хранятся вне /my-project/. Если приложению Django не нужно ничего перенаправлять, это работает нормально, но если оно попытается перенаправить запрос (например, добавить завершающую косую черту к http://example.com/my-project/foo), оно в конечном итоге удалит /my-project/ из URL-адреса, оставив мне недействительный URL-адрес. http://example.com/foo/.

Моя конфигурация mod_proxy выглядит следующим образом:

<Proxy *>
    Order deny,allow
    Allow from all
</Proxy>
ProxyRequests On
ProxyPass /my-project/ http://127.0.0.1:18731/ retry=0
ProxyPassReverse /my-project/ http://127.0.0.1:18731/ retry=0
ProxyPreserveHost On
ProxyErrorOverride Off

Я не хочу заставлять Django добавлять префикс /my-project/ ко всем своим URL-адресам в интересах переносимости. Очевидно, Apache должен обрабатывать префикс самостоятельно с помощью строки ProxyPassReverse. Что я делаю неправильно?


person ashastral    schedule 20.06.2011    source источник
comment
Я решил переключиться на nginx, так как не мог найти решение проблемы Apache ProxyPassReverse в течение нескольких дней после обращения на несколько справочных сайтов. Не говоря уже о различных других проблемах, которые у меня были с Apache за последний год. Проблему также можно решить созданием отдельного виртуального хоста только для проксируемого сервера, но лично меня это решение не устраивает. Тем не менее, я бы порекомендовал сначала попробовать ответ Криса. Я лично не тестировал его. но его рассуждения верны (хотя для меня они опоздали на несколько месяцев).   -  person ashastral    schedule 24.06.2011


Ответы (3)


У меня была эта проблема.

ProxyPreserveHost On

<Location "/my-project/">
    ProxyPass http://127.0.0.1:18173/my-project/
    ProxyPassReverse http://127.0.0.1:18173/my-project/
    RequestHeader set SCRIPT_NAME /my-project
    RequestHeader set X-FORWARDED-PROTOCOL ssl
    RequestHeader set X-FORWARDED-SSL on
</Location>

Чтобы приложение WSGI могло создать абсолютный URL-адрес, нам нужно:

  • ProxyPreserveHost On, поэтому заголовок Host: передается, и приложение знает имя хоста, на котором нас видит клиент.
  • Добавьте заголовок SCRIPT_NAME, чтобы приложение знало, где находится его корень.
  • Установите заголовки X-FORWARDED- по мере необходимости. Я тоже использую ssl, поэтому я должен сказать приложению, что оно должно использовать схему https.

Я использую директивы <Location>, потому что я делаю намного больше на этот вхост. Но вы можете легко переписать это, передав path аргументов в ProxyPass. и директивы ProxyPassReverse.

NB: ProxyRequests должно быть Выкл. , если только вам не нужен прямой прокси-сервер. Если вы читаете это, вам, вероятно, нужен только обратный прокси.

Специальное примечание Django: settings.LOGIN_URL используется как есть, поэтому вам нужно будет добавить к нему SCRIPT_NAME самостоятельно.

person Chris Wesseling    schedule 20.10.2011

Вы пробовали это? Я также добавил свой проект к URL-адресу, который вы проксируете.

<Proxy *>
    Order deny,allow
    Allow from all
</Proxy>
ProxyRequests On
ProxyPass /my-project/ http://127.0.0.1:18731/my-project/ retry=0
ProxyPassReverse /my-project/ http://127.0.0.1:18731/my-project/ retry=0
ProxyPreserveHost On
ProxyErrorOverride Off

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

Обновление: описанное выше не сработало, попробуйте что-нибудь другое.

Попробуйте что-то вроде этого и посмотрите, поможет ли это. Он устроен немного иначе. Он проксирует все, кроме мультимедиа, которое обслуживается через псевдоним. Это устраняет необходимость иметь /my-project/ вообще.

<VirtualHost *:80>
ServerName example.com
UseCanonicalName On
ServerAdmin webmaster@localhost

LogLevel warn
CustomLog /var/log/apache2/example.com/access.log combined
ErrorLog /var/log/apache2/example.com/error.log
ServerSignature On

Alias /media/ /home/example/example.com/pysrc/project/media/

ProxyPass /media/ !
ProxyPass / http://127.0.0.1:18731/
ProxyPassReverse / http://127.0.0.1:18731/
ProxyPreserveHost On
ProxyErrorOverride Off
</VirtualHost>
person Ken Cochrane    schedule 21.06.2011
comment
Это не работает. Django ожидает запросов, например. /foo/, а не /my-project/foo/, поэтому ProxyPass должен быть корректным. Изменение ProxyPassReverse никак не влияет на мою сторону, что заставляет меня думать, что он вообще не используется. - person ashastral; 21.06.2011
comment
Обновил мой ответ другим вариантом, посмотрите, поможет ли это. - person Ken Cochrane; 21.06.2011
comment
Также обратите внимание, что proxyrequests отсутствует, что означает, что по умолчанию он будет отключен, что обычно используется для обратных прокси. Еще одна настройка, с которой можно поиграться, если она не работает, — это proxypreservehost. - person Ken Cochrane; 21.06.2011
comment
Ваш другой вариант действительно сработает, но веб-сайт, над которым я работаю, имеет контент, отличный от сайта gunicorn/Django, в корневом каталоге, поэтому мне нужно иметь возможность разместить прокси-сервер в своем собственном пространстве. Я полагаю, что мог бы просто создать новый хост для проекта, но я все еще хочу знать, почему ProxyPassReverse терпит неудачу. - person ashastral; 21.06.2011
comment
вы также можете настроить поддомен для другого варианта. Вы пытались изменить proxyrequests или proxyprservehost на другие значения, чтобы увидеть, не в этом ли проблемы? - person Ken Cochrane; 21.06.2011
comment
Я действительно пытался изменить оба этих значения. И создание другого поддомена — это то, что я имел в виду под созданием нового хоста. Я, вероятно, пока выберу это решение, и если кто-то еще попытается использовать мое приложение в подкаталоге, это будет их проблема, а не моя. :) - person ashastral; 22.06.2011
comment
Вы пробовали использовать nginx в качестве обратного прокси вместо apache? Это то, что я использую, и это легкий, быстрый и простой в настройке. - person Ken Cochrane; 22.06.2011

Я решил исходную проблему, задав в конфигурации ProxyPassReverse фактическое доменное имя:

ProxyPass /my-project/ http://127.0.0.1:18731/
ProxyPassReverse /my-project/ http://mydomain.com/

Подсказка: значения Apache ProxyPassReverse

person alexef    schedule 21.03.2013