Проблема
Когда общедоступное имя хоста, которое вы используете для доступа к прокси, отличается от внутреннего имени хоста сервера приложений, Django не может узнать, какое имя хоста использовалось в исходном запросе, если прокси не проходитвместе с этой информацией.
Возможные решения
1) Установите прокси-сервер для прохождения по оригинальному хосту
От MDN :
Заголовок X-Forwarded-Host (XFH) является де-факто стандартным заголовком для идентификации исходного хоста, запрошенного клиентом в заголовке HTTP-запроса хоста.
Имена хостов и порты обратных прокси (балансировщики нагрузки (CDN) могут отличаться от исходного сервера, обрабатывающего запрос, в этом случае заголовок X-Forwarded-Host полезен для определения того, какой хост был изначально использован.
Есть две вещи, которые вам следуетdo:
- убедитесь, что все прокси перед Django проходят вдоль
X-Forwarded-Host
header - включите
USE_X_FORWARDED_HOST
в настройках - есливнутренняя и внешняя схемы также различаются, установите
SECURE_PROXY_SSL_HEADER
в значащее значение и настройте сервер на отправку соответствующего заголовка
Когда USE_X_FORWARDED_HOST
установлено в True
в settings.py
,HttpRequest.build_absolute_uri
использует заголовок X-Forwarded-Host
вместо request.META['HTTP_HOST']
или request.META['SERVER_NAME']
.
Я не буду слишком углубляться в настройку прокси-сервера (поскольку это больше относится к профессиональному сетевому администрированию, чем к программированию наобласть действия этого сайта), но для nginx это должно быть что-то вроде:
location / {
...
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
...
proxy_pass http://upstream:port;
}
Вероятно, лучшее решение, так как оно полностью динамическое, вам не нужно ничего менять, если изменяется публичная схема / имя хоста вбудущее.
Если внутренняя и внешняя схемы также различаются, вы можете установить SECURE_PROXY_SSL_HEADER
в settings.py
примерно так:
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
А затем добавить следующее кконфигурация сервера:
Forwarded-Proto: https;
2) Использовать одно и то же имя хоста для публичных и частных серверов
Допустим, ваше общедоступное имя хоста - "host.example.com": вы можете добавить строку вродеэто к вашему /etc/hosts
(в Windows %windir%\System32\drivers\etc\hosts
):
127.0.0.1 host.example.com
Теперь вы можете использовать имя хоста в конфигурации nginx:
proxy_pass http://host.example.com:port;
Когда внутренняя и внешняя схемы также различаются (внешние https(внутренний http), вы можете установить SECURE_PROXY_SSL_HEADER
, как описано в первом решении.
Каждый раз, когда изменяется публичное имя хоста, вам придется обновлять конфигурацию, но я думаю, что это нормально для небольших проектов.