Nginx как API-gateway и Kubernetes Gateway API

Рейтинг: 64.6% · 12 голосов
Самый подробный курс по Nginx - от первого конфига до production API-gateway. Архитектура и event loop, контексты и location, виртуальные хосты, статика, reverse proxy и upstream-балансировка, кэширование, HTTPS и TLS (post-quantum), HTTP/2 и HTTP/3 QUIC, безопасность и rate limiting, realip, JSON-логи и сквозная трассировка, метрики, тюнинг и траблшутинг. Плюс OpenResty (Lua, фазы, JWT, динамика) и Angie (нативные Prometheus, ACME, dynamic upstream). На основе эталонного gateway и лучших практик. Для новичков и SRE/DevOps. Актуально на 2026 (nginx 1.30/1.31, Angie, ingress-nginx EOL -> Gateway API).
Ответить
Аватара пользователя
Igor_NgINX
Сообщения: 44
Зарегистрирован: 11 май 2026, 05:31

Nginx как API-gateway и Kubernetes Gateway API

Сообщение Igor_NgINX »

Оглавление курса (44)
  1. Что такое Nginx и почему он захватил веб
  2. Установка Nginx, Angie и OpenResty: пакеты, версии, Docker
  3. Первый конфиг с нуля: минимальный сервер за 5 минут
  4. Архитектура процессов: master, worker и event loop
  5. Анатомия конфигурации: контексты, наследование и модульность
  6. Виртуальные хосты: server и server_name
  7. Директива location: матчинг и приоритеты по шагам
  8. Раздача статики: root, alias, try_files, sendfile
  9. Переменные, map и блок if
  10. rewrite, return и канонизация URL
  11. Работа с заголовками: add_header и proxy_set_header
  12. Модель доверия прокси-заголовков: realip и защита от спуфинга
  13. Сжатие: gzip, brotli и zstd
  14. Reverse proxy: proxy_pass и проброс запроса
  15. upstream и балансировка нагрузки
  16. Таймауты, повторы и устойчивость прокси
  17. FastCGI и PHP: nginx + PHP-FPM (и uwsgi/scgi)
  18. WebSocket, gRPC и стриминг через Nginx
  19. Кэширование ответов: proxy_cache и микрокэш
  20. HTTPS и TLS: сертификаты, протоколы, шифры (2026)
  21. Let's Encrypt и ACME: certbot, acme.sh, нативный ACME Angie
  22. HTTP/2 и HTTP/3 (QUIC) в 2026
  23. Безопасность: заголовки, скрытие версии, ограничения
  24. Rate limiting и защита от перегрузки
  25. Контроль доступа: allow/deny, auth_basic, auth_request и mTLS
  26. Логирование: access_log, форматы и структурированный JSON
  27. Сквозная трассировка запросов и OpenTelemetry
  28. Метрики и мониторинг Nginx
  29. Производительность и тюнинг под нагрузку
  30. Траблшутинг: 502, 504, 403, 404 и debug-лог
  31. OpenResty: Nginx как платформа на LuaJIT
  32. Фазы обработки запроса и Lua-хуки
  33. Lua API: ngx.*, shared dict, cosocket и lua-resty-core
  34. Практика OpenResty: авторизация, JWT, кэш, Redis
  35. Angie: современный форк Nginx 2026
  36. Динамическая конфигурация и service discovery
  37. Nginx как API-gateway и Kubernetes Gateway API (вы здесь)
  38. Динамические модули, njs и WAF
  39. Stream-модуль: проксирование TCP и UDP
  40. Деплой, перезагрузка и конфиг как код
  41. Сценарий: статика, SPA и кэширование за CDN
  42. Сценарий: микросервисный gateway по образцу ngx-trace-gateway
  43. Капстоун: собираем production-gateway с нуля
  44. Чек-лист безопасности, CVE 2026 и аудит конфигурации
Зачем вообще шлюз перед микросервисами

Представь десяток сервисов: auth, billing, catalog, search, notifications. У каждого свой порт, свой деплой, свои таймауты. Если выпустить их в мир напрямую, клиент должен знать все адреса, ты должен на каждом повесить TLS, rate limit, проверку токена, CORS и логи. Это копипаста, которая разъезжается через неделю. Шлюз решает боль одной фразой: одна точка входа, за которой прячется вся внутренняя топология. Снаружи виден один домен api.example.com, внутри - маршрутизация по пути, хосту и заголовку, единая аутентификация и единые наблюдаемость и лимиты.

Именно в этой роли nginx живёт уже пятнадцать лет, и связка nginx api gateway давно стала индустриальным дефолтом. На нём же построены Kong, APISIX и частично Traefik - то есть когда ты учишь nginx как шлюз, ты заодно понимаешь, что у них под капотом. В этом уроке разберём паттерны API-gateway на чистом nginx и на OpenResty, а потом честно поговорим про Kubernetes: про nginx ingress, про то, что в 2026 с ним случилось, и куда индустрия переезжает.

Ключевая мысль: gateway - это не "ещё один прокси". Это слой политик. Маршрут - политика. Лимит - политика. Проверка JWT - политика. CORS - политика. Чем чище ты отделяешь политики от бэкендов, тем дольше живёт конфиг.

Изображение

Паттерны API-gateway на nginx: маршрутизация, версии, лимиты

Начнём с маршрутизации - сердца шлюза. nginx умеет разводить трафик по трём осям: по пути (location), по хосту (server_name) и по заголовку (через map плюс переменную в proxy_pass или через if по $http_*). Базовый каркас выглядит так.

Код: Выделить всё

upstream auth_svc    { server 10.0.1.10:8080; keepalive 32; }
upstream billing_svc { server 10.0.2.10:8080; keepalive 32; }
upstream catalog_svc { server 10.0.3.10:8080; keepalive 32; }

server {
    listen 443 ssl;
    listen 443 quic reuseport;
    http2 on;
    http3 on;
    server_name api.example.com;
    add_header Alt-Svc 'h3=":443"; ma=86400' always;

    # маршрут по пути
    location /auth/    { proxy_pass http://auth_svc/; }
    location /billing/ { proxy_pass http://billing_svc/; }
    location /catalog/ { proxy_pass http://catalog_svc/; }
}
Обрати внимание на слеш в proxy_pass: http://auth_svc/ отрезает префикс /auth/ и отдаёт бэкенду уже /login, а не /auth/login. Это классический источник 404: забыл слеш - получил двойной префикс. Бэкенды соединяются по HTTP/1.1 с keepalive (с nginx 1.29.7, вошедшего в stable 1.30, это поведение по умолчанию; на старых версиях явно ставь proxy_http_version 1.1 и proxy_set_header Connection "").

Версионирование API. Две рабочие схемы. Первая - версия в пути, /v1/ и /v2/ как отдельные location на разные апстримы. Прозрачно, кэшируется, видно в логах. Вторая - версия в заголовке Accept или X-API-Version, разруливается через map.

Код: Выделить всё

map $http_x_api_version $catalog_backend {
    default       catalog_v2;
    "1"           catalog_v1;
    "2"           catalog_v2;
}

location /catalog/ {
    proxy_pass http://$catalog_backend/;
}
Когда proxy_pass содержит переменную, nginx требует резолвер и не отрезает префикс автоматически - поэтому здесь добавляй resolver и при необходимости rewrite. Это тонкость, на которой спотыкаются: динамический proxy_pass ведёт себя иначе, чем статический.

Rate limit на токен, а не только на IP. Лимит по $binary_remote_addr защищает от грубого флуда, но за NAT или CDN тысяча клиентов выглядит одним IP. Профессиональный gateway лимитирует по идентификатору потребителя - по API-ключу или по subject из JWT. В эталонном ngx-trace-gateway это сделано через map в $api_consumer_id и несколько зон:

Код: Выделить всё

map $http_authorization $api_consumer_id { default anon; }
map $http_x_api_key     $rl_api_key      { default "";   }

limit_req_zone $binary_remote_addr zone=public_api_ip:10m   rate=60r/m;
limit_req_zone $api_consumer_id    zone=public_api_user:10m rate=120r/m;
limit_req_zone $rl_api_key         zone=public_api_key:10m  rate=10r/s;

location /catalog/ {
    limit_req zone=public_api_ip  burst=20 nodelay;
    limit_req zone=public_api_key burst=20 delay=10;
    proxy_pass http://catalog_svc/;
}
burst=20 nodelay даёт всплеск без задержки (превышение -> 503), а delay=10 пропускает первые 10 без задержки, остальные из burst придерживает. Несколько limit_req в одном location складываются: запрос должен пройти все зоны.

JWT, OAuth2, CORS и трансформация запроса

Шлюз - правильное место для аутентификации: проверил токен один раз на входе, дальше внутренний трафик уже доверенный. На чистом nginx это делается двумя способами.

auth_request. nginx делает внутренний субзапрос к сервису-валидатору; 2xx - пускаем, 401/403 - режем. Бэкендам не нужно знать про токены вообще.

Код: Выделить всё

location = /_authz {
    internal;
    proxy_pass http://auth_svc/verify;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Original-URI $request_uri;
}
location /billing/ {
    auth_request /_authz;
    auth_request_set $user $upstream_http_x_user;
    proxy_set_header X-User $user;
    proxy_pass http://billing_svc/;
}
auth_request_set вытаскивает заголовок из ответа валидатора и пробрасывает дальше - так gateway превращает токен в доверенный X-User для бэкенда. Это и есть трансформация: снаружи Bearer-токен, внутри простой заголовок.

Проверка JWT прямо в gateway. В чистом open-source nginx нативной проверки JWT нет (она есть в NGINX Plus). На OpenResty её делают через Lua. Здесь жёсткое правило безопасности: библиотека lua-resty-jwt имеет историю уязвимостей alg-confusion и alg=none, поэтому НИКОГДА не доверяй заголовку alg из самого токена - явно фиксируй допустимый алгоритм и ключ.

Код: Выделить всё

access_by_lua_block {
    local jwt = require "resty.jwt"
    local h = ngx.var.http_authorization
    if not h then return ngx.exit(401) end
    local token = h:gsub("^Bearer%s+", "")
    local obj = jwt:verify(SECRET, token, {
        valid_issuers = { "https://idp.example.com" }
    })
    -- критично: проверяем сами, а не верим токену
    if not obj.verified or obj.header.alg ~= "RS256" then
        ngx.log(ngx.WARN, "jwt rejected: ", obj.reason)
        return ngx.exit(401)
    end
    ngx.req.set_header("X-User", obj.payload.sub)
}
Для полноценного OAuth2/OIDC (authorization code flow, обновление токенов, интроспекция) на OpenResty де-факто стандарт - lua-resty-openidc: он берёт на себя редиректы к провайдеру, валидацию по JWKS и сессии. Писать это руками не надо.

CORS. Браузерный preflight - это OPTIONS-запрос, на который gateway должен ответить сам, не дёргая бэкенд.

Код: Выделить всё

if ($request_method = OPTIONS) {
    add_header Access-Control-Allow-Origin  $http_origin always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
    add_header Access-Control-Max-Age 600 always;
    return 204;
}
Не ставь Allow-Origin "*" вместе с Allow-Credentials - браузер это отвергнет, да и дыра. Лучше отражай $http_origin из белого списка через map.

Агрегация и трансформация. Если фронту нужен один ответ из нескольких сервисов, на OpenResty это делают через ngx.location.capture_multi (параллельные субзапросы) или через njs. Для njs учти: в 2026 классический JS-движок помечен deprecated, рекомендуемый - QuickJS (js_engine qjs;), у него ES2023, async, Fetch и WebCrypto. Async в njs работает только в js_content и js_access, не в js_set.

Nginx ingress в Kubernetes: что сломалось в 2026

Теперь самое важное и самое запутанное. Когда говорят "nginx kubernetes" или "kubernetes ingress nginx", под одним именем прячутся ТРИ совершенно разных продукта. Их путают постоянно, и в 2026 эта путаница стоит денег и безопасности.
  • community ingress-nginx (репозиторий kubernetes/ingress-nginx, тот, что ставят через helm install ingress-nginx) - самый популярный исторически. В 2026 он МЁРТВ.
  • F5 NGINX Ingress Controller (NIC, репозиторий nginxinc/kubernetes-ingress) - отдельный продукт от F5, OSS и Plus-редакции. ЖИВ и развивается.
  • NGINX Gateway Fabric (NGF) - реализация нового Kubernetes Gateway API на дата-плейне nginx, тоже от F5. ЖИВ, это будущее.
Факт, который надо знать назубок: проект community ingress-nginx ОФИЦИАЛЬНО ретайрнут. Репозиторий стал read-only в конце марта 2026 (24-31 марта), новых фич нет, багфиксов нет, и - критично - CVE больше НЕ патчатся. Решение приняли из-за хронических уязвимостей: в марте 2025 был IngressNightmare (CVE-2025-1974, неаутентифицированный RCE через admission webhook), в начале 2026 разом вышли ещё несколько HIGH-severity CVE. Преемник под названием InGate тоже свернули. Поэтому правило простое: для нового прода ingress-nginx не выкатывать. Если он у тебя уже крутится - планируй миграцию, потому что незакрытая RCE на входе кластера это не "потом".

Важная оговорка: сам ресурс Ingress в Kubernetes никуда не делся, спецификация Ingress остаётся в ядре. Умер именно контроллер kubernetes/ingress-nginx. Контроллеры Traefik, HAProxy, Kong и F5 NGINX Ingress Controller продолжают обслуживать Ingress-ресурсы как ни в чём не бывало.

Переезд на Kubernetes Gateway API: ingress2gateway 1.0

Куда переезжать? Индустрия выбрала nginx gateway api как направление, точнее - Kubernetes Gateway API как стандарт на смену Ingress. Gateway API решает то, на чём Ingress буксовал: ролевую модель (инфра-команда владеет Gateway, продуктовые команды - своими HTTPRoute), выразительную маршрутизацию по заголовкам, методам, весам без зоопарка вендорских аннотаций. Ingress конфигурировался десятками annotation-строк, которые у каждого контроллера свои; Gateway API выносит это в типизированные ресурсы Gateway, HTTPRoute, GRPCRoute.

Сравни философию. Ingress:

Код: Выделить всё

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "20"
Gateway API - то же самое, но веса каноничны и переносимы между контроллерами:

Код: Выделить всё

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: catalog
spec:
  parentRefs:
    - name: api-gateway
  rules:
    - matches:
        - path: { type: PathPrefix, value: /catalog }
      backendRefs:
        - name: catalog-v1
          weight: 80
        - name: catalog-v2
          weight: 20
Это нативный canary прямо в API: 80/20 между версиями, без аннотаций. Переезжать руками не нужно - в марте 2026 SIG-Network выпустил ingress2gateway 1.0. Инструмент читает твои Ingress-манифесты и генерирует Gateway плюс HTTPRoute. В версии 1.0 он понимает 30+ популярных аннотаций ingress-nginx (CORS, rewrite, regex-пути, backend TLS) и честно предупреждает, что перевести не смог.

Код: Выделить всё

ingress2gateway print --input-file ingress.yaml --providers ingress-nginx > gateway.yaml
Дальше выбираешь дата-плейн: F5 NGINX Gateway Fabric (на nginx), Envoy Gateway, Istio - все они conformant-реализации одного стандарта. В этом и сила: HTTPRoute переносится между ними почти без правок.

Canary и blue-green на gateway без Kubernetes. Если ты на голом nginx, тот же эффект дают split_clients (стабильное разбиение по хешу) и веса в upstream:

Код: Выделить всё

split_clients "$request_id" $catalog_pool {
    20%     catalog_v2;
    *       catalog_v1;
}
location /catalog/ { proxy_pass http://$catalog_pool/; }
split_clients хеширует ключ и режёт по процентам детерминированно - тот же $request_id всегда попадёт в ту же группу. Для blue-green просто переключи * между пулами.

Типичные грабли
  • Забытый слеш в proxy_pass. http://svc и http://svc/ ведут себя по-разному с префиксом location. Симптом - бэкенд получает удвоенный путь и отдаёт 404.
  • Доверие к alg из JWT. Если проверяешь токен в Lua и не фиксируешь алгоритм, атакующий подсунет alg=none или RS256->HS256 и подделает подпись. Всегда задавай ожидаемый alg явно.
  • Rate limit только по IP за CDN/NAT. $remote_addr там - адрес ближайшего прокси, а не клиента. Нужен модуль realip с set_real_ip_from ТОЛЬКО на доверенные сети, иначе клиент подделает X-Forwarded-For и обойдёт лимит.
  • Установка community ingress-nginx в новый кластер в 2026. Это установка софта без патчей безопасности на самый периметр. Не делай так - бери F5 NIC или Gateway API.
  • Путаница трёх "nginx ingress". Гуглишь баг, находишь решение - проверь, к какому из трёх продуктов оно относится. Аннотации community-контроллера не работают в F5 NIC и наоборот.
  • add_header в if. Заголовки внутри if могут не наследоваться так, как ты ждёшь. Для CORS-preflight это терпимо (там return), но в общем случае держи add_header вне if и используй always.
Мини-лаба: gateway с маршрутизацией и JWT

Соберём минимальный шлюз на OpenResty по шагам. Понадобится Docker.
  • Шаг 1. Подними два бэкенда-заглушки: docker run -d --name svc-a -p 8001:80 kennethreitz/httpbin и аналогично svc-b на 8002.
  • Шаг 2. Создай gateway.conf с двумя upstream (svc_a -> host.docker.internal:8001, svc_b -> :8002) и server на 8080.
  • Шаг 3. Сделай маршруты: location /a/ -> proxy_pass http://svc_a/ и location /b/ -> http://svc_b/. Не забудь слеши.
  • Шаг 4. Добавь на /b/ зону limit_req по $binary_remote_addr с rate=2r/s burst=2 nodelay.
  • Шаг 5. На /a/ повесь access_by_lua_block, который требует заголовок Authorization и при его отсутствии делает ngx.exit(401). Пока без полной проверки подписи - просто факт наличия.
  • Шаг 6. Запусти openresty/openresty:latest, смонтировав конфиг ro: docker run -d -p 8080:8080 -v $PWD/gateway.conf:/etc/nginx/conf.d/default.conf:ro openresty/openresty:latest.
  • Шаг 7. Проверь: curl localhost:8080/a/get -> 401; curl -H "Authorization: Bearer x" localhost:8080/a/get -> 200. Пробей /b/ циклом из 10 быстрых запросов - увидишь 503 после лимита.
Когда заработает, добавь третий location /c/ со split_clients 50/50 между svc_a и svc_b и убедись, что повторные запросы с одним $request_id стабильно идут в один бэкенд, а разные - размазываются.

Контрольные вопросы
  • Почему лимитировать только по $remote_addr опасно за CDN, и что нужно настроить, чтобы лимит считался по реальному клиенту?
  • Чем отличаются три продукта со словом "nginx ingress" и какой из них в 2026 нельзя ставить в новый прод и почему?
  • Зачем при проверке JWT в Lua явно фиксировать алгоритм подписи, и какие атаки это закрывает?
  • Как nginx ведёт себя со слешем в proxy_pass при префиксном location, и почему это частый источник 404?
Итог

API-gateway на nginx - это слой политик над микросервисами: маршрутизация по пути/хосту/заголовку, версионирование, rate limit по токену, проверка JWT/OAuth2, CORS и трансформация. На чистом nginx хватает auth_request, map и limit_req; на OpenResty добавляются Lua-проверки и агрегация, но с дисциплиной безопасности (фиксируй alg, не храни cosocket на уровне модуля). В Kubernetes 2026 запомни главное: community ingress-nginx ретайрнут и без CVE-патчей, F5 NGINX Ingress Controller и NGINX Gateway Fabric живы, а будущее - Kubernetes Gateway API, на который переезжают инструментом ingress2gateway 1.0. За образец production-структуры держи ngx-trace-gateway: модульные globals, сквозная трассировка и лимиты по consumer-id.
👍2 ❤️3 🔥1 😄 🤔
Аватара пользователя
candye
Сообщения: 1
Зарегистрирован: 21 май 2026, 09:39

Re: Nginx как API-gateway и Kubernetes Gateway API

Сообщение candye »

Спасибо, наконец кто то разложил по полкам эти три nginx ingress. Я реально ставил community контроллер месяц назад в новый кластер, теперь буду срочно мигрировать на Gateway API.
👍 ❤️1 🔥 😄 🤔
Аватара пользователя
BashGuru
Сообщения: 1
Зарегистрирован: 08 июн 2026, 14:59

Re: Nginx как API-gateway и Kubernetes Gateway API

Сообщение BashGuru »

Вопрос по auth_request: если валидатор лежит, location с auth_request отдаёт 500 на всё или есть способ зафейлить мягко? Хочется чтобы при падении authz не валился весь шлюз.
👍1 ❤️2 🔥 😄 🤔
Ответить
← Предыдущая глава
Динамическая конфигурация и service discovery
Следующая глава →
Динамические модули, njs и WAF

Все главы курса «Nginx профессионально: от первого конфига до API-gateway на OpenResty и Angie»

Поделиться темой: ✈ Telegram VK
Похожие запросы: nginx как API-gateway и Kubernetes Ingress

Вернуться в «Nginx профессионально: от первого конфига до API-gateway на OpenResty и Angie»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость