Docker: Enrutamiento HTTPS
Cómo gestionar el enrutamiento HTTP y el cifrado TLS (HTTPS) en tus contenedores Docker
Bienvenido a la documentación de Stackhero
Stackhero ofrece una plataforma Docker cloud CaaS (Containers as a Service) lista para usar, diseñada para despliegues de contenedores rápidos y fiables:
- Despliegue en producción con un simple
docker-compose up. No necesita configuración adicional: simplemente inicie sus contenedores.- Elija su propio nombre de dominio, asegurado automáticamente con HTTPS (por ejemplo: https://api.su-empresa.com, https://www.su-empresa.com o https://backoffice.su-empresa.com).
- Disfrute de un alto rendimiento y una seguridad robusta sobre infraestructura privada y dedicada.
- Aplique actualizaciones con un solo clic para un mantenimiento sencillo y sin complicaciones.
Puede tener sus contenedores en producción en unos cinco minutos. Stackhero gestiona la infraestructura, las actualizaciones y la seguridad por usted, para que pueda centrarse en el desarrollo de sus aplicaciones. Lea más sobre el alojamiento cloud Docker CaaS.
Cada instancia de Stackhero para Docker incluye un servidor Traefik dedicado y preconfigurado que gestiona el tráfico HTTP y lo cifra automáticamente utilizando certificados TLS. Esta configuración simplificada hace que el enrutamiento sea sencillo y eficiente. Por ejemplo:
- Envía el tráfico de
https://www.my-company.com(con o sin el prefijo www) a tu contenedorfrontend. - Ruta
https://www.my-company.com/documentationsa tu contenedordocumentations. - Dirige
https://api.my-project.ioa tu contenedorapi.
Puedes gestionar un número ilimitado de dominios con creación y renovación automática de certificados TLS. Lo mejor de todo es que puedes configurar todo esto con solo tres líneas.
Configuración básica de Traefik
En todos los ejemplos de configuración siguientes, tendrás que reemplazar
<XXXXXX>.stackhero-network.comcon el nombre de dominio de tu instancia de Stackhero para Docker.
A continuación, se muestra un ejemplo básico de un archivo docker-compose.yml:
services:
test:
image: nginx
labels:
- "traefik.enable=true" # Habilitar Traefik para enrutar el tráfico a este contenedor
- "traefik.http.routers.test.rule=Host(`<XXXXXX>.stackhero-network.com`)" # Definir el host
- "traefik.http.routers.test.tls.certresolver=letsencrypt" # Usar 'letsencrypt' como el resolutor de certificados TLS
En este ejemplo, un contenedor llamado test se ejecuta utilizando la imagen de Nginx. La configuración clave se proporciona en la sección de etiquetas. Simplemente necesitas copiar estas líneas en tu archivo docker-compose.yml y reemplazar <XXXXXX>.stackhero-network.com con tu dominio de servicio.
Puedes desplegar el contenedor usando:
docker context use <XXXXXX>.stackhero-network.com
docker-compose up
Después de que el contenedor se inicie, visita https://<XXXXXX>.stackhero-network.com/ para ver la página "Welcome to nginx!".
Página de bienvenida de Nginx
Si no ves la página de bienvenida de Nginx, verifica el panel de control de Traefik para posibles errores.
Con esta configuración, las solicitudes HTTP enviadas a <XXXXXX>.stackhero-network.com se enrutan a tu contenedor test y Traefik crea y gestiona automáticamente los certificados TLS para HTTPS.
Gestionar dominios personalizados con Traefik
En el ejemplo anterior, utilizamos el dominio predeterminado <XXXXXX>.stackhero-network.com. En la práctica, probablemente usarás tus propios dominios de empresa o proyecto, como www.my-company.com o api.my-project.io. La sección a continuación explica cómo configurar dominios personalizados.
Configurar tu primer dominio con Traefik
En este ejemplo, configurarás el dominio api.my-project.io. Reemplaza my-project.io con un dominio que poseas y api con tu subdominio deseado.
Primero, actualiza la configuración DNS de tu dominio para que api.my-project.io apunte a tu dominio <XXXXXX>.stackhero-network.com.
- Inicia sesión en tu proveedor de dominio y accede a tu configuración DNS.
- Crea una nueva entrada llamada
api(u otro subdominio de tu elección), establece su tipo enCNAMEy establece su destino en<XXXXXX>.stackhero-network.com.
Ejemplo de configuración DNS en la interfaz DNS de Cloudflare
Una vez configurado el DNS, puedes validarlo ejecutando:
host api.my-project.io
Deberías ver una respuesta similar a:
api.my-project.io is an alias for <XXXXXX>.stackhero-network.com
La propagación DNS puede tardar hasta 24 horas dependiendo de tu proveedor. Si el comando
hostno devuelve la respuesta esperada, espera y vuelve a intentarlo más tarde.
A continuación, actualiza tu archivo docker-compose.yml con la siguiente configuración:
services:
api:
image: traefik/whoami
hostname: api
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.my-project.io`)" # Añade tu dominio aquí
- "traefik.http.services.api.loadbalancer.server.port=<PORT>" # Reemplaza "<PORT>" con el puerto en el que tu API está escuchando
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
No olvides reemplazar
api.my-project.iocon tu dominio real en la etiqueta TraefikHost.
Despliega tu contenedor con:
docker-compose up -d
Luego visita https://api.my-project.io. Deberías ver una página de texto que muestra el nombre de host de tu contenedor api.
Prueba de que Traefik está gestionando nuestro tráfico HTTP con cifrado TLS para nuestro nuevo dominio
En la primera creación del contenedor, los certificados TLS pueden tardar unos segundos en generarse. Si encuentras un error TLS, espera unos segundos y actualiza la página para permitir que se generen los certificados.
¡Felicidades, ahora has configurado tu primer dominio personalizado!
Cómo redirigir un subdominio "www" a tu dominio raíz usando Traefik
Al definir una URL de sitio web como my-company.com, es una buena idea configurar también un subdominio "www". Esto asegura que los usuarios que se conecten a través de www.my-company.com sean redirigidos a tu sitio principal y ayuda a evitar problemas de contenido duplicado.
En el ejemplo a continuación, se gestionan tanto my-company.com como www.my-company.com. Los usuarios que acceden a www.my-company.com son redirigidos a my-company.com:
services:
frontend:
image: traefik/whoami
hostname: frontend
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`my-company.com`) || Host(`www.my-company.com`)" # Añade ambos dominios aquí
- "traefik.http.services.frontend.loadbalancer.server.port=<PORT>" # Reemplaza "<PORT>" con el puerto en el que tu frontend está escuchando
- "traefik.http.routers.frontend.tls.certresolver=letsencrypt"
# Redirigir 'www.my-company.com' a 'my-company.com':
- 'traefik.http.routers.frontend.middlewares=redirect-www'
- "traefik.http.middlewares.redirect-www.redirectregex.regex=^https://www.my-company.com/(.*)"
- "traefik.http.middlewares.redirect-www.redirectregex.replacement=https://my-company.com/$${1}"
- "traefik.http.middlewares.redirect-www.redirectregex.permanent=true"
Enrutar un camino a un contenedor específico con Traefik
Supongamos que tienes un contenedor dedicado a tu sitio de documentación. Podrías querer enrutar https://my-company.com/docs a este contenedor mientras envías otras solicitudes, como https://my-company.com/, a tu contenedor frontend. El ejemplo a continuación muestra cómo se logra esto:
services:
documentations:
image: traefik/whoami
hostname: documentations
labels:
- "traefik.enable=true"
- "traefik.http.routers.documentations.rule=Host(`my-company.com`) && PathPrefix(`/docs`)" # Define el prefijo de camino aquí
- "traefik.http.services.documentations.loadbalancer.server.port=<PORT>" # Reemplaza "<PORT>" con el puerto en el que tu contenedor de documentación está escuchando
- "traefik.http.routers.documentations.tls.certresolver=letsencrypt"
frontend:
image: traefik/whoami
hostname: frontend
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`my-company.com`) || Host(`www.my-company.com`)"
- "traefik.http.services.frontend.loadbalancer.server.port=<PORT>" # Reemplaza "<PORT>" con el puerto en el que tu frontend está escuchando
- "traefik.http.routers.frontend.tls.certresolver=letsencrypt"
# Redirigir 'www.my-company.com' a 'my-company.com':
- 'traefik.http.routers.frontend.middlewares=redirect-www'
- "traefik.http.middlewares.redirect-www.redirectregex.regex=^https://www.my-company.com/(.*)"
- "traefik.http.middlewares.redirect-www.redirectregex.replacement=https://my-company.com/$${1}"
- "traefik.http.middlewares.redirect-www.redirectregex.permanent=true"
Ahora, al visitar https://my-company.com/docs (o cualquier subruta como https://my-company.com/docs/something) se mostrará contenido del contenedor documentations. Otros caminos, por ejemplo https://my-company.com/help, serán servidos por el contenedor frontend.
Definir un puerto de contenedor personalizado en Traefik
Por defecto, Traefik se conecta al primer puerto expuesto del contenedor. En algunos casos, podrías necesitar especificar un puerto particular. El ejemplo a continuación demuestra cómo definir un puerto personalizado:
services:
frontend:
image: traefik/whoami
hostname: frontend
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`my-company.com`)"
- "traefik.http.routers.frontend.tls.certresolver=letsencrypt"
# Enrutar tráfico de 'https://my-company.com' al contenedor 'frontend' en el puerto 80
- "traefik.http.services.frontend.loadbalancer.server.port=80"
Buenas prácticas de nomenclatura de Traefik y Docker Compose
Al definir un contenedor en tu archivo docker-compose.yml, algunos campos son importantes para una mejor consistencia y facilidad de gestión. Considera usar la siguiente configuración recomendada:
services:
<CONTAINER_NAME>:
image: traefik/whoami
hostname: <CONTAINER_NAME>
container_name: <CONTAINER_NAME>
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.routers.<CONTAINER_NAME>.rule=Host(`my-company.com`)"
- "traefik.http.routers.<CONTAINER_NAME>.tls.certresolver=letsencrypt"
Simplemente reemplaza <CONTAINER_NAME> con el nombre deseado para tu contenedor, por ejemplo frontend.
Error de Let's Encrypt "Domain name contains an invalid character"
Al crear un subdominio, Let's Encrypt sigue las RFC 952 y 1123, que solo permiten caracteres en el conjunto [a-zA-Z0-9-].
Aunque los guiones bajos ('_') están permitidos en los nombres de registros DNS, no son aceptables en los nombres de host. Como resultado, Let's Encrypt rechaza subdominios como "my_subdomain.example.com" y muestra el error "Domain name contains an invalid character".
Para resolver este problema, simplemente elimina cualquier guion bajo de tus subdominios.