Skip to main content

Traefik

Routing seguro para tus aplicaciones en containers usando Traefik v2 con  Let's Encrypt - Crstian's blog

Traefik es un proxy inverso compatible con Docker que incluye su propio panel de supervisión. Es además un balanceador de carga adaptado a la computación en la nube mediante microservicios. Traefik se integra con los principales componentes de infraestructura configurándose a sí mismo automáticamente y de forma dinámica. Traefik es simple de operar pero capaz de manejar sistemas complejos y grandes en entornos diversos y diferentes capas de la pila de red como HTTP, TCP o UDP. Proporciona funcionalidades de intermediario que aumenta sus capacidades para realizar balanceo de carga o servir como gateway API.

Como proxy inverso intercepta las peticiones entrantes y las redirige a los servicios adecuados. A diferencia de proxys inversos configurados de forma estática, Traefik usa descubrimiento de servicios para configurarse a sí mismo según los servicios en ejecución. Puede hacer de proxy en diferentes capas de la pila de red proporcionando funcionalidades como balanceo de carga, limitación de peticiones, circuit breaker, duplicación o mirroring, autenticación y más. También soporta terminación de SSL y puede usar un proveedor ACME como Let’s Encrypt para la generación automática de certificados.

Enlaces

https://doc.traefik.io/traefik/

groales/traefik - traefik - ICT

Traefik es un reverse proxy moderno y ligero que detecta servicios Docker automáticamente y los expone vía HTTP/HTTPS con reglas declarativas (labels) y certificados TLS automáticos con Let's Encrypt.

Traefik 2.*.* en Docker con LetsEncrypt Quick-Deploy - Saiyans Blog

Características

  • 🔒 HTTPS automático con Let's Encrypt (HTTP-01)
  • 🧠 Descubrimiento automático de servicios Docker
  • 🧷 Redirección HTTP→HTTPS
  • 🧰 Dashboard web (seguro por dominio)
  • 🧩 Middlewares: auth básica, headers de seguridad, rate limit, etc.

Requisitos

  • Docker + Docker Compose
  • Red Docker externa proxy
  • Dominio apuntando al servidor (para dashboard y certificados)
  • Puertos 80 y 443 accesibles desde Internet

Despliegue

1) Crear red proxy
docker network create proxy
2) Clonar y configurar
git clone https://git.ictiberia.com/groales/traefik
cd traefik

# Crear carpeta para ACME
mkdir -p letsencrypt
touch ./letsencrypt/acme.json
chmod 600 ./letsencrypt/acme.json
3) Editar configuración

IMPORTANTE: Antes de desplegar, edita los siguientes archivos con tus datos reales:

traefik.yml:

certificatesResolvers:
  letsencrypt:
    acme:
      email: tu-email@tudominio.com  # ← EDITA AQUÍ

docker-compose.yaml:

labels:
  - "traefik.http.routers.traefik.rule=Host(`traefik.tudominio.com`)"  # ← EDITA AQUÍ
4) Desplegar
docker network create proxy  # Si no existe
docker compose up -d

Traefik dispone de los siguientes archivos de configuración:

  • docker-compose.yaml: fichero declarativo de traefik
  • traefik.yml: fichero de configuración estática. Este fichero define los puertos en que Traefik estará escuchando (Entrypoints), la parte de obtención de certificados a través de Let’s Ecrypt, etc.
  • dynamic/config.yml: fichero de configuración dinámica. Contiene configuración de parámetros que pueden cambiar durante la ejecución, como middlewares, rutas para servicios externos que no están en Docker, etc. 
  • acme.json: Almacena los certificados que Traefik genera para cada uno de nuestro servicios.

docker-compose.yaml

services:
  traefik:
    image: traefik:latest
    container_name: traefik
    restart: always
    ports:
      - "80:80"      # HTTP
      - "443:443"    # HTTPS
      # - "8080:8080" # Dashboard (exponer solo si lo proteges)
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik.yml:/traefik.yml:ro
      - ./letsencrypt:/letsencrypt
      - ./dynamic:/etc/traefik/dynamic:ro
    environment:
      TZ: "Europe/Madrid"
    networks:
      - proxy
    labels:
      - "traefik.enable=true"
      # Dashboard seguro por dominio
      - "traefik.http.routers.traefik.rule=Host(`traefik.tudominio.com`)"  # EDITA CON TU DOMINIO
      - "traefik.http.routers.traefik.entrypoints=websecure"
      - "traefik.http.routers.traefik.tls=true"
      - "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
      - "traefik.http.routers.traefik.service=api@internal"
      # Autenticación básica (usa middleware del archivo dynamic/middlewares.yml)
      - "traefik.http.routers.traefik.middlewares=auth-basic@file"

networks:
  proxy:
    external: true
traefik.yml
# Traefik Dashboard
api:
  dashboard: true
  insecure: false
# Puertos de escucha de Traefik y redirección automatica
entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    network: proxy
  file:
    directory: /etc/traefik/dynamic
    watch: true
# Certificates from an ACME server
certificatesResolvers:
  letsencrypt:
    acme:
      email: admin@tudominio.com  # EDITA CON TU EMAIL REAL
      storage: /letsencrypt/acme.json
      httpChallenge:
        entryPoint: web
log:
  level: INFO
accessLog: {}
dynamic/config.yml
# ============================================
# CONFIGURACIÓN DINÁMICA DE TRAEFIK
# ============================================
# Este archivo contiene middlewares, routers y servicios
# Traefik recarga automáticamente los cambios (~10s)

http:
  # ============================================
  # MIDDLEWARES
  # ============================================
  middlewares:
    # Headers de seguridad
    security-headers:
      headers:
        stsSeconds: 63072000
        forceSTSHeader: true
        stsIncludeSubdomains: true
        stsPreload: true
        frameDeny: true
        contentTypeNosniff: true
        browserXssFilter: true
        referrerPolicy: "strict-origin-when-cross-origin"
        customResponseHeaders:
          X-Robots-Tag: "none,noarchive,nosnippet,notranslate,noimageindex"

    # Rate limiting
    rate-limit:
      rateLimit:
        average: 100
        burst: 200
        period: 1m

    # IP Allow List (ejemplo - ajusta tus IPs)
    ip-allowlist:
      ipAllowList:
        sourceRange:
          - "127.0.0.1/32"
          - "10.0.0.0/8"
          - "172.16.0.0/12"
          - "192.168.0.0/16"

    # Autenticación básica (genera hash con: docker run --rm httpd:alpine htpasswd -nbB admin tu_password)
    auth-basic:
      basicAuth:
        users:
          - "admin:$2y$05$example_hash_CHANGE_THIS"  # CAMBIA ESTE HASH

    # Redirect www a root
    redirect-www:
      redirectRegex:
        regex: "^https?://www\\.(.+)"
        replacement: "https://${1}"
        permanent: true

  # ============================================
  # ROUTERS (Ejemplos comentados)
  # ============================================
  # routers:
  #   # Ejemplo: Router para aplicación web con HTTPS y middlewares
  #   whoami:
  #     rule: "Host(`whoami.tudominio.com`)"
  #     entryPoints:
  #       - websecure
  #     middlewares:
  #       - security-headers
  #       - rate-limit
  #     service: whoami-service
  #     tls:
  #       certResolver: letsencrypt
  #
  #   # Ejemplo: Router con autenticación básica y restricción IP
  #   admin-panel:
  #     rule: "Host(`admin.tudominio.com`)"
  #     entryPoints:
  #       - websecure
  #     middlewares:
  #       - auth-basic
  #       - ip-allowlist
  #       - security-headers
  #     service: admin-service
  #     tls:
  #       certResolver: letsencrypt

  # ============================================
  # SERVICES (Ejemplos comentados)
  # ============================================
  # services:
  #   # Ejemplo: Servicio apuntando a contenedor local
  #   whoami-service:
  #     loadBalancer:
  #       servers:
  #         - url: "http://whoami:80"
  #
  #   # Ejemplo: Servicio apuntando a servidor externo
  #   admin-service:
  #     loadBalancer:
  #       servers:
  #         - url: "http://192.168.1.100:8080"
  #
  #   # Ejemplo: Servicio con health check
  #   api-service:
  #     loadBalancer:
  #       servers:
  #         - url: "http://api:3000"
  #       healthCheck:
  #         path: "/health"
  #         interval: "10s"
  #         timeout: "3s"

Para poder haver una validación de usuario básica y validarnos en el panel web de Traefik, usaremos el "middleware auth-basic"

Generamos el hash y lo incluimos en el fichero dynamic/config.yml

openssl passwd -apr1 SuperSecreta123
$apr1$Bc8RJ6KW$.XVxhYuIvbz6Llz9tZ.451

NAT Hairpinning

También conocido como enrutamiento en horquilla, "NAT loopback" o "NAT reflection", es una técnica utilizada en redes de computadoras que permite que un dispositivo en una red se comunique con otro dispositivo en la misma red utilizando su dirección IP externa. Esto es útil cuando un dispositivo en la red necesita acceder a un servicio que está alojado en otro dispositivo en la misma red, pero solo se puede acceder al servicio a través de la dirección IP externa. Hairpinning se puede utilizar en una variedad de escenarios de red, como cuando un sitio web está alojado en un servidor local o cuando se utiliza una conexión VPN para acceder a una red remota.
La siguiente imagen muestra un ejemplo en el que un servicio publicado en la IP pública 203.40.40.5. Los paquetes que atraviesan el Firewall desde la red local (INSIDE) con destino IP publica 203.40.40.5 se transforman gracias al "NAT Hairpinning":
La IP destino 203.40.40.5 es reemplazada con la IP privada 192.168.5.5. También conocida como Destination NAT (DNAT).
La IP origen 192.168.1.50 es reemplazada con la IP 192.168.5.1 – IP del firewall. También conocida como Source NAT (SNAT).
Cuando los paquetes llegan al servidor destino tienen las IPs origen y destino siguientes (ambas privadas):
  • IP origen: 192.168.5.1
  • IP destino: 192.168.5.5

image.png