# Enrutamiento HTTP con Traefik


## Introducción

Durante el desarrollo local, es bastante común necesitar ejecutar múltiples servicios HTTP. Es posible que tengas tanto una API como una aplicación frontend, un servicio de WireMock para simular puntos finales de datos (endpoints) o un visualizador de base de datos (como phpMyAdmin o pgAdmin). En muchas configuraciones de desarrollo, estos servicios se exponen en diferentes puertos, lo que requiere que recuerdes qué puerto corresponde a cada servicio, pero también puede introducir otros problemas (como CORS).

Un proxy inverso puede simplificar enormemente esta configuración al ser el único servicio expuesto y enrutar las solicitudes al servicio adecuado según la URL de la solicitud (ya sea por ruta o por nombre de host). [Traefik](https://traefik.io/traefik/) es un proxy inverso y balanceador de carga moderno y nativo de la nube que hace que el desarrollo y el despliegue de aplicaciones multiservicio sean más sencillos. Esta guía te mostrará cómo usar Traefik con Docker para mejorar tu entorno de desarrollo.

En esta guía, aprenderás a:

1. Iniciar Traefik con Docker
2. Configurar reglas de enrutamiento para dividir el tráfico entre dos contenedores
3. Usar Traefik en un entorno de desarrollo contenedorizado
4. Usar Traefik para enviar solicitudes a cargas de trabajo no contenedorizadas

## Requisitos previos

Se requieren los siguientes requisitos previos para seguir esta guía práctica:

- [Docker Desktop](https://www.docker.com/products/docker-desktop/)
- [Node.js](https://nodejs.org/en/download/package-manager) y [yarn](https://yarnpkg.com/)
- Conceptos básicos de Docker

## Uso de Traefik con Docker

Una de las características únicas de Traefik es su capacidad para configurarse de muchas formas. Al utilizar el proveedor de Docker, Traefik obtiene su configuración de otros contenedores en ejecución mediante [etiquetas (labels)](https://docs-docker.esdocu.com/config/labels-custom-metadata/). Traefik monitoreará los eventos del motor (para inicios y paradas de contenedores), extraerá las etiquetas y actualizará su configuración.

Aunque existen [muchas etiquetas monitoreadas por Traefik](https://doc.traefik.io/traefik/routing/providers/docker/), las dos más comunes serán:

- `traefik.http.routers.<nombre-del-servicio>.rule`: utilizada para indicar la regla de enrutamiento ([consulta todas las reglas disponibles aquí](https://doc.traefik.io/traefik/routing/routers/#rule))
- `traefik.http.services.<nombre-del-servicio>.loadbalancer.server.port`: indica el puerto al que Traefik debe reenviar la solicitud. Ten en cuenta que este puerto del contenedor no necesita estar expuesto en tu máquina host ([lee sobre la detección de puertos aquí](https://doc.traefik.io/traefik/providers/docker/#port-detection))

Hagamos una demostración rápida de cómo iniciar Traefik y luego configurar dos contenedores adicionales para que sean accesibles utilizando diferentes nombres de host.

1. Para que dos contenedores puedan comunicarse entre sí, deben estar en la misma red. Crea una red llamada `traefik-demo` utilizando el comando `docker network create`:

   ```console
   $ docker network create traefik-demo
   ```

2. Inicia un contenedor Traefik utilizando uno de los siguientes métodos. Estos comandos exponen Traefik en el puerto 80, montan el socket de Docker (que se utiliza para monitorear los contenedores para actualizar la configuración) y pasan el argumento `--providers.docker` para configurar Traefik para que use el proveedor de Docker.

   **Usando Docker Hardened Images**



   Las imágenes protegidas de Docker (Docker Hardened Images - DHI) para Traefik están disponibles en [Docker Hub](https://hub.docker.com/hardened-images/catalog/dhi/traefik).
   Si aún no te has autenticado, primero ejecuta:

   ```bash
   $ docker login dhi.io
   ```

   Luego inicia un contenedor utilizando la imagen Hardened:

   ```console
   $ docker run -d --network=traefik-demo \
     -p 80:80 \
     -v /var/run/docker.sock:/var/run/docker.sock \
     dhi.io/traefik:3.6.2 \
     --providers.docker
   ```

   **Usando la imagen oficial**



   También puedes usar la imagen oficial de Docker Hub:

   ```console
   $ docker run -d --network=traefik-demo \
     -p 80:80 \
     -v /var/run/docker.sock:/var/run/docker.sock \
     traefik:v3.6.2 \
     --providers.docker
   ```

   

3. Ahora, inicia un contenedor Nginx simple y define las etiquetas que Traefik está monitoreando para configurar el enrutamiento HTTP. Ten en cuenta que el contenedor Nginx no expone ningún puerto.

   **Usando Docker Hardened Images**



   Las imágenes protegidas de Docker (DHI) para Nginx están disponibles en [Nginx DHI image](https://hub.docker.com/hardened-images/catalog/dhi/nginx).
   Si aún no te has autenticado, primero ejecuta:

   ```bash
   $ docker login dhi.io
   ```

   ```console
   $ docker run -d --network=traefik-demo \
     --label 'traefik.http.routers.nginx.rule=Host(`nginx.localhost`)' \
     dhi.io/nginx:1.29.3
   ```

   **Usando la imagen oficial**



   También puedes ejecutar la imagen oficial de Nginx de la siguiente manera:

   ```console
   $ docker run -d --network=traefik-demo \
     --label 'traefik.http.routers.nginx.rule=Host(`nginx.localhost`)' \
     nginx:1.29.3
   ```

   

   Una vez que el contenedor se inicie, abre tu navegador en [http://nginx.localhost](http://nginx.localhost) para ver la aplicación (todos los navegadores basados en Chromium enrutan las solicitudes `*.localhost` localmente sin necesidad de configuración adicional).

4. Inicia una segunda aplicación que utilizará un nombre de host diferente.

   ```console
   $ docker run -d --network=traefik-demo --label 'traefik.http.routers.welcome.rule=Host(`welcome.localhost`)' docker/welcome-to-docker
   ```

   Una vez que el contenedor se inicie, abre tu navegador en http://welcome.localhost. Deberías ver un sitio web "Welcome to Docker".

## Uso de Traefik en desarrollo

Ahora que has probado Traefik, es hora de intentar usarlo en un entorno de desarrollo. En este ejemplo, utilizarás una aplicación de ejemplo que tiene un frontend y un backend divididos. Esta pila de aplicaciones tiene la siguiente configuración:

1. Todas las solicitudes a /api van al servicio API.
2. Todas las demás solicitudes a localhost van al cliente frontend.
3. Dado que la aplicación utiliza MySQL, db.localhost debería proporcionar phpMyAdmin para facilitar el acceso a la base de datos durante el desarrollo.

![Diagrama de arquitectura que muestra a Traefik enrutando solicitudes a otros contenedores según la ruta de la solicitud](/guides/images/traefik-in-development.webp)

Se puede acceder a la aplicación en GitHub en [dockersamples/easy-http-routing-with-traefik](https://github.com/dockersamples/easy-http-routing-with-traefik).

1. En el archivo `compose.yaml`, Traefik está utilizando la siguiente configuración:

   **Usando la imagen DHI**



   ```yaml
   services:
     proxy:
       image: dhi.io/traefik:3.6.2
       command: --providers.docker
       ports:
         - 80:80
       volumes:
         - /var/run/docker.sock:/var/run/docker.sock
   ```

   **Usando la imagen oficial**



   ```yaml
   services:
     proxy:
       image: traefik:v3.6.2
       command: --providers.docker
       ports:
         - 80:80
       volumes:
         - /var/run/docker.sock:/var/run/docker.sock
   ```

   

   Ten en cuenta que esta es esencialmente la misma configuración que se usó anteriormente, pero ahora con la sintaxis de Compose.

2. El servicio client tiene la siguiente configuración, que iniciará el contenedor y le proporcionará las etiquetas para recibir solicitudes en localhost.

   **Usando Docker Hardened Images**



   Las imágenes protegidas de Docker (DHI) para Nginx están disponibles en [Nginx DHI image](https://hub.docker.com/hardened-images/catalog/dhi/nginx).

   Si aún no te has autenticado, primero ejecuta:

   ```bash
   $ docker login dhi.io
   ```

   Puedes usarlo como tu imagen base como se muestra a continuación:

   ```yaml
   services:
     # …
     client:
       image: dhi.io/nginx:1.29.3-alpine3.21
       volumes:
         - "./client:/usr/share/nginx/html"
       labels:
         traefik.http.routers.client.rule: "Host(`localhost`)"
   ```

   **Usando la imagen oficial**



   ```yaml
   services:
     # …
     client:
       image: nginx:1.29.3-alpine3.22
       volumes:
         - "./client:/usr/share/nginx/html"
       labels:
         traefik.http.routers.client.rule: "Host(`localhost`)"
   ```

   

3. El servicio api tiene una configuración similar, pero notarás que la regla de enrutamiento tiene dos condiciones: el host debe ser "localhost" y la ruta de la URL debe tener el prefijo "/api". Dado que esta regla es más específica, Traefik la evaluará primero en comparación con la regla del cliente.

   ```yaml {hl_lines=[7,8]}
   services:
     # …
     api:
       build: ./dev/api
       volumes:
         - "./api:/var/www/html/api"
       labels:
         traefik.http.routers.api.rule: "Host(`localhost`) && PathPrefix(`/api`)"
   ```

4. Y finalmente, el servicio `phpmyadmin` está configurado para recibir solicitudes para el nombre de host "db.localhost". El servicio también tiene variables de entorno definidas para iniciar sesión automáticamente, haciendo que sea un poco más sencillo ingresar a la aplicación.

   ```yaml {hl_lines=[5,6]}
   services:
     # …
     phpmyadmin:
       image: phpmyadmin:5.2.1
       labels:
         traefik.http.routers.db.rule: "Host(`db.localhost`)"
       environment:
         PMA_USER: root
         PMA_PASSWORD: password
   ```

5. Antes de iniciar la pila, detén el contenedor Nginx si aún se está ejecutando.

   Y eso es todo. Ahora, solo necesitas poner en marcha la pila de Compose con `docker compose up` y todos los servicios y aplicaciones estarán listos para el desarrollo.

## Enviar tráfico a cargas de trabajo no contenedorizadas

En algunas situaciones, es posible que desees reenviar solicitudes a aplicaciones que no se ejecutan en contenedores. En el siguiente diagrama de arquitectura, se utiliza la misma aplicación de antes, pero la API y las aplicaciones de React ahora se ejecutan de forma nativa en la máquina host.

![Un diagrama de arquitectura que muestra varios componentes y el enrutamiento entre ellos. Traefik puede enviar solicitudes tanto a cargas de trabajo contenedorizadas como no contenedorizadas](/guides/traefik/images/traefik-non-containerized-workload-architecture.webp)

Para lograr esto, Traefik necesitará usar otro método para configurarse. Con el proveedor File puedes definir las reglas de enrutamiento en un documento YAML. Aquí tienes un archivo de ejemplo:

```yaml
http:
  routers:
    native-api:
      rule: "Host(`localhost`) && PathPrefix(`/api`)"
      service: native-api
    native-client:
      rule: "Host(`localhost`)"
      service: native-client

  services:
    native-api:
      loadBalancer:
        servers:
          - url: "http://host.docker.internal:3000/"
    native-client:
      loadBalancer:
        servers:
          - url: "http://host.docker.internal:5173/"
```

Esta configuración indica que las solicitudes para `localhost/api` se reenviarán a un servicio llamado `native-api`, que luego reenvía la solicitud a http://host.docker.internal:3000. El nombre de host `host.docker.internal` es un nombre que proporciona Docker Desktop para enviar solicitudes a la máquina host.

Con este archivo, el único cambio es en la configuración de Compose para Traefik. Específicamente, han cambiado dos cosas:

1. El archivo de configuración se monta dentro del contenedor Traefik (la ruta de destino exacta depende de ti).
2. Se actualiza el comando (`command`) para añadir el proveedor file y apuntar a la ubicación del archivo de configuración.

  **Usando la imagen DHI**



  ```yaml
  services:
    proxy:
      image: dhi.io/traefik:3.6.2
      command: --providers.docker --providers.file.filename=/config/traefik-config.yaml --api.insecure
      ports:
        - 80:80
        - 8080:8080
      volumes:
        - /var/run/docker.sock:/var/run/docker.sock
        - ./dev/traefik-config.yaml:/config/traefik-config.yaml
  ```

  **Usando la imagen oficial**



  ```yaml
  services:
    proxy:
      image: traefik:v3.6.2
      command: --providers.docker --providers.file.filename=/config/traefik-config.yaml --api.insecure
      ports:
        - 80:80
        - 8080:8080
      volumes:
        - /var/run/docker.sock:/var/run/docker.sock
        - ./dev/traefik-config.yaml:/config/traefik-config.yaml
  ```

  

### Iniciar la aplicación de ejemplo

Para ejecutar la aplicación de ejemplo que reenvía solicitudes de Traefik a aplicaciones que se ejecutan de forma nativa, realiza los siguientes pasos:

1. Si aún tienes la pila de Compose en ejecución, deténla con el siguiente comando:

   ```console
   $ docker compose down
   ```

2. Inicia la aplicación utilizando el archivo `compose-native.yaml` proporcionado:

   ```console
   $ docker compose -f compose-native.yaml up
   ```

   Al abrir [http://localhost](http://localhost) se devolverá un error "502 Bad Gateway" porque las otras aplicaciones aún no se están ejecutando.

3. Inicia la API ejecutando los siguientes pasos:

   ```console
   cd api
   yarn install
   yarn dev
   ```

4. Inicia el frontend ejecutando los siguientes pasos en una nueva terminal (comenzando desde la raíz del proyecto):

   ```console
   cd client
   yarn install
   yarn dev
   ```

5. Abre la aplicación en [http://localhost](http://localhost). Deberías ver una aplicación que recupera un mensaje de [http://localhost/api/messages](http://localhost/api/messages). También puedes abrir [http://db.localhost](http://db.localhost) para ver o ajustar los mensajes disponibles directamente desde la base de datos Mongo. Traefik se asegurará de que las solicitudes se enruten correctamente al contenedor o aplicación correctos.

6. Cuando hayas terminado, ejecuta `docker compose down` para detener los contenedores y detén las aplicaciones de Yarn presionando `ctrl+c`.

## Resumen

Ejecutar múltiples servicios no tiene por qué requerir una configuración complicada de puertos y una buena memoria. Con herramientas como Traefik, es sencillo lanzar los servicios que necesitas y acceder a ellos sin complicaciones, ya sea para la aplicación en sí (como el frontend y el backend) o para herramientas de desarrollo adicionales (como phpMyAdmin).

