Как установить и настроить Apache APISIX на VPS
Когда обычного Nginx с парой location уже не хватает — нужны динамические маршруты без перезагрузки конфига, rate limiting, JWT-авторизация и метрики из коробки — многие берут Kong или собирают самодельный слой на Lua-скриптах. Apache APISIX решает эту задачу проще: это API-шлюз на базе Nginx и LuaJIT (движок OpenResty), где маршруты и плагины настраиваются через REST API и хранятся в etcd, а не в текстовом конфиге. Дальше — рабочая установка на VPS через Docker Compose, первый маршрут, SSL и набор плагинов, которые реально нужны в проде.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что такое APISIX и когда он нужен вместо обычного Nginx
APISIX — это reverse proxy и API-шлюз с плагинной архитектурой. Технически он состоит из трёх частей:
- Data plane — сам APISIX,worker-процессы на базе Nginx/OpenResty, которые реально проксируют трафик;
- etcd — распределённое key-value хранилище, где лежит вся конфигурация (маршруты, апстримы, плагины). APISIX подписывается на изменения в etcd и применяет их без перезапуска;
- Admin API — REST API (порт 9180 по умолчанию), через который вы создаёте и меняете маршруты. Веб-интерфейса из коробки нет — для UI ставится отдельный компонент apisix-dashboard.
Смысл появляется, когда у вас не один сайт, а несколько бэкендов (микросервисы, мобильный API, партнёрские интеграции), и маршруты меняются чаще, чем раз в месяц. Задача «добавить новый эндпоинт с лимитом запросов и JWT-проверкой» в APISIX — это один POST-запрос к Admin API, без nginx -s reload и без риска уронить конфиг опечаткой в location.
Если у вас один сайт с парой апстримов и конфигурация меняется редко — переплата: проще и надёжнее взять Nginx как reverse proxy. APISIX стоит ставить, когда динамика маршрутов и плагины перевешивают сложность лишнего etcd в стеке.
Требования к серверу и подготовка
APISIX сам по себе лёгкий (сборка на Nginx съедает немного памяти на старте), но etcd под нагрузкой любит iops и не любит своп. Ориентир для продакшена:
| Параметр | Минимум | Комфортно |
|---|---|---|
| CPU | 1 vCPU | 2 vCPU |
| RAM | 1 GB | 2-4 GB |
| Диск | 15 GB SSD | 30+ GB NVMe |
| ОС | Ubuntu 24.04 / Debian 12 | Ubuntu 24.04 |
На 1 GB RAM APISIX и однонодовый etcd поднимутся и будут работать, но при активной записи в etcd (частое создание маршрутов, большие ACL-списки) лучше закладывать 2 GB — иначе etcd может начать спотыкаться о OOM killer.
Перед установкой:
apt update && apt upgrade -y
apt install -y curl ca-certificates gnupg
Docker и Docker Compose — обязательны, вся установка ниже собрана вокруг них. Заодно откройте нужные порты в фаерволе — как минимум 80/443 наружу и 9180 (Admin API) только с доверенных IP, это лучше сделать через ufw сразу после установки Docker.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверУстановка через Docker Compose
Официальный путь для продакшена — Helm на Kubernetes, но для одиночного VPS Docker Compose проще и вполне жизнеспособен: он же используется в quickstart-сценариях самого проекта. Поднимаем три контейнера: etcd, apisix и apisix-dashboard.
mkdir -p /opt/apisix && cd /opt/apisix
mkdir -p apisix_log apisix_conf dashboard_conf etcd_data
Файл docker-compose.yml:
version: "3"
services:
etcd:
image: bitnami/etcd:3.5
restart: unless-stopped
environment:
ETCD_ENABLE_V2: "true"
ALLOW_NONE_AUTHENTICATION: "yes"
ETCD_ADVERTISE_CLIENT_URLS: "http://etcd:2379"
ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2379"
volumes:
- ./etcd_data:/bitnami/etcd
networks:
- apisix
apisix:
image: apache/apisix:3.9.1-debian
restart: unless-stopped
depends_on:
- etcd
volumes:
- ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro
- ./apisix_log:/usr/local/apisix/logs
ports:
- "9080:9080" # HTTP data plane
- "9443:9443" # HTTPS data plane
- "9180:9180" # Admin API
networks:
- apisix
dashboard:
image: apache/apisix-dashboard:3.0.1-alpine
restart: unless-stopped
depends_on:
- apisix
volumes:
- ./dashboard_conf/conf.yaml:/usr/local/apisix-dashboard/conf/conf.yaml:ro
ports:
- "9000:9000"
networks:
- apisix
networks:
apisix:
driver: bridge
Версии образов (3.9.1, 3.0.1) — ориентир на момент написания, перед установкой сверьтесь с актуальными тегами на Docker Hub, APISIX выпускает релизы регулярно.
Файл apisix_conf/config.yaml — минимум для работы с внешним etcd и своим ключом Admin API:
deployment:
admin:
allow_admin:
- 0.0.0.0/0 # на проде замените на реальные доверенные IP
admin_key:
- name: "admin"
key: "ЗАМЕНИТЕ_НА_СЛУЧАЙНУЮ_СТРОКУ_32+_СИМВОЛА"
role: admin
etcd:
host:
- "http://etcd:2379"
prefix: "/apisix"
timeout: 30
Файл dashboard_conf/conf.yaml:
conf:
listen:
host: 0.0.0.0
port: 9000
etcd:
endpoints:
- etcd:2379
authentication:
secret: "ЗАМЕНИТЕ_НА_ДРУГУЮ_СЛУЧАЙНУЮ_СТРОКУ"
expire_time: 3600
users:
- username: admin
password: "ЗАМЕНИТЕ_НА_НАДЁЖНЫЙ_ПАРОЛЬ"
Ключ admin_key продублируйте один в один в обоих файлах ниже, где это нужно, и никогда не оставляйте дефолтный edd1c9f034335f136f87ad84b625c8f из официальных примеров — по нему в интернете сканируют открытые Admin API пачками.
Запуск:
docker compose up -d
docker compose ps
Проверка, что data plane жив:
curl -i http://127.0.0.1:9080/apisix/status
Дашборд будет на http://IP-сервера:9000 — до настройки SSL и ограничения доступа держите порт 9000 закрытым для внешнего мира через ufw и заходите только через SSH-туннель (ssh -L 9000:localhost:9000 user@server).
Первый маршрут и Admin API
Маршруты (routes) и апстримы (upstreams) создаются через Admin API. Заведём апстрим на локальный сервис (например, приложение на порту 3000) и маршрут к нему:
curl -i "http://127.0.0.1:9180/apisix/admin/routes/1" \
-H "X-API-KEY: ЗАМЕНИТЕ_НА_СЛУЧАЙНУЮ_СТРОКУ_32+_СИМВОЛА" \
-X PUT -d '
{
"uri": "/api/*",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:3000": 1
}
}
}'
Проверяем:
curl -i "http://127.0.0.1:9080/api/health"
Если бэкенд слушает на 3000 и отвечает — запрос через 9080 дойдёт до него, минуя прямой доступ к порту (который стоит закрыть в ufw). Для нескольких бэкендов апстрим можно вынести отдельным объектом и переиспользовать в разных маршрутах:
curl -i "http://127.0.0.1:9180/apisix/admin/upstreams/backend-app" \
-H "X-API-KEY: ЗАМЕНИТЕ_НА_СЛУЧАЙНУЮ_СТРОКУ_32+_СИМВОЛА" \
-X PUT -d '
{
"type": "roundrobin",
"nodes": {
"10.0.0.11:3000": 1,
"10.0.0.12:3000": 1
}
}'
Дальше маршрут ссылается на него через "upstream_id": "backend-app" вместо инлайн-объекта — удобно, когда за одним апстримом несколько маршрутов.
SSL и домены
За TLS-терминацию отвечает сам APISIX (порт 9443), сертификат подгружается тоже через Admin API, а не через файлы в /etc/nginx/. Если у вас уже есть сертификат от Let's Encrypt (например, выпущенный certbot'ом отдельно с DNS-валидацией, без занятого 80-го порта), загружаем его так:
curl -i "http://127.0.0.1:9180/apisix/admin/ssls/1" \
-H "X-API-KEY: ЗАМЕНИТЕ_НА_СЛУЧАЙНУЮ_СТРОКУ_32+_СИМВОЛА" \
-X PUT -d '
{
"cert": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
"key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",
"snis": ["api.example.com"]
}'
Переносить содержимое .pem-файлов в JSON руками неудобно — проще собрать запрос скриптом, который читает файлы и подставляет их через jq:
CERT=$(cat /etc/letsencrypt/live/api.example.com/fullchain.pem)
KEY=$(cat /etc/letsencrypt/live/api.example.com/privkey.pem)
jq -n --arg cert "$CERT" --arg key "$KEY" \
'{cert: $cert, key: $key, snis: ["api.example.com"]}' | \
curl -i "http://127.0.0.1:9180/apisix/admin/ssls/1" \
-H "X-API-KEY: ЗАМЕНИТЕ_НА_СЛУЧАЙНУЮ_СТРОКУ_32+_СИМВОЛА" \
-X PUT -d @-
Продление Let's Encrypt происходит отдельно от APISIX — certbot обновляет файлы на диске, а вам нужен хук, который после renew перезаливает сертификат в etcd тем же запросом (обычный deploy-hook в конфиге certbot). Автоматического подхвата обновлённого файла с диска, как у Nginx с ssl_certificate, здесь нет — это одно из ограничений APISIX, о котором стоит знать заранее.
Плагины: лимиты, авторизация, метрики
Плагины включаются per-route прямо в теле маршрута, без отдельных модулей. Три самых востребованных в проде:
Rate limiting — защита от перебора и грубого DDoS на уровне приложения:
"plugins": {
"limit-req": {
"rate": 10,
"burst": 5,
"key_type": "var",
"key": "remote_addr"
}
}
JWT-авторизация — проверка токена на входе, без своей логики в бэкенде:
"plugins": {
"jwt-auth": {}
}
Для jwt-auth сначала нужно создать consumer с секретом через /apisix/admin/consumers, а уже клиент присылает токен, подписанный этим секретом.
Prometheus — экспорт метрик по каждому маршруту (RPS, латентность, коды ответов):
"plugins": {
"prometheus": {}
}
После включения метрики доступны на http://127.0.0.1:9091/apisix/prometheus/metrics (порт настраивается) — их можно скрейпить тем же Prometheus, что уже собирает метрики с других контейнеров вашего стека.
Полный список плагинов (IP restriction, CORS, request-id, proxy-cache, cache, opentelemetry и другие) смотрите в документации проекта — набор регулярно пополняется, и версии плагинов привязаны к версии образа apache/apisix.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Чем APISIX лучше обычного Nginx для API?
Тем, что маршруты, upstream'ы и плагины меняются через REST API без перезагрузки процесса и без риска сломать текстовый конфиг опечаткой. Для статичного набора из пары location'ов разница не критична — там проще Nginx как reverse proxy.
Обязателен ли etcd, нельзя ли обойтись без него?
Начиная с APISIX есть standalone-режим с конфигурацией из YAML-файла (без etcd), но он теряет главное преимущество — динамические изменения без перезапуска. Для прода с активно меняющимися маршрутами держат etcd, для простого статичного шлюза standalone-режим может быть избыточен по сложности установки ради того же результата, что даёт Nginx.
APISIX и Kong — в чём разница?
Оба — плагинные API-шлюзы поверх Nginx/OpenResty. Kong традиционно использует PostgreSQL или свой DB-less режим, APISIX — etcd. Разница на практике чаще всего в наборе плагинов и личных предпочтениях команды; если уже пробовали Kong Gateway в Docker Compose, сравнение будет нагляднее на своих задачах.
Как защитить Admin API от посторонних?
Три вещи обязательны: сменить дефолтный admin_key, ограничить allow_admin реальными IP (а не 0.0.0.0/0, как в примере выше для локальной отладки) и закрыть порт 9180 в ufw для всех, кроме доверенных адресов.
Нужен ли отдельный VPS под APISIX или можно на том же сервере, где бэкенд?
Можно на одном — легковесная связка APISIX + однонодовый etcd на 2 vCPU / 2-4 GB RAM спокойно уживается с несколькими бэкенд-контейнерами. Разносить стоит, когда трафик через шлюз растёт настолько, что нагрузка от etcd (диск, iops) начинает мешать основным сервисам.
Что делать, если etcd упал?
APISIX держит в памяти последнюю применённую конфигурацию и продолжает проксировать трафик по ней, но новые изменения через Admin API применяться не будут, пока etcd не поднимется обратно. Резервное копирование данных etcd (папка etcd_data в примере выше) — обязательная часть плана бэкапов, как и для любого stateful-контейнера.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →