Loading...

Производительность · 9 мин чтения

Reverse proxy: что он делает, как его настроить и когда пора остановиться

Reverse proxy — самый полезный узел в веб-инфраструктуре и самый незаметно неправильно настроенный. В этом руководстве — что это такое, рабочая конфигурация nginx вместе с заголовками, которые все забывают, и честный момент, когда содержать свой собственный обходится дороже, чем отдать эту работу CDN.

Обновлено

Reverse proxy: что он делает, как его настроить и когда пора остановиться

Reverse proxy и forward proxy

Forward proxy работает на клиента. Браузер настроен на его использование, и он забирает интернет от имени браузера — корпоративная фильтрация исходящего трафика, и вообще большая часть того, что люди имеют в виду, когда ищут слово «прокси».

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

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

Что вы реально получаете

Терминация TLS. Сертификаты живут в одном месте, а не на каждом сервере приложения. Продление становится одной задачей вместо многих.

Маршрутизация. Один хост, несколько бэкендов: /api — в сервис на Node, / — в WordPress, /static — в объектное хранилище. Клиент видит один сайт.

Кэширование. Прокси сам отвечает на повторяющиеся запросы. Это самый большой прирост производительности, доступный большинству сайтов, и он же чаще всего остаётся выключенным.

Сжатие. Brotli или gzip применяются один раз на границе вашего стека, а не в каждом приложении.

Rate limiting и фильтрация. Место, где можно применять лимиты и блокировать трафик до того, как он дойдёт до кода, работа которого стоит денег.

Сокрытие origin. Если сервер приложения доступен только от прокси, атакам приходится идти через ту единственную дверь, которую вы контролируете.

Место, где можно менять поведение. Редиректы, переписывание заголовков и страницы обслуживания, не требующие деплоя приложения.

Рабочая конфигурация nginx

Минимум, который действительно работает правильно, — заголовки ниже не опциональное украшение, именно они делают так, чтобы приложение видело клиента, а не прокси:

``` server { listen 443 ssl; server_name example.com;

ssl_certificate /etc/ssl/example.com/fullchain.pem; ssl_certificate_key /etc/ssl/example.com/privkey.pem;

location / { proxy_pass http://127.0.0.1:3000;

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_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } ```

Host — без него бэкенд видит 127.0.0.1, и любой абсолютный URL, который он строит, оказывается неверным.

X-Forwarded-For и X-Real-IP — без них каждый запрос в логе вашего приложения будет приходить от прокси, а любая логика на основе IP молча применяется к прокси вместо посетителя.

X-Forwarded-Proto — без него приложение за терминацией TLS думает, что оно на обычном HTTP, и генерирует ссылки http://, что создаёт петлю редиректов, стоящую всем как минимум одного потерянного дня.

Пара Upgrade — без неё WebSocket не работает, и сбой выглядит как баг приложения, а не прокси.

Кэширование на прокси, коротко

nginx умеет кэшировать ответы апстрима через proxy_cache. Механика довольно простая: объявить путь кэша, включить его в location и решить, что и насколько долго сохранять.

``` proxy_cache_path /var/cache/nginx keys_zone=site:50m max_size=5g inactive=24h;

location / { proxy_cache site; proxy_cache_valid 200 10m; proxy_cache_key "$scheme$request_method$host$request_uri"; add_header X-Cache-Status $upstream_cache_status; proxy_pass http://127.0.0.1:3000; } ```

Помогает это или вредит — решают две вещи.

Ключ кэша. По умолчанию он включает полный URI, поэтому ?utm_source=twitter создаёт отдельную запись от чистого URL. Одна кампания может раздробить ваш кэш на тысячи копий одной и той же страницы и уронить долю попаданий до нуля. Отсекайте параметры, которые не меняют ответ.

Очистка кэша. У open-source nginx нет механизма purge: либо ждать TTL, либо вручную удалять файлы из директории кэша — на каждой машине. Обычно именно в этом месте «мы держим свой собственный прокси» начинает причинять боль, потому что опубликовать исправление и десять минут ждать, пока оно появится, — не тот процесс, который кому-то нравится.

Что на самом деле стоит содержать свой собственный

Один nginx перед одним приложением — это дёшево и совершенно разумно. Цена приходит позже, по частям.

Это одна-единственная машина. Reverse proxy, который является единственным входом, — это и единственная вещь, которая обязана не падать. Сделать его отказоустойчивым — значит завести вторую машину, плавающий адрес или DNS failover и держать идентичный конфиг на обеих.

Сертификаты. Автоматическое продление — решённая задача ровно до того момента, пока хук продления на второй ноде молча не откажет, а вы не узнаете об этом из предупреждения браузера.

Инвалидация кэша между узлами. С двумя прокси у вас два кэша, и очистка означает делать её на обоих, надёжно, прямо из вашего пайплайна деплоя.

Он в одном месте. А ваши посетители — нет. Прокси в одном дата-центре не может быть близко к пользователям в другой стране — это проблема физики, а не конфигурации.

Настройка не заканчивается. Размеры буферов, таймауты, keepalive до апстримов, worker connections — каждая из этих настроек нормальна при вашем текущем трафике и неверна при трафике в десять раз больше.

Когда пора отдать эту работу кому-то ещё

CDN — это reverse proxy, который кто-то другой эксплуатирует сразу во множестве локаций. Функции те же самые — терминация TLS, кэширование, сжатие, фильтрация, маршрутизация, — а различия как раз в тех частях, которые были самыми сложными: география, отказоустойчивость и мгновенная очистка кэша на всех узлах сразу.

Разумная граница такая. Держите свой прокси, пока он делает локальную работу: маршрутизацию между сервисами внутри одной машины или одного кластера, правила, зависящие от внутреннего состояния. Отдавайте публичную сторону, когда ловите себя на решении задач распределения: вторая нода ради отказоустойчивости, очистка кэша сразу на нескольких машинах, посетители в другой стране, ждущие оборота запроса до вас и обратно.

Большинство команд в итоге получают и то и другое, и это разумное устройство: CDN, смотрящий в интернет, и небольшой nginx внутри, который делает маршрутизацию, в которой он хорош. Чего не стоит делать — тратить квартал на то, чтобы плохо пересобрать своими руками то, что CDN даёт вам с первого дня.

Частые вопросы

Reverse proxy — это то же самое, что балансировщик нагрузки?

Они пересекаются. Балансировщик нагрузки распределяет запросы между несколькими бэкендами; reverse proxy вдобавок терминирует TLS, кэширует, переписывает и фильтрует. nginx умеет и то и другое, поэтому термины и используют как взаимозаменяемые. Если единственная задача — раскидывать трафик по идентичным серверам, «балансировщик нагрузки» — более точное слово.

Замедляет ли reverse proxy сайт?

Он добавляет один хоп — единицы миллисекунд, если прокси рядом с origin, — и убирает гораздо больше, когда включено кэширование: закэшированный ответ вообще не доходит до вашего приложения. Вредит это в случае, когда прокси находится в другом регионе и от ваших пользователей, и от вашего origin.

Почему моё приложение видит IP прокси вместо посетителя?

Потому что либо отсутствуют forwarded-заголовки, либо приложение не настроено им доверять. Нужны обе половины: прокси должен отправлять X-Forwarded-For, а фреймворку нужно явно сказать, каким адресам прокси он может верить. Если доверять этому заголовку откуда угодно, клиент сможет подделать собственный IP.

Можно ли кэшировать страницы для залогиненных пользователей?

По умолчанию нет, и обычно этого и не стоит хотеть — именно так один пользователь видит дашборд другого. Обычный паттерн — обходить кэш при наличии cookie сессии и агрессивно кэшировать для анонимных посетителей, которые составляют основную массу трафика большинства сайтов.

Как очистить кэш прокси nginx?

У open-source nginx нет директивы purge. Варианты — удалить нужные файлы из директории кэша на каждой ноде, использовать сторонний модуль purge или подождать TTL. Очистка кэша по требованию сразу на всех машинах — одна из конкретных вещей, которые вы получаете, перенося слой кэширования в CDN.