Django ОШИБКА: неверный заголовок HTTP_HOST: u'/run/myprojectname/gunicorn.sock:'
Я знаю, что таких вопросов много на SO, но ни один из них не отвечает на мою конкретную проблему.
Я понимаю, что Джанго ALLOWED_HOSTS
значение блокирует любые запросы к порту 80
на мой IP, которые не приходят с соответствующими Host:
значение, и что когда приходит запрос, который не имеет правильного значения, Django отправляет мне электронное письмо. Я также знаю о хитром взломе Nginx, чтобы решить эту проблему, но я пытаюсь понять природу одного такого запроса и определить, является ли это проблемой безопасности, о которой мне нужно беспокоиться.
Такие запросы имеют смысл:
[Django] ERROR: Invalid HTTP_HOST header: '203.0.113.1'. You may need to add u'203.0.113.1' to ALLOWED_HOSTS.
Но этот вид меня бесит:
[Django] ERROR: Invalid HTTP_HOST header: u'/run/my_project_name/gunicorn.sock:'.
Не означает ли это, что отправитель Host: /run/my_project_name/gunicorn.sock
на сервер? Если это так, как они имеют путь к моему .sock
файл? Мой сервер как-то пропускает эту информацию?
Кроме того, так как я использую Django 1.6.5, я не понимаю, почему я получаю эти электронные письма вообще, так как этот билет был помечен как исправленный в течение некоторого времени.
Может кто-нибудь пролить свет на то, что мне не хватает?
Это мое settings.LOGGING
переменная:
{
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse'}
},
'formatters': {
'simple': {'format': '%(levelname)s %(message)s'},
'verbose': {'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'}
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'verbose',
'level': 'DEBUG'
},
'mail_admins': {
'class': 'django.utils.log.AdminEmailHandler',
'filters': ['require_debug_false'],
'level': 'ERROR'
}
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True
},
'my_project_name': {
'handlers': ['console'],
'level': 'DEBUG'
}
},
'version': 1
}
А вот мой конфиг nginx:
worker_processes 1;
pid /run/nginx.pid;
error_log /var/log/myprojectname/nginx.error.log debug;
events {
}
http {
include mime.types;
default_type application/octet-stream;
access_log /var/log/myprojectname/nginx.access.log combined;
sendfile on;
gzip on;
gzip_http_version 1.0;
gzip_proxied any;
gzip_min_length 500;
gzip_disable "MSIE [1-6]\.";
gzip_types text/plain text/html text/xml text/css
text/comma-separated-values
text/javascript application/x-javascript
application/atom+xml;
upstream app_server {
server unix:/run/myprojectname/gunicorn.sock fail_timeout=0;
}
server {
listen 80 default;
listen [::]:80 default;
client_max_body_size 4G;
server_name myprojectname.mydomain.tld;
keepalive_timeout 5;
root /var/www/myprojectname;
location / {
try_files $uri @proxy_to_app;
}
location @proxy_to_app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
proxy_pass http://app_server;
}
error_page 500 502 503 504 /500.html;
location = /500.html {
root /tmp;
}
}
}
Наконец, я нашел это в моем журнале доступа nginx. Это соответствует электронным письмам, которые приходят с жалобой на то, что /run/myprojectname/gunicorn.sock является недействительным заголовком HTTP_HOST.*
Все это было в одной строке, конечно:
2014/09/05 20:38:56 [info] 12501#0: *513 epoll_wait() reported that client
prematurely closed connection, so upstream connection is closed too while sending
request to upstream, client: 54.84.192.68, server: myproject.mydomain.tld, request:
"HEAD / HTTP/1.0", upstream: "http://unix:/run/myprojectname/gunicorn.sock:/"
Очевидно, я все еще не знаю, что это значит, хотя:-(
- Обновление № 1: добавил мой
settings.LOGGING
- Обновление № 2: Добавлен мой конфиг nginx
- Обновление № 3: Добавлена интересная строка из моего журнала nginx.
- Обновление № 4: Обновлен мой конфиг nginx
3 ответа
Похоже на
proxy_set_header Host $http_host
proxy_set_header Host $host
а также server_name
должен быть установлен соответственно на адрес, используемый для доступа к серверу. Если вы хотите, чтобы он все поймал, вы должны использовать server_name www.domainname.com ""
( документ здесь).
Я не уверен, но я думаю, что то, что вы видите, происходит, если клиент не отправляет Host:
заголовок. Поскольку nginx не получает Host:
заголовок, нет Host:
Заголовок передается в Gunicorn. На данный момент, я думаю, что Gunicorn заполняет Host:
как путь к сокету и говорит Django об этом, так как это соединение используется. С помощью $host
и настройка server_name
в Nginx должен обеспечить Host:
правильно передан Gunicorn и исправить эту проблему.
Что касается электронной почты, то в соответствии с коммитом в тикете, который вы связали, похоже, что электронные письма по-прежнему отправляются запрещенным хостам. В документ также был добавлен способ отключения отправляемых писем:
'loggers': {
'django.security.DisallowedHost': {
'handlers': ['null'],
'propagate': False,
},
Я сталкивался с некоторыми комментариями, которые предполагают, что подавление электронных писем не является хорошей идеей, потому что это непосредственно не решает проблему. Самое эффективное решение, которое я нашел, это добавить следующее в ваши настройки nginx:
server {
...
## Deny illegal Host headers
if ($host !~* ^(mydomain.com|www.mydomain.com)$ ) {
return 444;
}
}
Для получения дополнительной информации: https://snakeycode.wordpress.com/2015/05/31/django-error-invalid-http_host-header/
В блоге упоминается этот вопрос.
Я знаю, что это старый вопрос, но проблема произошла со мной только сегодня. Рекомендуемое решение для документации Django состоит в том, чтобы добавить сервер nginx "перехватить все" в вашей конфигурации nginx:
server {
listen 80 default_server;
return 444;
}
Официальные документы nginx рекомендуют то же решение, дают или принимают некоторые синтаксические нюансы.
Таким образом, запрос не переходит к django, соединение немедленно закрывается, когда nginx получает некорректный запрос.