0

Nginx proxy_pass

10.11.2023

Рассмотрим самый простой пример. Буду использовать свой технический домен site.ru в этом и последующих примерах. Допустим, у нас есть сайт test.site.ru. В DNS создана A запись, указывающая на ip адрес сервера, где установлен nginx – nginx_srv. Мы будем проксировать все запросы с этого сервера на другой сервер в локальной сети test_srv, где реально размещается сайт.

Рисуем конфиг для секции server:

server {
    listen 80;
    server_name test.site.ru;
    access_log /var/log/nginx/test.site.ru-access.log;
    error_log /var/log/nginx/test.site.ru-error.log;

location / {
    proxy_pass http://x.x.x.x; # ip локального сервера
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;
    }
}

Заходим по адресу http://test.site.ru. Мы должны попасть на test_srv, где тоже должен работать какой-то веб сервер. В моем случае это будет тоже nginx. У вас должно открыться содержимое, аналогичное тому, что вы увидите, набрав http://x.x.x.x в локальной сети. Если что-то не работает, то проверьте сначала, что по адресу директивы proxy_pass у вас все корректно работает.

Директива php REMOTE_ADDR не будет возвращать настоящий ip адрес клиента. А он очень часто бывает нужен. Мы это дальше исправим.

Передача реального ip (real ip) адреса клиента в nginx при proxy_pass

В предыдущем примере мы на самом деле передаем реальный ip адрес клиента с помощью директивы proxy_set_header, которая добавляет в заголовок X-Real-IP настоящий ip адрес клиента. Теперь нам нужно на принимающей стороне, то есть test_srv сделать обратную замену – заменить информацию об адресе отправителя на ту, что указана в заголовке X-Real-IP. Добавляем в секцию server следующие параметры:

set_real_ip_from (внешний IP);
real_ip_header X-Real-IP;

Полностью секция server на test_srv в самом простом варианте получается следующей:

server {
	listen       80 default_server;
	server_name  test.site.ru;
	root         /usr/share/nginx/html;
	set_real_ip_from (внешний IP);
	real_ip_header X-Real-IP;
        
    location / {
	index index.php index.html index.htm;
	try_files	$uri $uri/	=404;
	}

    location ~ \.php$ {
	fastcgi_pass   127.0.0.1:9000;
	fastcgi_index  index.php;
	fastcgi_intercept_errors on; 
	include fastcgi_params;
	fastcgi_param       SCRIPT_FILENAME  $document_root$fastcgi_script_name;
	fastcgi_ignore_client_abort     off;
	}

    error_page 404 /404.html;
	location = /40x.html {
    }

    error_page 500 502 503 504 /50x.html;
	location = /50x.html {
    }
}

Сохраняем конфиг, перечитываем его и снова проверяем. В логах вы должны увидеть свой реальный ip адрес. Его же вы увидите в логе web сервера на test_srv.

Дальше рассмотрим более сложные конфигурации.

Передача https через nginx с помощью proxy pass

Если у вас сайт работает по https, то достаточно настроить ssl только на nginx_srv, если вы не беспокоитесь за передачу информации от nginx_srv к test_srv. Она может осуществляться по незащищенному протоколу. Рассмотрю пример с бесплатным сертификатом let’s encrypt. Это как раз один из кейсов, когда я использую proxy_pass. Очень удобно настроить на одном сервере автоматическое получение всех необходимых сертификатов. Подробно настройку let’s encrypt я рассматривал отдельно. Сейчас будем считать, что у вас стоит certbot и все готово для нового сертификата, который потом будет автоматически обновляться.

Для этого нам надо на nginx_srv добавить еще один location – /.well-known/acme-challenge/. Полная секция server нашего тестового сайта на момент получения сертификата будет выглядеть вот так:

server {
    listen 80;
    server_name test.site.ru;
    access_log /var/log/nginx/test.site.ru-access.log;
    error_log /var/log/nginx/test.site.ru-error.log;

    location /.well-known/acme-challenge/ {
	root /web/sites/test.site.ru/www/;
    }

    location / {
	proxy_pass http://x.x.x.x;    
	proxy_set_header Host $host;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_set_header X-Real-IP $remote_addr;
    }
}

Перечитывайте конфиг nginx и получайте сертификат. После этого конфиг меняется на следующий:

server {
    listen 80;
    server_name test.site.ru;
    access_log /var/log/nginx/test.site.ru-access.log;
    error_log /var/log/nginx/test.site.ru-error.log;
    return 301 https://$server_name$request_uri; # редирект обычных запросов на https
    }

server {
    listen 443 ssl http2;
    server_name test.site.ru;
    access_log /var/log/nginx/test.site.ru-ssl-access.log;
    error_log /var/log/nginx/test.site.ru-ssl-error.log;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/test.site.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/test.site.ru/privkey.pem;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;

    location /.well-known/acme-challenge/ {
	root /web/sites/test.site.ru/www/;
    }
    location / {
	proxy_pass http://x.x.x.x; 
	proxy_set_header Host $host;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_set_header X-Real-IP $remote_addr;
    }
}

Проверяем, что получилось. Видим успешное применение SSL ввиде зеленого замка.

Наш сайт работает по https, при том, что мы вообще не трогали сервер, где этот сайт располагается. Конкретно с web сайтом это может быть не так актуально, но если вы проксируете запросы не на обычный сайт, а на какой-то нестандартный сервис, который трудно перевести на https, это может быть хорошим решением.

Проксирование определенной директории или файлов

Рассмотрим еще один пример. Допустим, у вас форум живет в директории http://test.site.ru/forum/, вы хотите вынести форум на отдельный web сервер для увеличения быстродействия. Для этого к предыдущему конфигу добавьте еще один location.

location /forum/ {
	proxy_pass http://x.x.x.x; 
	proxy_set_header Host $host;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_set_header X-Real-IP $remote_addr;
        proxy_redirect default;
	}

Еще одно популярное решение. Вы можете отдавать картинки с одного сервера, а все остальное с другого. В моем примере, картинки будут жить на том же сервере, где nginx, а остальной сайт на другом сервере. Тогда у нас должна быть примерно такая конфигурация локаций.

location / {
	proxy_pass http://x.x.x.x; 
	proxy_set_header Host $host;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_set_header X-Real-IP $remote_addr;
	}

location ~ \.(gif|jpg|png)$ {
	root /web/sites/test.site.ru/www/images;
	}

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

Существует очень много директив для управления прокси-соединениями. Все они описаны в соответствующей документации nginx. Я не большой специалист по настройке nginx. В основном использую свои готовые конфиги, зачастую даже не вникая в суть, если получается сразу решить задачу. Подсматриваю что-то у других, записываю к себе, стараюсь разобраться.

Особое внимание следует уделить директивам кэширования proxy_cache, если в этом есть потребность. Можно существенно увеличить отклик веб сайта, если подходящим образом настроить отдачу кэша. Но это тонкий момент и нужно настраивать в каждом конкретном случае отдельно. Готовых рецептов тут не бывает.

Более подробно о комплексной настройке nginx читайте в отдельной большой статье с моими личными примерами.

Часто задаваемые вопросы по теме статьи (FAQ)

При использовании https нужно ли в режиме proxy_pass настраивать https и на бэкенде?

В общем случае не обязательно. Но есть некоторый софт, который не может корректно работать в таком режиме. Он не понимает, как корректно обрабатывать такую ситуацию. Может создавать ссылки вида http://site.ru:443, которые будут являться ошибочными. В таком случае необходимо настроить обмен между nginx и бэк сервером тоже https соединение.

Как наиболее простым спосбом передавать сертификат let’s encrypt с nginx на backend? Ведь обновдление и генерация сертификата происходят только на nginx.

Я в таких случаях использую 2 способа, в зависимости от ситуации. Самый простой – на сервере с nginx настроить nfs сервер, а на бэкенде подмонтировать по nfs к себе директорию /etc/letsencrypt и спокойно использовать сертификаты, как-будто они лежат локально. Второй вариант – использовать простой bash скрипт для копирования сертификатов к себе на сервер по scp. В обоих случаях надо не забыть на бэкенде перезапускать службы, которые использую сертификат, после его обновления.

При обращении с бэкенда по адресу сайта, запрос уходит на nginx proxy, так как в dns прописан его ip адрес. Из-за этого иногда не работают встроенные скрипты или проверки некоторых движков, так как они ожидают, что запрос вернется с того же сервера, с которого он был сделан. Но на практике он уходит на proxy и приходит оттуда.

В такой ситуации может помочь правка файла /etc/hosts на самом бэкенде. Сделайте там статическую запись с именем сайта и локальным ip адресом. Тогда запросы с самого сервера будут приходить на него же локально, а не на nginx proxy.

Что лучше использовать для проксирования http запросов nginx или haproxy?

Однозначного ответа на этот вопрос не может быть. В чем-то это схожий софт, но есть и существенные отличия. В общем случае, описанном в статье, принципиальной разницы нет. У haproxy в бесплатной версии есть функционал, который присутсвует только в nginx plus. Так что нужно смотреть по конкретным задачам и решать, какой продукт подойдет лучше.

Добавляет ли nginx в режиме proxy_pass дополнительные сетевые задержки?

Конечно да. Но на практике они очень малы, если nginx и целевой сервер находятся в общей локальной сети. С учетом задержек при передачи пакетов по сети интернет, этими локальными задержками можно пренебречь. Они будут ничтожно малы. Если же вы проксируете запросы через интернет, то нужно внимательно смотреть величину задержек между nginx и бэкендом. Желательно их делать минимальными, располагая сервера поближе друг к другу.

источник

Свежие комментарии

Подписка

Лучшие статьи

Рубрики

Популярное

Обратный SSL-прокси к 1С

Большое значение имеет шифрование при обмене информацией через интернет, особенно таких чувствительных данных, как логин и пароль. Если для работы применяется веб-публикация

Nginx Proxy Manager

В одной из прошлых статей мы разобрали как установить и настроить реверс прокси Traefik. В данной статье мы разберемся как установить и настроить
Previous Story

Построение отказоустойчивого кластера PostgreSQL. Настройка внешней синхронизации на PostgreSQL для механизма копий баз данных.

Next Story

HotSpot настройка

Latest from Blog

Настройка простого беспроводного репитера на устройстве MikroTik

При развертывании беспроводных сетей достаточно часто возникают ситуации, когда в некоторых местах квартиры или офиса мощность Wi-Fi сигнала недостаточна для уверенной работы. Конечно, наиболее действенным решением является создание централизованно управляемой сети и

Настройка и использование Redis

В этой статье мы расскажем что такое Redis, его преимущества и для каких целей он используется. Redis (REmote DIctionary Server) — сетевое журналируемое хранилище данных типа “ключ” — “значение” с открытым исходным кодом. По сути Redis представляет собой базу данных

Настройка и использование Memcached

В статье мы расскажем, что такое Memcache, зачем он нужен и как он влияет на работу некоторых популярных CMS. Кеширование данных – немаловажный момент в работе любого веб-проекта. С ростом посещаемости увеличиваются требования к

Как настроить логирование и ротацию логов Nginx

Вовремя настроенное журналирование позволяет в дальнейшем избежать неожиданных проблем с веб-сервером. Информация, хранящаяся в логах (или журналах) сервера, помогает быстро оценить ситуацию и устранить ошибки. В этой статье мы рассмотрим возможности логирования

Распределение выполнения запросов внутри приватной сети VPS через HAProxy

Приватную сеть можно использовать для распределения выполнения загрузки и балансировки запросов между несколькими серверами. Рассмотрим организацию такой балансировки на примере HAProxy – бесплатного ПО, предназначенного для распределения нагрузки и организации проксирования TCP-пакетов между несколькими обслуживающими
Go toTop

Don't Miss

Nginx Proxy Manager

В одной из прошлых статей мы разобрали как установить и

Обратный SSL-прокси к 1С

Большое значение имеет шифрование при обмене информацией через интернет, особенно