Todas las guías de despliegue Despliegue

Cómo instalar un certificado SSL personalizado en Traefik (v3)

Traefik es famoso por emitir certificados automáticamente mediante ACME. Pero a veces necesitas usar tu propio certificado en su lugar: uno emitido por GetHTTPS, una CA corporativa/interna, o un comodín que gestionas en otro sitio. Esta guía te muestra exactamente cómo hacerlo, en Traefik v3.

Lo fundamental que hay que entender desde el principio: no puedes adjuntar un archivo de certificado con una etiqueta de Docker. Las etiquetas de Traefik controlan el enrutamiento y activan TLS, pero el certificado en sí debe provenir del proveedor de archivos como configuración dinámica. Esto desconcierta a casi todo el mundo la primera vez. Lo haremos de la forma correcta.

Si todavía no tienes un certificado, consigue uno gratis en 5 minutos.

Cuándo usar esto (frente al ACME automático de Traefik)

Usa ACME automático (Let’s Encrypt)Usa tu propio certificado (esta guía)
Sitio web público, accesible desde internetServicio interno/intranet (sin DNS público)
Un certificado DV estándar es suficienteNecesitas una CA específica, un comodín o un certificado OV/EV
Traefik puede completar el desafío HTTP/DNSHost aislado (air-gapped) o tras un firewall
Quieres cero gestión de certificadosYa tienes un certificado de GetHTTPS u otro sitio

Si el ACME automático encaja con tu caso, certificatesResolvers de Traefik es más sencillo. Esta guía es para el caso “ya tengo fullchain.pem + privkey.pem y necesito que Traefik los sirva”.

Requisitos previos

  • Traefik v3 ejecutándose como contenedor de Docker (la configuración de abajo usa Docker, pero la parte de configuración dinámica se aplica a cualquier instalación)
  • Tus archivos de certificado — dos de ellos:
    • fullchain.pem — tu certificado + la cadena intermedia
    • privkey.pem — tu clave privada
  • Un dominio apuntando al host (o una entrada local en el archivo hosts para uso interno)

¿Qué archivos necesita Traefik? Traefik quiere la cadena completa en certFile y la clave en keyFile. Si usas un cert.pem que solo contiene la hoja, los clientes obtendrán errores de “cadena incompleta”: Traefik no añade automáticamente los intermedios para los certificados del proveedor de archivos. Usa fullchain.pem. Formatos de certificado explicados →

Cómo se divide la configuración de Traefik

Traefik tiene dos tipos de configuración, y los certificados viven en el segundo:

  • Configuración estática — establecida al arranque (entrypoints, providers). Cambiarla requiere reiniciar. Esto va en traefik.yml o en los flags del comando del contenedor.
  • Configuración dinámica — recargada en vivo sin reiniciar (routers, servicios, certificados TLS). Esto es lo que lee el proveedor de archivos.

Tu certificado es configuración dinámica. Por eso una etiqueta no puede llevarlo: las etiquetas se leen desde el proveedor de Docker, pero tls.certificates es un concepto del proveedor de archivos.

Paso 1: Coloca los archivos de certificado

Pon los archivos en un directorio que montarás dentro del contenedor:

mkdir -p ./traefik/certs
cp fullchain.pem ./traefik/certs/
cp privkey.pem   ./traefik/certs/

# Restringe el acceso a la clave privada
chmod 600 ./traefik/certs/privkey.pem
chmod 644 ./traefik/certs/fullchain.pem

Paso 2: Escribe la configuración dinámica

Crea ./traefik/dynamic/certs.yml. Aquí es donde declaras tu certificado:

# ./traefik/dynamic/certs.yml  (configuración dinámica — proveedor de archivos)
tls:
  certificates:
    - certFile: /certs/fullchain.pem
      keyFile: /certs/privkey.pem

  # Opcional: convierte este certificado en el predeterminado para cualquier host que no
  # coincida con un certificado más específico (p. ej. un comodín o una CA interna).
  stores:
    default:
      defaultCertificate:
        certFile: /certs/fullchain.pem
        keyFile: /certs/privkey.pem

Las rutas (/certs/...) son rutas dentro del contenedor: las montamos en el siguiente paso. Traefik selecciona el certificado correcto por solicitud usando SNI, haciendo coincidir el SAN del certificado con el nombre de host solicitado. El defaultCertificate es el recurso de reserva cuando nada más coincide.

Paso 3: Configura Traefik (configuración estática + montajes)

Aquí tienes un docker-compose.yml completo. Los entrypoints y el proveedor de archivos son configuración estática (pasados como flags del comando); el certificado se carga desde el archivo dinámico que acabas de escribir.

services:
  traefik:
    image: traefik:v3.3
    container_name: traefik
    restart: unless-stopped
    command:
      # ─── Entrypoints ───────────────────────────────
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      # Redirige todo el tráfico HTTP → HTTPS a nivel de entrypoint
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      - "--entrypoints.web.http.redirections.entrypoint.permanent=true"
      # ─── Providers ─────────────────────────────────
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      # El proveedor de archivos vigila el directorio de configuración dinámica
      - "--providers.file.directory=/dynamic"
      - "--providers.file.watch=true"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./traefik/certs:/certs:ro"
      - "./traefik/dynamic:/dynamic:ro"

  # ─── Servicio backend de ejemplo ──────────────────
  whoami:
    image: traefik/whoami
    container_name: whoami
    labels:
      - "traefik.enable=true"
      # Router: coincide con el host, sirve en el entrypoint HTTPS
      - "traefik.http.routers.whoami.rule=Host(`example.com`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      # Activa TLS en este router — el certificado proviene de la
      # configuración dinámica, NO de una etiqueta.
      - "traefik.http.routers.whoami.tls=true"

La línea crítica es traefik.http.routers.whoami.tls=true. Le indica a Traefik “sirve este router a través de TLS”. Traefik elige entonces el certificado coincidente del almacén del proveedor de archivos mediante SNI. No existe ninguna etiqueta como tls.certfile: eso no existe para los routers.

Paso 4: Arranca y verifica

docker compose up -d
docker compose logs -f traefik

Fíjate en que el proveedor de archivos cargue tu certificado. No deberías ver errores de TLS. Luego verifica:

Comprobación en el navegador

Visita https://example.com. Haz clic en el candado:

  • Emitido por — tu CA (Let’s Encrypt para GetHTTPS, o tu CA interna)
  • Válido — fechas de inicio y fin
  • Dominio — coincide con la URL

Comprobación por línea de comandos

# Confirma que Traefik está sirviendo TU certificado, no su predeterminado autofirmado
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates

Si ves CN=TRAEFIK DEFAULT CERT, Traefik recurrió a su marcador de posición integrado: tu certificado no se cargó. Consulta la sección Resolución de problemas más abajo.

Paso 5 (opcional): Refuerza TLS

Para controlar las versiones de protocolo y los cifrados, añade un bloque de opciones TLS a tu configuración dinámica y referéncialo desde el router. Añade a certs.yml:

tls:
  options:
    modern:
      minVersion: VersionTLS12
      sniStrict: true

Luego en la etiqueta del router:

- "traefik.http.routers.whoami.tls.options=modern@file"

El sufijo @file le indica a Traefik que este conjunto de opciones proviene del proveedor de archivos. Esto te restringe a TLS 1.2 y 1.3 y rechaza las conexiones sin un SNI coincidente.

HSTS: Añade la cabecera Strict-Transport-Security mediante un middleware headers de Traefik una vez que tengas la certeza de que HTTPS funciona en todas partes. Guía de HSTS →

Cómo renovar

Traefik no renueva automáticamente los certificados que proporcionas tú mismo: ese es el precio de usar el tuyo propio. Cuando tu certificado se acerque a su caducidad (día 60 de 90 para Let’s Encrypt):

  1. Consigue un certificado nuevo de GetHTTPS (o tu herramienta de renovación).
  2. Sobrescribe los archivos en su sitio:
    cp new-fullchain.pem ./traefik/certs/fullchain.pem
    cp new-privkey.pem   ./traefik/certs/privkey.pem
  3. Nada más. Como --providers.file.watch=true está establecido, Traefik detecta el cambio en el archivo y recarga el certificado en caliente: sin reinicio, sin tiempo de inactividad. Esta es una de las mejores cualidades de Traefik para los certificados personalizados.

Guía completa de renovación →

Resolución de problemas

Traefik sirve “TRAEFIK DEFAULT CERT” en lugar del mío

Causa: Traefik no pudo cargar tu certificado, así que recurrió a su marcador de posición autofirmado. Casi siempre es un problema de ruta o de montaje.

Solución:

# 1. Confirma que los archivos existen DENTRO del contenedor en la ruta esperada
docker compose exec traefik ls -l /certs

# 2. Confirma que el archivo dinámico está montado y es legible
docker compose exec traefik cat /dynamic/certs.yml

# 3. Revisa los logs para encontrar la razón real
docker compose logs traefik | grep -i "certificate\|tls\|error"

Las rutas certFile/keyFile en certs.yml deben coincidir con las rutas del contenedor (/certs/...), no con las rutas de tu host.

”unable to find certificate for domain” / se sirve el certificado equivocado

Causa: Ningún SAN de certificado coincide con el nombre de host solicitado, y no hay ningún defaultCertificate establecido.

Solución: O bien añade el nombre de host a tu certificado, o bien establece un defaultCertificate en el bloque stores.default (Paso 2) para que Traefik tenga un recurso de reserva.

El router devuelve 404 y el certificado ni siquiera se comprueba

Causa: La regla del router no coincide, o el servicio no está expuesto. TLS es irrelevante hasta que el enrutamiento coincide.

Solución:

# Verifica que el router existe y está activado
docker compose exec traefik wget -qO- http://localhost:8080/api/http/routers 2>/dev/null | grep whoami

Asegúrate de que traefik.enable=true esté en el contenedor backend y de que la regla Host() coincida con el dominio que estás probando.

Los cambios en certs.yml no surten efecto

Causa: El proveedor de archivos no está vigilando, o has editado la configuración estática (que necesita un reinicio).

Solución: Confirma que --providers.file.watch=true está en la configuración estática. Recuerda: los entrypoints/providers son estáticos (requieren reinicio); los routers y tls.certificates son dinámicos (se recargan en caliente).

“x509: certificate signed by unknown authority” desde los clientes

Causa: Cadena incompleta: usaste un cert.pem que solo contiene la hoja en certFile en lugar de fullchain.pem.

Solución: Apunta certFile a la cadena completa. Si solo tienes archivos por separado, concaténalos (primero la hoja, luego los intermedios):

cat cert.pem intermediate.pem > fullchain.pem

Preguntas frecuentes

¿Puedo especificar el archivo de certificado con una etiqueta de Docker?

No. Este es el malentendido número 1. Las etiquetas establecen traefik.http.routers.<name>.tls=true para activar TLS, pero los archivos de certificado deben declararse en la configuración dinámica mediante el proveedor de archivos (tls.certificates). No existe ninguna etiqueta de router que apunte a un archivo .pem.

¿Necesito tls=true en el router si ya tengo un certificado?

Sí. Declarar el certificado en tls.certificates lo hace disponible, pero cada router sigue necesitando tls=true (o escuchar en un entrypoint con TLS activado) para servir realmente a través de HTTPS. Definir un certificado por sí solo no cambia un router a TLS.

¿Puedo combinar ACME automático y certificados personalizados?

Sí. Traefik puede usar un certificatesResolver para algunos routers y certificados del proveedor de archivos para otros. Por solicitud, una coincidencia explícita de tls.certificates por SNI tiene prioridad sobre ACME para ese nombre de host.

¿Dónde van los certificados en Kubernetes?

No en el proveedor de archivos: en Kubernetes proporcionas los certificados como TLS Secrets y los referencias desde el IngressRoute/Ingress. El enfoque del proveedor de archivos de esta guía es para Docker e instalaciones independientes (no K8s).

¿Traefik renueva automáticamente mi certificado personalizado?

No. La renovación automática solo se aplica a los certificados que Traefik emite por sí mismo mediante ACME. Para tus propios certificados, reemplazas los archivos, pero gracias a --providers.file.watch=true, Traefik los recarga en caliente sin tiempo de inactividad, tal como se describe en la sección Cómo renovar más arriba.

¿Funciona esto con certificados ECDSA/ECC?

Sí. Traefik sirve los certificados ECDSA exactamente igual que los RSA: la misma configuración de certFile/keyFile. GetHTTPS emite ECDSA P-256 de forma predeterminada para handshakes más pequeños y rápidos.

Artículos relacionados

Despliegue 2026-05-08
Certificados SSL con Docker y proxies inversos
Configura HTTPS para contenedores Docker usando proxy inverso Nginx, Traefik con Let's Encrypt automático, o montaje manual de certificados.
Primeros pasos 2026-05-08
Cómo obtener un certificado SSL gratuito (guía paso a paso)
Obtén un certificado SSL gratuito de Let's Encrypt en 5 minutos — sin software que instalar, sin cuenta que crear. Guía completa con 4 métodos, ambos tipos de desafío, instalación en 6 plataformas y solución de problemas.
Despliegue 2026-05-08
Cómo instalar un certificado SSL en Nginx
Guía paso a paso para instalar un certificado SSL en Nginx. Cubre subida de archivos, configuración completa del bloque server, mejores prácticas TLS, HTTP/2, HSTS, redirección y solución de 6 errores comunes.
SSL y certificados 2026-05-07
Formatos de certificados SSL: PEM, PFX, DER explicados
Comprende los formatos de certificado PEM, PFX/PKCS#12 y DER. Aprende qué formato necesita tu servidor y cómo convertir entre ellos con OpenSSL.
Obtén un certificado SSL gratuito en tu navegador
Sin instalación, sin cuenta. Tu clave privada nunca sale de tu dispositivo.
Obtener certificado