--- title: "Cómo configurar Apache APISIX con Docker en Ubuntu 24.04" description: "Despliega Apache APISIX y etcd con Docker Compose en Ubuntu 24.04, crea rutas con la Admin API y protégelas con key-auth, limit-count y un certificado TLS." category: "Proxy y Equilibrio de Carga" language: es source: https://cubepath.com/es/docs/proxy-y-equilibrio-de-carga/configuracion-de-la-puerta-de-api-apisix updated: 2026-09-25 --- # Cómo configurar Apache APISIX con Docker en Ubuntu 24.04 Apache APISIX es una puerta de enlace de API de código abierto basada en Nginx y OpenResty. Guarda su configuración en etcd, de modo que las rutas, los upstreams y los plugins que creas con su Admin API se aplican al instante en todos los nodos, sin recargas. En este tutorial desplegarás APISIX y etcd con Docker Compose en Ubuntu 24.04, publicarás un servicio de prueba y lo protegerás con autenticación por clave, un límite de peticiones y un certificado TLS. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS y al menos 2 GB de RAM, por ejemplo un VPS de CubePath. - Un usuario no root con privilegios `sudo`. - Docker Engine y el plugin de Docker Compose instalados desde el repositorio oficial de Docker, con tu usuario en el grupo `docker`. - `curl` y `jq`: `sudo apt install curl jq`. - Opcional, para el paso 7: un dominio apuntando al servidor y un certificado para él (por ejemplo, emitido con Certbot). ## Conceptos de APISIX | Objeto | Qué representa | |---|---| | Upstream | Un grupo de nodos backend con su algoritmo de balanceo y sus comprobaciones de salud. | | Route | La regla que asocia peticiones (URI, host, método) con un upstream y con plugins. | | Consumer | Un cliente de la API, con sus credenciales. | | Plugin | Funcionalidad (autenticación, límites, reescritura) aplicada a una ruta, un servicio, un consumidor o de forma global. | | SSL | Un certificado y su clave, asociados a uno o varios nombres (SNI). | APISIX escucha en el puerto 9080 (HTTP) y 9443 (HTTPS) para el tráfico de clientes, y en el 9180 para la Admin API, que da control total sobre el gateway y nunca debe quedar expuesta a Internet. ## Paso 1: Preparar el proyecto y la clave de administración Crea un directorio para el despliegue: ```bash mkdir -p ~/apisix && cd ~/apisix ``` Genera una clave aleatoria para la Admin API y cópiala; la usarás en el archivo de configuración: ```bash openssl rand -hex 16 ``` ```output 3f9c2b7e6a1d48c0b5e2f7a9d1c3e8b4 ``` Guárdala en una variable de entorno para usarla en los comandos de este tutorial, sustituyendo `your_admin_key` por el valor generado: ```bash export ADMIN_KEY=your_admin_key ``` ## Paso 2: Escribir la configuración de APISIX Crea el archivo de configuración: ```bash nano ~/apisix/config.yaml ``` ```yaml apisix: node_listen: 9080 deployment: role: traditional role_traditional: config_provider: etcd admin: admin_key_required: true admin_key: - name: admin key: your_admin_key role: admin allow_admin: - 0.0.0.0/0 etcd: host: - "http://etcd:2379" prefix: "/apisix" timeout: 30 ``` - `admin_key`: sustituye `your_admin_key` por la clave generada en el paso 1. Todas las llamadas a la Admin API deberán enviarla en la cabecera `X-API-KEY`. - `allow_admin`: permite la Admin API desde cualquier IP del lado del contenedor. Es seguro solo porque en el paso siguiente el puerto 9180 se publica únicamente en `127.0.0.1` del servidor. - `etcd`: APISIX guarda la configuración bajo el prefijo `/apisix` del etcd definido en Compose. El archivo contiene la clave, pero el contenedor de APISIX, que no se ejecuta con tu usuario, necesita leerlo. En lugar de restringir el archivo, restringe el directorio para que otros usuarios del servidor no puedan acceder a él: ```bash chmod 700 ~/apisix ``` ## Paso 3: Definir los contenedores Crea el archivo de Compose: ```bash nano ~/apisix/compose.yaml ``` ```yaml services: etcd: image: quay.io/coreos/etcd:v3.5.21 restart: unless-stopped command: - etcd - --name=etcd0 - --data-dir=/etcd-data - --listen-client-urls=http://0.0.0.0:2379 - --advertise-client-urls=http://etcd:2379 volumes: - etcd-data:/etcd-data apisix: image: apache/apisix:3.12.0-debian restart: unless-stopped depends_on: - etcd volumes: - ./config.yaml:/usr/local/apisix/conf/config.yaml:ro ports: - "80:9080" - "443:9443" - "127.0.0.1:9180:9180" httpbin: image: mccutchen/go-httpbin restart: unless-stopped volumes: etcd-data: ``` - etcd no publica puertos: solo APISIX accede a él por la red interna de Compose. - El tráfico de clientes llega por los puertos 80 y 443 del servidor; la Admin API solo desde el propio servidor. - `httpbin` es una aplicación de prueba que devuelve los datos de cada petición. En producción la sustituirás por tus servicios. Consulta en Docker Hub la última versión estable de `apache/apisix` con sufijo `-debian` si quieres una más reciente que la del ejemplo. > Importante: los puertos publicados por Docker no pasan por las reglas de UFW. Por eso la Admin API se enlaza explícitamente a `127.0.0.1`. ## Paso 4: Arrancar la pila ```bash docker compose up -d docker compose ps ``` ```output NAME IMAGE STATUS apisix-apisix-1 apache/apisix:3.12.0-debian Up 10 seconds apisix-etcd-1 quay.io/coreos/etcd:v3.5.21 Up 11 seconds apisix-httpbin-1 mccutchen/go-httpbin Up 11 seconds ``` Comprueba que la Admin API responde con tu clave y que aún no hay rutas: ```bash curl -s http://127.0.0.1:9180/apisix/admin/routes -H "X-API-KEY: $ADMIN_KEY" | jq ``` ```output { "total": 0, "list": [] } ``` Sin la cabecera, o con una clave incorrecta, la respuesta es `401`. Una petición al proxy devuelve 404 porque no hay ninguna ruta: ```bash curl -s http://localhost/ ``` ```output {"error_msg":"404 Route Not Found"} ``` ## Paso 5: Crear un upstream y una ruta Crea un upstream llamado `httpbin` con balanceo round robin y una comprobación de salud activa. Para añadir más réplicas de la aplicación bastaría con añadir nodos a la lista `nodes`: ```bash curl -s -X PUT http://127.0.0.1:9180/apisix/admin/upstreams/httpbin \ -H "X-API-KEY: $ADMIN_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "roundrobin", "nodes": [ { "host": "httpbin", "port": 8080, "weight": 1 } ], "checks": { "active": { "type": "http", "http_path": "/status/200", "healthy": { "interval": 5, "successes": 2 }, "unhealthy": { "interval": 5, "http_failures": 3 } } } }' | jq '.value | {id, type}' ``` ```output { "id": "httpbin", "type": "roundrobin" } ``` Las rutas se van a ir ampliando con plugins, así que es más cómodo mantenerlas en un archivo JSON y enviarlo completo con `PUT`, que crea o reemplaza el objeto: ```bash nano ~/apisix/route-demo.json ``` ```json { "name": "demo", "uri": "/demo/*", "upstream_id": "httpbin", "plugins": { "proxy-rewrite": { "regex_uri": ["^/demo/(.*)", "/$1"] } } } ``` El plugin `proxy-rewrite` elimina el prefijo `/demo`, de modo que `/demo/get` llega a la aplicación como `/get`. Crea la ruta: ```bash curl -s -X PUT http://127.0.0.1:9180/apisix/admin/routes/demo \ -H "X-API-KEY: $ADMIN_KEY" \ -H "Content-Type: application/json" \ -d @route-demo.json | jq '.value | {id, uri}' ``` Prueba la ruta a través del proxy: ```bash curl -s -o /dev/null -w '%{http_code}\n' http://localhost/demo/status/418 ``` ```output 418 ``` `httpbin` responde en `/status/` con el código que se le pide. Recibir un `418` confirma que la petición ha llegado a la aplicación como `/status/418`, sin el prefijo. Para enrutar por dominio, añade `"host": "api.your_domain"` al JSON de la ruta. ## Paso 6: Añadir autenticación y límite de peticiones Crea un consumidor con una clave de API. El nombre de un consumidor solo admite letras, números y guiones bajos: ```bash API_KEY=$(openssl rand -hex 20) curl -s -X PUT http://127.0.0.1:9180/apisix/admin/consumers \ -H "X-API-KEY: $ADMIN_KEY" \ -H "Content-Type: application/json" \ -d "{\"username\": \"app_client\", \"plugins\": {\"key-auth\": {\"key\": \"$API_KEY\"}}}" \ | jq '.value.username' echo "$API_KEY" ``` Guarda la clave que muestra el último comando: es la que entregarás al cliente. Edita la ruta para añadir los plugins `key-auth` y `limit-count`: ```bash nano ~/apisix/route-demo.json ``` ```json { "name": "demo", "uri": "/demo/*", "upstream_id": "httpbin", "plugins": { "proxy-rewrite": { "regex_uri": ["^/demo/(.*)", "/$1"] }, "key-auth": {}, "limit-count": { "count": 5, "time_window": 60, "key_type": "var", "key": "remote_addr", "rejected_code": 429, "policy": "local" } } } ``` - `key-auth` exige la clave en la cabecera `apikey`. - `limit-count` permite 5 peticiones por minuto y por IP de origen, un valor bajo para poder probarlo. La política `local` cuenta en memoria de cada nodo; con varios nodos, usa `redis` para compartir el contador. Aplica la nueva versión de la ruta: ```bash curl -s -X PUT http://127.0.0.1:9180/apisix/admin/routes/demo \ -H "X-API-KEY: $ADMIN_KEY" \ -H "Content-Type: application/json" \ -d @route-demo.json | jq '.value.plugins | keys' ``` ```output [ "key-auth", "limit-count", "proxy-rewrite" ] ``` Comprueba que sin clave la petición se rechaza y que con clave pasa hasta alcanzar el límite: ```bash curl -s -o /dev/null -w '%{http_code}\n' http://localhost/demo/get for i in $(seq 1 6); do curl -s -o /dev/null -w '%{http_code}\n' -H "apikey: $API_KEY" http://localhost/demo/get done ``` ```output 401 200 200 200 200 200 429 ``` Las respuestas incluyen las cabeceras `X-RateLimit-Limit`, `X-RateLimit-Remaining` y `X-RateLimit-Reset` para que el cliente sepa cuánto margen le queda: ```bash curl -s -D - -o /dev/null -H "apikey: $API_KEY" http://localhost/demo/get | grep -i ratelimit ``` Por defecto la cabecera `apikey` también llega al backend. Si no quieres que la aplicación vea la clave del cliente, configura el plugin como `"key-auth": {"hide_credentials": true}`. ## Paso 7: Añadir un certificado TLS APISIX elige el certificado por SNI entre los objetos `ssls` guardados en etcd. Construye el JSON con `jq`, que se encarga de escapar los saltos de línea del PEM, y envíalo a la Admin API. La clave privada solo es legible por root, por eso `jq` se ejecuta con `sudo`: ```bash sudo jq -n \ --rawfile cert /etc/letsencrypt/live/your_domain/fullchain.pem \ --rawfile key /etc/letsencrypt/live/your_domain/privkey.pem \ --arg sni your_domain \ '{cert: $cert, key: $key, snis: [$sni]}' \ | curl -s -X PUT http://127.0.0.1:9180/apisix/admin/ssls/your_domain \ -H "X-API-KEY: $ADMIN_KEY" \ -H "Content-Type: application/json" \ -d @- | jq '.value.snis' ``` ```output [ "your_domain" ] ``` Comprueba desde tu equipo que APISIX presenta el certificado. Como `curl` valida el certificado, un `200` confirma que es correcto (si acabas de agotar el límite del paso 6, espera un minuto): ```bash curl -s -o /dev/null -w '%{http_code}\n' -H "apikey: your_api_key" https://your_domain/demo/get ``` ```output 200 ``` Cuando renueves el certificado, repite el mismo comando: el `PUT` con el mismo identificador lo reemplaza sin reiniciar nada. Puedes automatizarlo con un hook de despliegue de Certbot en `/etc/letsencrypt/renewal-hooks/deploy/`. ## Paso 8: Revisar la configuración guardada Lista todas las rutas y los upstreams con sus identificadores: ```bash curl -s http://127.0.0.1:9180/apisix/admin/routes -H "X-API-KEY: $ADMIN_KEY" \ | jq '.list[].value | {id, uri, plugins: (.plugins | keys)}' curl -s http://127.0.0.1:9180/apisix/admin/upstreams -H "X-API-KEY: $ADMIN_KEY" \ | jq '.list[].value | {id, type, nodes}' ``` Toda la configuración vive en el volumen `etcd-data`. Incluye ese volumen (o una instantánea con `etcdctl snapshot save`) en tus copias de seguridad, y guarda los archivos JSON de las rutas en un repositorio Git para poder recrearlas. ## Solución de problemas - **APISIX se reinicia en bucle**: mira `docker compose logs apisix`. Los errores habituales son YAML mal indentado en `config.yaml` o que etcd no está disponible todavía; en el segundo caso, APISIX se recupera solo en unos segundos. - **`401` en la Admin API**: la cabecera `X-API-KEY` no coincide con `admin_key` en `config.yaml`. Tras cambiar la clave, aplica los cambios con `docker compose restart apisix`. - **`404 Route Not Found`**: ninguna ruta coincide. Revisa `uri` y `host` con el comando del paso 8; recuerda que `/demo/*` no coincide con `/demo` sin barra final. - **`502 Bad Gateway`**: APISIX no llega al upstream. Comprueba el nombre y puerto de los nodos y revisa `docker compose logs apisix | grep -i upstream`. ## Conclusión APISIX funciona con etcd como almacén de configuración, publica un servicio a través de una ruta con reescritura de URI, exige claves de API, limita las peticiones y sirve HTTPS con tu certificado, todo configurado en caliente desde una Admin API accesible solo en local. Como siguientes pasos, puedes añadir más nodos al upstream, activar el plugin `prometheus` para exportar métricas o levantar un segundo nodo de APISIX contra el mismo etcd para tener alta disponibilidad.