Как получить реальный IP-адрес клиента на сервере пирамиды за прокси-сервером nginx
У меня есть приложение Pyramid, которое использует request.environ['REMOTE_ADDR']
в некоторых местах.
Приложение обслуживается Python Paste на порту 6543, и сервер nginx, прослушивающий порт 80, пересылает запросы на сервер Paste.
Конфигурация nginx основана на кулинарной книге Pyramid:
server {
listen 80; ## listen for ipv4
listen [::]:80 default ipv6only=on; ## listen for ipv6
server_name localhost;
access_log /var/log/nginx/localhost.access.log;
location / {
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;
proxy_pass http://127.0.0.1:6543;
}
В приложении Pyramid переменная request.environ['REMOTE_ADDR'] теперь всегда равна 127.0.0.1. Я вижу несколько стратегий для решения этой проблемы, но я не знаю, есть ли рекомендуемый способ сделать это.
Вот что я рассматриваю:
добавьте подписчика NewRequest, который заменяет request.environ['REMOTE_ADDR'] при необходимости:
if 'HTTP_X_REAL_IP' in event.request.environ: event.request.environ['REMOTE_ADDR'] = event.request.environ['HTTP_X_REAL_IP']
используйте промежуточное программное обеспечение wsgi для изменения request.environ перед попаданием на слой Pyramid.
что-то другое
Какую стратегию вы используете для развертывания приложений Pyramid? Что произойдет, если у меня будет два прокси nginx? (первый обслуживает локальную сеть, а второй - компьютер, напрямую подключенный к Интернету).
4 ответа
Если вы используете paste.deploy.config.PrefixMiddleware
в вашем трубопроводе WSGI через use = egg:PasteDeploy#prefix
, он автоматически переведет X-Forwarded-For
в REMOTE_ADDR
, Это также отлично подходит для других свойств вашего обратного прокси, например, он будет переводить X-Forwarded-Proto
в wsgi.url_scheme
чтобы убедиться, что если пользователь заходит с https, то сгенерированные URL-адреса также будут https.
http://pythonpaste.org/deploy/class-paste.deploy.config.PrefixMiddleware.html
Я использую Gevent Server за Nginx, и я использую request.client_addr
получить IP-адрес клиента.
Если у вас нет трубопровода WSGI или вы не хотите использовать paste
Затем добавьте обработчик событий:
config.add_subscriber(reverseProxyProtocolCorrection,'pyramid.events.NewRequest')
Обработчик события может читать как:
def reverseProxyProtocolCorrection(event):
event.request.scheme = 'https' if event.request.headers['X-Forwarded-Proto']=='https' else 'http'
event.request.remote_addr=parseXForward(event.request.headers['X-Forwarded-For'],event.request.remote_addr)
и убедитесь, что ваш прокси установил заголовки
В nginx:
location / {
proxy_pass http://yourapp;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
}
в php я делаю:
if($_SERVER["HTTP_X_FORWARDED_FOR"]){
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
}else{
$ip = $_SERVER["REMOTE_ADDR"];
}
возможно в python похоже, $ip это твой реальный ip