Esta es la primera entrada de nuestra serie sobre la implementación de NGINX Open Source y NGINX Plus como puerta de enlace de API:
- Esta entrada proporciona instrucciones de configuración detalladas para varios casos de uso. Publicada originalmente en 2018, se ha actualizado para reflejar las prácticas recomendadas actuales de configuración de API, utilizando bloques
locationanidados para enrutar las solicitudes en lugar de reglas de reescritura. - Parte 2 amplía esos casos de uso y analiza una serie de medidas de protección que pueden aplicarse para proteger y asegurar los servicios de API de backend en producción.
- Parte 3 explica cómo implementar NGINX Open Source y NGINX Plus como puerta de enlace de API para servicios gRPC.
Nota: Salvo que se indique lo contrario, toda la información de esta publicación se aplica tanto a NGINX Open Source como a NGINX Plus. Para facilitar la lectura, en el resto del blog se utiliza simplemente «NGINX».
La API HTTP constituye el núcleo de las arquitecturas de aplicaciones modernas. HTTP permite desarrollar aplicaciones rápidamente y mantenerlas con facilidad. La API HTTP proporciona una interfaz común, independientemente de la escala de la aplicación, desde un microservicio con una única finalidad hasta un monolito que lo abarca todo. Gracias al uso de HTTP, los avances en la entrega de aplicaciones web que permiten dar servicio a sitios de Internet a hiperescala también pueden aprovecharse para ofrecer API fiables y de alto rendimiento.
Para obtener una excelente introducción a la importancia de las puertas de enlace de API para las aplicaciones de microservicios, consulte Creación de microservicios: uso de una puerta de enlace de API en nuestro blog.
Como proxy inverso y equilibrador de carga ligero y de alto rendimiento líder del mercado, NGINX cuenta con las funciones avanzadas de procesamiento HTTP necesarias para gestionar el tráfico de las API. Esto convierte a NGINX en la plataforma ideal para crear una puerta de enlace de API. En esta entrada del blog describimos varios casos de uso habituales de las puertas de enlace de API y mostramos cómo configurar NGINX para gestionarlos de forma eficiente, escalable y fácil de mantener. También describimos una configuración completa que puede servir como base para un despliegue en producción.
Presentación de la API de Warehouse
La función principal de la puerta de enlace de API es proporcionar un punto de entrada único y coherente para varias API, independientemente de cómo estén implementadas o desplegadas en el backend. No todas las API son aplicaciones de microservicios. Nuestra puerta de enlace de API debe gestionar las API existentes, los monolitos y las aplicaciones que están realizando una transición parcial a los microservicios.
En esta entrada del blog nos referimos a una API hipotética para la gestión de inventarios, la «API de almacén». Utilizamos ejemplos de código de configuración para ilustrar distintos casos de uso. La API de almacén es una API RESTful que recibe solicitudes JSON y genera respuestas JSON. Sin embargo, el uso de JSON no supone una limitación ni un requisito de NGINX cuando se implementa como puerta de enlace de API; NGINX es independiente del estilo arquitectónico y de los formatos de datos utilizados por las propias API.
La API de almacén se implementa como un conjunto de microservicios independientes y se publica como una única API. Los recursos de inventario y precios se implementan como servicios separados y se despliegan en distintos backends. Por tanto, la estructura de rutas de la API es la siguiente:
api
└── warehouse
├── inventory
└── pricingPor ejemplo, para consultar el inventario actual del almacén, una aplicación cliente realiza una solicitud HTTP GET a /api/warehouse/inventory.

Organización de la configuración de NGINX
Una de las ventajas de utilizar NGINX como puerta de enlace de API es que puede desempeñar esa función y, al mismo tiempo, actuar como proxy inverso, equilibrador de carga y servidor web para el tráfico HTTP existente. Si NGINX ya forma parte de su infraestructura de entrega de aplicaciones, por lo general no es necesario implementar una puerta de enlace de API independiente. Sin embargo, algunos de los comportamientos predeterminados que se esperan de una puerta de enlace de API difieren de los esperados para el tráfico procedente de navegadores. Por ese motivo, separamos la configuración de la puerta de enlace de API de cualquier configuración existente (o futura) para el tráfico procedente de navegadores.
Para lograr esta separación, creamos una estructura de configuración compatible con una instancia de NGINX multipropósito y que facilita la automatización del despliegue de la configuración mediante canalizaciones de CI/CD. La estructura de directorios resultante en /etc/nginx es la siguiente.
etc/
└── nginx/
├── api_conf.d/ ………………………………… Subdirectory for per-API configuration
│ └── warehouse_api.conf …… Definition and policy of the Warehouse API
├── api_backends.conf ………………… The backend services (upstreams)
├── api_gateway.conf …………………… Top-level configuration for the API gateway server
├── api_json_errors.conf ………… HTTP error responses in JSON format
├── conf.d/
│ ├── ...
│ └── existing_apps.conf
└── nginx.confLos directorios y nombres de archivo de toda la configuración de la puerta de enlace de API llevan el prefijo api_. Cada uno de estos archivos y directorios habilita una función o capacidad diferente de la puerta de enlace de API, como se explica en detalle a continuación. El archivo warehouse_api.conf es un ejemplo genérico que representa los archivos de configuración descritos a continuación, que definen la API de almacén de distintas maneras.
Definición de la puerta de enlace de API de nivel superior
Toda la configuración de NGINX parte del archivo de configuración principal, nginx.conf. Para cargar la configuración de la puerta de enlace de API, añadimos una directiva include en el bloque http de nginx.conf que hace referencia al archivo que contiene la configuración de la puerta de enlace, api_gateway.conf (línea 28, justo debajo). Tenga en cuenta que el archivo nginx.conf predeterminado utiliza una directiva include para cargar la configuración HTTP para navegadores desde el subdirectorio conf.d (línea 29). En esta entrada del blog se utiliza ampliamente la directiva include para facilitar la lectura y permitir la automatización de algunas partes de la configuración.
Cargando ejemplo de código…
El archivo api_gateway.conf define el servidor virtual que presenta NGINX a los clientes como una puerta de enlace de API. Esta configuración presenta todas las API publicadas por la puerta de enlace de API en un único punto de entrada: https://api.example.com/ (línea 9), protegido mediante TLS según la configuración de las líneas 12 a 17. Tenga en cuenta que esta configuración utiliza exclusivamente HTTPS, es decir, no hay ningún proceso de escucha HTTP sin cifrar. Se presupone que los clientes de API conocen el punto de entrada correcto y establecen conexiones HTTPS de forma predeterminada.
Esta configuración está pensada para ser estática: los detalles de cada API y sus servicios de backend se especifican en los archivos a los que hace referencia la directiva include de la línea 20. Las líneas 23 a 26 se ocupan de la gestión de errores y se explican más adelante, en Respuesta a errores.
Cargando ejemplo de código…
Backends de API de servicio único frente a microservicios
Algunas API pueden implementarse en un único backend, aunque normalmente esperamos que haya más de uno por motivos de resiliencia o equilibrio de carga. En las API basadas en microservicios, definimos backends individuales para cada servicio; en conjunto, funcionan como la API completa. En este caso, nuestra API de almacén se despliega como dos servicios independientes, cada uno con varios backends.
Cargando ejemplo de código…
Todos los servicios de API de backend correspondientes a todas las API publicadas por la puerta de enlace de API se definen en api_backends.conf. Aquí utilizamos varios pares de dirección IP y puerto en cada bloque upstream para indicar dónde está implementado el código de la API, aunque también se pueden utilizar nombres de host. Los suscriptores de NGINX Plus también pueden aprovechar el equilibrado de carga DNS dinámico para que los nuevos backends se añadan automáticamente a la configuración en tiempo de ejecución.
Definición de la API de almacén
La API de almacén se define mediante varios bloques location en una configuración anidada, como se muestra en el siguiente ejemplo. El bloque location exterior (/api/warehouse) identifica la ruta base, bajo la cual las ubicaciones anidadas especifican los URI válidos que se enrutan a los servicios de API de backend. El uso de un bloque exterior nos permite definir políticas comunes que se aplican a toda la API (en este ejemplo, la configuración de registro de la línea 6).
Cargando ejemplo de código…
NGINX cuenta con un sistema muy eficiente y flexible para asociar el URI de la solicitud con una sección de la configuración. El orden de las directivas location no es importante: se elige la coincidencia más específica. En este caso, las ubicaciones anidadas de las líneas 10 y 14 definen dos URI más específicos que el bloque location externo; la directiva proxy_pass de cada bloque anidado dirige las solicitudes al grupo de servidores upstream correspondiente. La configuración de políticas se hereda de la ubicación externa, salvo que sea necesario proporcionar una política más específica para determinados URI.
Los URI que no coincidan con ninguna de las ubicaciones anidadas se gestionan mediante la ubicación externa, que incluye una directiva general (línea 18) que devuelve la respuesta 404 (No encontrado) para todos los URI no válidos.
Elegir entre una definición amplia y una precisa para las API
Existen dos enfoques para definir una API: uno amplio y otro preciso. El enfoque más adecuado para cada API depende de sus requisitos de seguridad y de si es conveniente que los servicios de backend gestionen URI no válidos.
En warehouse_api_simple.conf anterior, utilizamos el enfoque amplio para la API de almacén y definimos prefijos de URI en las líneas 10 y 14, de modo que cualquier URI que comience por uno de esos prefijos se redirija mediante proxy al servicio de backend correspondiente. Con esta coincidencia amplia de ubicaciones basada en prefijos, las solicitudes a la API dirigidas a los siguientes URI son válidas:
/api/warehouse/inventory
/api/warehouse/inventory/
/api/warehouse/inventory/foo
/api/warehouse/inventoryfoo
/api/warehouse/inventoryfoo/bar/
Si la única consideración es redirigir cada solicitud al servicio de backend correcto, el enfoque general ofrece el procesamiento más rápido y la configuración más compacta. Por otro lado, un enfoque más preciso permite que la puerta de enlace de API comprenda todo el espacio de URI de la API al definir explícitamente la ruta URI de cada recurso de API disponible. Siguiendo el enfoque preciso, la siguiente configuración del enrutamiento de URI en la API Warehouse utiliza una combinación de coincidencias exactas (=) y expresiones regulares (~) para definir todas y cada una de las URI válidas.
Cargando ejemplo de código…
Esta configuración es más detallada, pero describe con mayor precisión los recursos implementados por los servicios de backend. Esto ofrece la ventaja de proteger dichos servicios frente a solicitudes de clientes con un formato incorrecto, a costa de una pequeña sobrecarga adicional debida a la comparación de expresiones regulares. Con esta configuración, NGINX acepta algunos URI y rechaza otros por considerarlos no válidos:
URI válidos URI no válidos/api/warehouse/inventory /api/warehouse/inventory//api/warehouse/inventory/shelf/foo /api/warehouse/inventoryfoo/api/warehouse/inventory/shelf/foo/box/bar /api/warehouse/inventory/shelf/api/warehouse/inventory/shelf/-/box/- /api/warehouse/inventory/shelf/foo/bar/api/warehouse/pricing/baz /api/warehouse/pricing /api/warehouse/pricing/baz/pub
El uso de una definición precisa de la API permite utilizar los formatos de documentación de API existentes para configurar la puerta de enlace de API. Es posible automatizar las definiciones de API de NGINX a partir de la especificación OpenAPI (anteriormente denominada Swagger). Entre los Gists de esta entrada del blog se incluye un script de ejemplo para este fin.
Reescritura de solicitudes de clientes para gestionar cambios incompatibles
A medida que las API evolucionan, a veces es necesario realizar cambios que rompen la compatibilidad estricta con versiones anteriores y obligan a actualizar los clientes. Un ejemplo de ello es cuando se cambia el nombre o la ubicación de un recurso de una API. A diferencia de un navegador web, una puerta de enlace de API no puede enviar a sus clientes una redirección (código 301 (Movido permanentemente)) que indique la nueva ubicación. Afortunadamente, cuando no resulta práctico modificar los clientes de la API, podemos reescribir sus solicitudes sobre la marcha.
En el siguiente ejemplo, utilizamos el mismo enfoque general que en warehouse_api_simple.conf anterior, pero en este caso la configuración sustituye una versión anterior de la API de almacén, en la que el servicio de precios estaba implementado como parte del servicio de inventario. La directiva rewrite de la línea 3 convierte las solicitudes dirigidas al antiguo recurso de precios en solicitudes dirigidas al nuevo servicio de precios.
Cargando ejemplo de código…
Respuesta a errores
Una de las principales diferencias entre las API HTTP y el tráfico basado en navegadores es la forma en que se comunican los errores al cliente. Cuando NGINX se implementa como puerta de enlace de API, lo configuramos para que devuelva los errores de la manera que mejor se adapte a los clientes de la API.
La configuración de nivel superior de la puerta de enlace de API incluye una sección que define cómo gestionar las respuestas de error.
Cargando ejemplo de código…
La directiva error_page de la línea 23 especifica que, cuando una solicitud no coincide con ninguna de las definiciones de la API, NGINX devuelve el error 400 (Solicitud incorrecta) en lugar del error predeterminado 404 (No encontrado). Este comportamiento (opcional) exige que los clientes de la API solo realicen solicitudes a los URI válidos incluidos en la documentación de la API e impide que los clientes no autorizados descubran la estructura de URI de las API publicadas a través de la puerta de enlace de API.
La línea 24 hace referencia a los errores generados por los propios servicios de backend. Las excepciones no controladas pueden contener trazas de pila u otros datos confidenciales que no queremos que se envíen al cliente. Esta configuración añade un nivel adicional de protección al enviar una respuesta de error estandarizada al cliente.
La lista completa de respuestas de error estandarizadas se define en un archivo de configuración independiente al que hace referencia la directiva include de la línea 25, cuyas primeras líneas se muestran a continuación. Este archivo se puede modificar si se prefiere un formato de error distinto de JSON; en ese caso, el valor default_type de la línea 26 de api_gateway.conf debe cambiarse para que coincida. También puede incluir una directiva include independiente en la sección de políticas de cada API para hacer referencia a otro archivo de respuestas de error que sustituya las respuestas globales.
Cargando ejemplo de código…
Con esta configuración, una solicitud de cliente a un URI no válido recibe la siguiente respuesta. [terminal]$ curl -i https://api.example.com/foo HTTP/1.1 400 Solicitud incorrecta Server: nginx/1.19.5 Content-Type: application/json Content-Length: 39 Connection: keep-alive {"status":400,"message":"Solicitud incorrecta"}[/terminal]Implementación de la autenticación
No es habitual publicar API sin algún tipo de autenticación que las proteja. NGINX ofrece varios métodos para proteger las API y autenticar a sus clientes. Para obtener información sobre métodos que también se aplican a las solicitudes HTTP convencionales, consulte la documentación sobre listas de control de acceso basadas en direcciones IP (ACL), autenticación mediante certificados digitales y autenticación HTTP básica. Aquí nos centramos en los métodos de autenticación específicos para API.
Autenticación mediante clave de API
Las claves de API son un secreto compartido que conocen tanto el cliente como la puerta de enlace de la API. Una clave de API es, en esencia, una contraseña larga y compleja que se proporciona al cliente de la API como credencial a largo plazo. Crear claves de API es sencillo: basta con codificar un número aleatorio, como en este ejemplo.
$ openssl rand -base64 187B5zIqmRGXmrJTFmKa99vcitEn la línea 2 del archivo de configuración principal de la puerta de enlace de API, api_gateway.conf, incluimos un archivo llamado api_keys.conf, que contiene una clave de API para cada cliente de API, identificado por el nombre del cliente u otra descripción. Este es el contenido del archivo:
Cargando ejemplo de código…
Las claves de API se definen dentro de un bloque map. La directiva map acepta dos parámetros. El primero define dónde encontrar la clave de API, en este caso, en la cabecera HTTP apikey de la solicitud del cliente, tal como se recoge en la variable $http_apikey. El segundo parámetro crea una nueva variable ($api_client_name) y le asigna el valor del segundo parámetro de la línea en la que el primer parámetro coincide con la clave.
Por ejemplo, cuando un cliente presenta la clave de API 7B5zIqmRGXmrJTFmKa99vcit, la variable $api_client_name se establece en client_one. Esta variable se puede utilizar para comprobar si los clientes están autenticados e incluirse en las entradas de registro para realizar auditorías más detalladas. El formato del bloque map es sencillo y fácil de integrar en flujos de trabajo automatizados que generan el archivo api_keys.conf a partir de un almacén de credenciales existente.
Aquí habilitamos la autenticación mediante clave de API modificando la configuración «amplia» (warehouse_api_simple.conf) para incluir una directiva auth_request en la sección de políticas que delega la decisión de autenticación en una ubicación específica.
Cargando ejemplo de código…
Con la directiva auth_request (línea 7), podemos, por ejemplo, hacer que la autenticación la gestione un servidor de autenticación externo, como la introspección de tokens de OAuth 2.0. En este ejemplo, en cambio, añadimos la lógica para validar las claves de API al archivo de configuración principal de la puerta de enlace de API, mediante el siguiente bloque location denominado /_validate_apikey.
Cargando ejemplo de código…
La directiva internal de la línea 30 significa que los clientes externos no pueden acceder directamente a esta ubicación (solo mediante auth_request). Los clientes deben proporcionar su clave de API en la cabecera HTTP apikey. Si esta cabecera no está presente o está vacía (línea 32), enviamos una respuesta 401 (No autorizado) para indicar al cliente que debe autenticarse. La línea 35 gestiona el caso en el que la clave de API no coincide con ninguna de las claves del bloque map; en ese caso, el parámetro default de la línea 2 de api_keys.conf establece $api_client_name como una cadena vacía, y enviamos una respuesta 403 (Prohibido) para indicar al cliente que la autenticación ha fallado. Si no se cumple ninguna de esas condiciones, la clave de API es válida y la ubicación devuelve una respuesta 204 (Sin contenido).
Con esta configuración, la API de Warehouse ahora implementa la autenticación mediante clave de API.
$ curl https://api.example.com/api/warehouse/pricing/item001{"status":401,"message":"Unauthorized"}
$ curl -H "apikey: thisIsInvalid" https://api.example.com/api/warehouse/pricing/item001
{"status":403,"message":"Forbidden"}
$ curl -H "apikey: 7B5zIqmRGXmrJTFmKa99vcit" https://api.example.com/api/warehouse/pricing/item001
{"sku":"item001","price":179.99}Autenticación JWT
Los tokens web JSON (JWT) se utilizan cada vez más para la autenticación de API. La compatibilidad nativa con JWT es exclusiva de NGINX Plus y permite validar los JWT tal como se describe en Autenticación de clientes de API con JWT y NGINX Plus en nuestro blog. Para ver un ejemplo de implementación, consulte Control del acceso a métodos específicos en la parte 2.
Resumen
Este primer artículo de una serie detalla una solución completa para implementar NGINX Open Source y NGINX Plus como puerta de enlace de API. El conjunto completo de archivos tratados en este artículo se puede consultar y descargar desde nuestro repositorio de GitHub Gist.
Consulta las demás entradas de esta serie:
- La parte 2 explora casos de uso más avanzados para proteger los servicios de backend frente a clientes maliciosos o con un comportamiento inadecuado.
- Parte 3 explica cómo implementar NGINX como puerta de enlace de API para servicios gRPC.
Para probar NGINX Plus, inicie hoy mismo su prueba gratuita de 30 días o póngase en contacto con nosotros para hablar sobre sus casos de uso.
Sobre el autor

Artículos relacionados del blog
Únete a F5 NGINX en AppWorld 2024
Descubre las numerosas razones para asistir al evento insignia de F5, que incluirá un emocionante anuncio sobre la cartera de productos NGINX.
Rotación de certificados SSL/TLS sin reinicios en NGINX Open Source
La función de diccionario compartido permite configurar NGINX sin necesidad de reiniciarlo al renovar los certificados SSL/TLS.
Exposición de APIs en Kubernetes
La unidad 2 de Microservices March 2022 se centra en cómo exponer tus API en Kubernetes. Aquí tienes enlaces a los recursos que necesitas: la retransmisión en directo del 14 de marzo, artículos de blog y otros recursos de preparación, y el laboratorio práctico «Protege las API de Kubernetes mediante la limitación de solicitudes».
NGINX Sprint 2.0: visión clara, código renovado y nuevos compromisos con el código abierto
Hoy, en NGINX Sprint 2.0, anunciamos cómo respaldaremos nuestra visión del futuro de las aplicaciones modernas con una mayor presencia en la comunidad de código abierto, incluida la participación en el proyecto comunitario Kubernetes, nuevos proyectos de software de código abierto y la arquitectura de referencia para aplicaciones modernas.
Presentamos NGINX Plus R22
NGINX Plus R22 incorpora nuevas funcionalidades, como la compatibilidad con OCSP para verificar la revocación de certificados en TLS mutuo, el uso de varios proveedores de identidad OIDC en una configuración, el seguimiento en tiempo real de la limitación de solicitudes y conexiones en el panel de NGINX Plus y mejoras en NGINX JavaScript.
Presentamos NGINX Plus R17
NGINX Plus R17 incorpora compatibilidad con la limitación de velocidad en dos fases y con TLS 1.3, la versión más reciente del protocolo Transport Layer Security. La configuración de OpenID Connect es más sencilla y NGINX ModSecurity WAF es el doble de rápido que antes. También se ha actualizado el módulo JavaScript de NGINX.