Как в Django корректно определить IP-адрес и протокол клиента за прокси-сервером

«Как в Django корректно определить IP-адрес и протокол клиента за прокси-сервером» — вопрос из категории Django, который задают на 10% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Когда Django-приложение работает за обратным прокси-сервером (например, Nginx), информация о реальном клиенте (IP-адрес, протокол) передается через HTTP-заголовки. Для корректной обработки этих данных необходимо настроить Django.

Ключевые заголовки:

  • X-Forwarded-For: Содержит исходный IP-адрес клиента.
  • X-Forwarded-Proto: Содержит исходный протокол (http или httpsси).
  • X-Forwarded-Host: Содержит исходное имя хоста, запрошенное клиентом.

Настройка в settings.py:

Чтобы Django доверял этим заголовкам и использовал их для обновления объекта request, необходимо установить следующие параметры:

# settings.py

# Доверяем заголовку X-Forwarded-Proto, который устанавливает прокси-сервер
# Это необходимо, чтобы request.is_secure() возвращал True для HTTPS-запросов
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# Доверяем заголовку X-Forwarded-Host
USE_X_FORWARDED_HOST = True

# Обязательно добавьте доменное имя или IP-адрес вашего прокси в ALLOWED_HOSTS
ALLOWED_HOSTS = ['your-domain.com', 'localhost', '127.0.0.1']

Пример конфигурации Nginx:

Прокси-сервер должен быть настроен для передачи этих заголовков.

location / {
    # Передаем запрос на Gunicorn/uWSGI
    proxy_pass http://unix:/run/gunicorn.sock;

    # Устанавливаем заголовки, которые будет использовать Django
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

После этой настройки request.META['REMOTE_ADDR'] будет содержать реальный IP-адрес клиента, а request.is_secure() будет корректно работать для HTTPS-соединений.