MAATRIX / Блог / Tyk Gateway на сервере: частые ошибки и решения

Tyk Gateway на сервере: частые ошибки и решения

MAATRIX

Tyk Gateway часто выбирают за то, что это полноценный open-source API-шлюз со встроенным порталом разработчика — не урезанный community-tier, а рабочий инструмент для продакшена. Но именно из-за гибкости конфигурации (Redis, API definitions в JSON, политики, плагины) на нём легко словить ошибку, которая в логах выглядит загадочно, а по факту сводится к одной строчке в конфиге. Ниже — конкретные ситуации, с которыми сталкиваются при развёртывании Tyk на своём сервере, и как их закрывать.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Redis недоступен: гейтвей не стартует или зависает

Tyk Gateway хранит в Redis почти всё оперативное состояние: сессии API-ключей, счётчики rate limiting, кэш политик. Без Redis шлюз либо не поднимается вовсе, либо стартует, но отвечает 500 на любой запрос.

Типичная ошибка в логах:

level=error msg="Error trying to set value" error="dial tcp 127.0.0.1:6379: connect: connection refused"

Проверьте цепочку из трёх вещей по порядку:

  1. Redis вообще запущен и слушает нужный порт:
redis-cli -h 127.0.0.1 -p 6379 ping
# должно вернуть PONG
  1. В tyk.conf секция storage указывает на реальный хост — в Docker Compose это имя сервиса, а не localhost:
"storage": {
  "type": "redis",
  "host": "redis",
  "port": 6379,
  "username": "",
  "password": "",
  "database": 0
}

Частая ошибка новичков — оставить "host": "localhost" в контейнере, где Redis живёт в соседнем сервисе redis и по localhost недоступен в принципе.

  1. Если Redis требует пароль (а на боевом сервере он обязан требовать), убедитесь, что в tyk.conf и в самом Redis (requirepass в redis.conf) значения совпадают, и что после смены пароля вы перезапустили оба процесса — Tyk не подхватывает пароль на лету.

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

API definitions не подхватываются гейтвеем

Вы создали JSON с описанием API, положили его в нужную папку, перезапустили Tyk — а он его "не видит": запрос к листен-пасу отдаёт 404 API not found.

Разбор по шагам:

  • Режим хранения API definitions. У Tyk их два: файловый (policies и apps лежат в файлах на диске, путь задаётся app_path в tyk.conf) и через Tyk Dashboard/Gateway API (definitions хранятся в Redis/Mongo). Если у вас open-source установка без Dashboard, работает файловый режим — и определение подхватывается только из указанной папки, обычно /opt/tyk-gateway/apps/.
  • Формат имени файла и поле api_id. Файл должен заканчиваться на .json, и внутри обязательно уникальный api_id — если он совпадает с уже загруженным API, второй молча игнорируется.
  • active: true в определении. Самая частая причина "API не виден" — забытое поле:
{
  "name": "orders-api",
  "api_id": "orders-api-1",
  "active": true,
  "proxy": {
    "listen_path": "/orders/",
    "target_url": "http://backend:8080/",
    "strip_listen_path": true
  }
}
  • Hot reload. После добавления или изменения файла гейтвей не подхватывает его сам — нужно послать сигнал:
curl -H "x-tyk-authorization: <secret из tyk.conf>" \
  -X GET http://127.0.0.1:8080/tyk/reload/group

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

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Rate limiting и quota работают не так, как ожидалось

Настроили лимит 100 запросов в минуту, а гейтвей режет раньше — или наоборот, пропускает больше, чем задано. Здесь почти всегда путаница между уровнями лимитов, а не баг.

У Tyk лимиты применяются в несколько слоёв, и они не заменяют друг друга, а складываются:

УровеньГде задаётсяНа что влияет
Global rate limittyk.confglobal_session_lifetime и smoothingОбщий предохранитель для всего гейтвея
API-level limitВ api_definition.json, секция rate_limitЛимит на конкретный API целиком
Key-level limitВ сессии ключа (rate и per)Лимит на конкретного потребителя
Policy limitВ политике, привязанной к ключуЛимит для группы ключей по одной политике

Если ключ привязан к политике и имеет собственные rate/per в сессии — побеждает политика, если в определении API не включён allowance для переопределения. Проверить, что реально применяется к ключу, проще всего запросом к management API:

curl -H "x-tyk-authorization: <secret>" \
  http://127.0.0.1:8080/tyk/keys/<key-id>

В ответе смотрите на rate, per и apply_policy_id — если политика подключена, значения из неё имеют приоритет. Также проверьте, что Redis не разделён между гейтвеями кластера: если у вас два инстанса Tyk за балансировщиком, а Redis у каждого свой локальный — счётчики не синхронизируются, и суммарный лимит фактически удваивается.

401/403 при валидном на вид JWT или API-ключе

Гейтвей отвергает токен, который, на первый взгляд, полностью корректен — подписан тем же секретом, не просрочен.

Основные причины:

  • Несовпадение iss (issuer) в токене и в API definition. Tyk сверяет поле identity_source и jwt_identity_base_field с claim в токене; если issuer в definition указан жёстко, а токен выпущен другим клиентом OAuth — 403 гарантирован.
  • Алгоритм подписи. Если definition ждёт RS256, а токен подписан HS256 (или наоборот), Tyk не станет "угадывать" — сразу отказ. Проверьте заголовок токена (jwt.io или jq -R 'split(".") | .[0] | @base64d' <<< "$TOKEN") и сравните с jwt_signing_method в definition.
  • Часовые пояса и exp/nbf. Если сервер и клиент, выпускающий токены, живут в разных часовых зонах без NTP-синхронизации, токен может считаться "ещё не начал действовать" (nbf в будущем) — банально из-за рассинхрона часов на пару минут. Проверьте timedatectl на сервере.
  • Хешированные ключи. Если в tyk.conf включён hash_keys: true, а вы ищете ключ по plain-значению через management API — не найдёте. Ищите по хешу или временно смотрите заголовок ответа x-ratelimit-remaining, который подтверждает, что ключ вообще был распознан.

Включите подробный лог на время отладки:

"log_level": "debug"

и смотрите journalctl -u tyk-gateway -f — Tyk честно пишет, на каком именно шаге валидации отвалился токен, если не душить уровень логов до info.

TLS-терминация: гейтвей за reverse proxy или напрямую

Два рабочих варианта: TLS терминирует сам Tyk (поле http_server_options.use_ssl в tyk.conf), либо перед ним стоит nginx/Caddy/Traefik, а Tyk слушает plain HTTP внутри приватной сети. На проде почти всегда правильнее второе — сертификаты, редиректы и HTTP/2 удобнее держать на прокси, а Tyk оставить чистым API-слоем.

Частые грабли этой связки:

  • X-Forwarded-For теряется или дублируется. Если reverse proxy не проксирует заголовки правильно, Tyk логирует и лимитирует по IP самого прокси, а не реального клиента — все запросы визуально идут "с одного адреса". В nginx это лечится стандартным набором:
location / {
    proxy_pass http://127.0.0.1:8080;
    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;
}
  • Таймауты не согласованы. Если у бэкенда за Tyk долгие ответы (агрегация, отчёты), а у nginx proxy_read_timeout по умолчанию 60 секунд — клиент получит 504 раньше, чем Tyk успеет доотдать ответ. Выравнивайте таймауты по всей цепочке: nginx → Tyk → backend.
  • Двойной gzip. Если сжатие включено и на Tyk, и на прокси, тело ответа может быть сжато дважды — клиент получит битый JSON. Оставляйте сжатие в одном месте цепочки.

Если решаете, что поставить перед гейтвеем — почитайте сравнение в статье Caddy или Nginx: что выбрать для сервера.

Docker Compose для продакшена: минимальный рабочий стек

Для боевого запуска Tyk Gateway достаточно двух сервисов — самого гейтвея и Redis, с вынесенными наружу конфигом и папкой API definitions:

services:
  redis:
    image: redis:7-alpine
    restart: unless-stopped
    command: redis-server --requirepass ${REDIS_PASSWORD} --maxmemory 512mb --maxmemory-policy allkeys-lru
    volumes:
      - redis-data:/data

  tyk-gateway:
    image: tykio/tyk-gateway:v5.3
    restart: unless-stopped
    depends_on:
      - redis
    ports:
      - "8080:8080"
    volumes:
      - ./tyk.conf:/opt/tyk-gateway/tyk.conf:ro
      - ./apps:/opt/tyk-gateway/apps
      - ./middleware:/opt/tyk-gateway/middleware:ro
    environment:
      - TYK_GW_STORAGE_HOST=redis
      - TYK_GW_STORAGE_PORT=6379
      - TYK_GW_STORAGE_PASSWORD=${REDIS_PASSWORD}

volumes:
  redis-data:

Важные нюансы этого файла:

  • restart: unless-stopped обязателен для обоих сервисов — иначе после перезагрузки сервера гейтвей молча останется лежать.
  • Переменные TYK_GW_* переопределяют значения из tyk.conf — удобно для секретов, чтобы пароль Redis не лежал в конфиге открытым текстом в git-репозитории.
  • Папка ./apps должна быть смонтирована именно как volume (не COPY в образ) — иначе для каждого нового API definition придётся пересобирать образ.
  • maxmemory-policy allkeys-lru для Redis в связке с Tyk — разумный дефолт: старые счётчики rate limiting вытесняются первыми, не роняя гейтвей при нехватке памяти.

Про общие грабли docker-compose на проде — отдельный разбор в статье Docker Compose для продакшена: частые ошибки и решения.

Мониторинг и диагностика: что смотреть в первую очередь

Когда гейтвей "работает, но как-то не так" — самая частая ошибка в диагностике — сразу лезть в логи Tyk, хотя проблема в трёх случаях из пяти лежит вне самого гейтвея.

Порядок проверки, который экономит время:

  1. /hello эндпоинт. Tyk отдаёт статус здоровья без аутентификации:
curl http://127.0.0.1:8080/hello

Ответ с "status": "pass" подтверждает, что гейтвей и его связь с Redis в порядке — если он не отвечает, проблема точно на уровне процесса или сети, а не в конкретном API definition.

  1. Метрики через Prometheus. При enable_metrics: true в конфиге Tyk отдаёт /metrics — латентность по API, количество 4xx/5xx, использование Redis-соединений. Как разворачивать стек мониторинга с нуля, описано в статье про Grafana и Prometheus на сервере.
  2. Логи бэкенда, а не только гейтвея. Если Tyk отдаёт 502/504, смотрите, что в этот момент отвечает (или не отвечает) target_url из API definition — гейтвей это прокси, он ретранслирует проблему из бэкенда.

Ресурсные лимиты (CPU/RAM) на контейнер с Tyk стоит выставлять с запасом на пики — под всплеском трафика JSON-парсинг definitions и логирование дают заметный CPU-скачок. Если ловите OOM или троттлинг, проверьте настройки в статье про лимиты ресурсов Docker по CPU и памяти.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

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

Обязателен ли Tyk Dashboard, или можно только Gateway?

Нет, не обязателен. Open-source Tyk Gateway полностью рабочий сам по себе, с файловыми API definitions и управлением через REST management API (/tyk/... эндпоинты с секретным заголовком). Dashboard — коммерческая надстройка с UI, аналитикой и порталом разработчика поверх Postgres/MongoDB; для многих задач хватает голого гейтвея.

Можно ли обойтись без Redis?

Нет — Redis жёстко зашит в архитектуру как хранилище сессий и счётчиков. Заменить его на что-то другое штатными средствами нельзя, но можно вынести на отдельный сервер и настроить Redis Sentinel или кластер для отказоустойчивости, если гейтвей критичен для продакшена.

Почему после docker compose restart tyk-gateway пропадают все API definitions?

Проверьте, что папка apps действительно смонтирована как volume, а не осталась внутри слоя образа. Если монтирование настроено верно, а definitions всё равно пропадают — вероятно, где-то в CI/CD пайплайне пересобирается образ без сохранения volume, и файлы реально удаляются на хосте.

Как обновить Tyk Gateway без даунтайма?

При одном инстансе — без простоя не обойтись, разве что на секунды при docker compose up -d с новым тегом образа (Docker пересоздаёт контейнер быстро). Для zero-downtime нужен как минимум второй инстанс гейтвея за балансировщиком с health check по /hello, чтобы обновлять их поочерёдно.

Гейтвей ест много памяти со временем — это утечка?

Чаще всего это не утечка самого Tyk, а рост Redis из-за неограниченного накопления сессий и логов аналитики. Проверьте maxmemory и maxmemory-policy у Redis, а также TTL на аналитических записях — без ограничения они копятся бесконечно.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →