Ai/automazione

Certificados TLS: Gestión Self-Hosted con Certctl y Docker

Cuando configuré entornos de staging para una organización sanitaria pública con 500 endpoints, la gestión de certificados TLS se convirtió en un cuello de botella. Los certificados self-signed caducaban sin aviso, los desarrolladores perdían horas configurando excepciones y las comunicaciones entre microservicios fallaban de repente. Con estándares como NIS2 art.21 exigiendo cifrado en tránsito incluso en redes internas, asegurar estos entornos deja de ser opcional. Certctl cambia esta dinámica por completo. Combinado con Docker Compose, permite generar y renovar certificados TLS de forma automática en entornos self-hosted. No hablo de una característica teórica. Hablo de reducir el tiempo de aprovisionamiento seguro de 2 horas a 30 segundos. En esta guía verás cómo desplegar una infraestructura de PKI local para desarrollo, generar tu propia Certificate Authority (CA), emitir certificados para dominios específicos y automatizar su renovación para que ningún servicio se quede sin cifrado. Lee también: Hardening SSH en Linux: Guía Completa 2026

Requisitos Previos / Entorno de Prueba

Antes de comenzar, necesitas preparar tu máquina con las herramientas adecuadas. Este entorno de prueba simula una infraestructura real de desarrollo.

  • Docker Engine 20.10 o superior instalado y funcionando.
  • Docker Compose V2 instalado como plugin de Docker.
  • certctl instalado localmente para validaciones (asegúrate de tener la última versión disponible).
  • Un editor de texto como vim o nano.
  • Conocimientos básicos de Docker Compose y PKI.

Puedes consultar la documentación oficial de Docker Compose en https://docs.docker.com/compose/ para revisar los detalles de instalación y sintaxis.

Configuración de Docker Compose

Creamos un archivo docker-compose.yml para definir los servicios necesarios. Necesitamos un container para certctl y, opcionalmente, un container para un servicio de prueba con Nginx para verificar los certificados generados.

version: '3.8'
services:
  certctl:
    image: ghcr.io/cloudflare/certctl:latest
    container_name: certctl
    volumes:
      - ./certs:/certs
    environment:
      - CERTCTL_CA_CN=MySelfSignedCA
    command: sleep infinity # Mantiene el container activo

  nginx:
    image: nginx:latest
    container_name: nginx-test
    ports:
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./certs:/etc/nginx/certs:ro
    depends_on:
      - certctl

Este archivo define dos servicios principales:

  • certctl: Utiliza la imagen Docker oficial de certctl desde GitHub Container Registry. Mapea el directorio local ./certs al directorio /certs dentro del container. La variable de entorno CERTCTL_CA_CN define el Common Name (CN) de la Certificate Authority. El comando sleep infinity mantiene el container en ejecución, permitiendo ejecutar comandos certctl en su interior bajo demanda.
  • nginx: Utiliza la imagen Docker de Nginx. Mapea el puerto 443 del host al puerto 443 del container. Monta el archivo de configuración local ./nginx.conf y el directorio de certificados ./certs como solo lectura. La directiva depends_on garantiza que el container certctl arranque antes que nginx.

Preparación de Directorios y Configuración Nginx

Crea el directorio local certs donde se almacenarán los certificados generados.

mkdir certs

Si deseas probar los certificados con Nginx, crea un archivo nginx.conf con la siguiente configuración básica para escuchar en el puerto 443:

events {}

http {
    server {
        listen 443 ssl;
        server_name localhost;

        ssl_certificate /etc/nginx/certs/example.com.crt;
        ssl_certificate_key /etc/nginx/certs/example.com.key;

        location / {
            root /usr/share/nginx/html;
            index index.html;
        }
    }
}

Esta configuración fuerza a Nginx a utilizar HTTPS con los certificados TLS generados por certctl. Verifica que las rutas ssl_certificate y ssl_certificate_key coincidan con los nombres de los archivos que generarás en el siguiente paso.

Generación de la Certificate Authority y Certificados

Con la estructura lista, iniciamos los containers definidos en el archivo docker-compose.yml:

docker-compose up -d

Este comando arranca los containers certctl y nginx en segundo plano. Generamos la CA ejecutando el comando certctl ca dentro del container certctl:

docker exec -it certctl certctl ca

Este comando genera una nueva CA en el directorio /certs dentro del container. Los archivos ca.crt y ca.key (certificado y clave privada de la CA) aparecerán en tu directorio local certs.

Salida esperada:

Generating a new CA in /certs
CA certificate: /certs/ca.crt
CA private key: /certs/ca.key

Emisión de Certificados para Dominios Específicos

Con la CA disponible, generamos un certificado TLS para un dominio específico. Por ejemplo, para emitir un certificado válido para example.com:

docker exec -it certctl certctl cert example.com

Este comando genera el certificado TLS para example.com en el directorio /certs. Los archivos example.com.crt y example.com.key (certificado y clave privada) se crearán en tu directorio local certs.

Salida esperada:

Generating a new certificate for example.com in /certs
Certificate: /certs/example.com.crt
Private key: /certs/example.com.key

Para verificar el funcionamiento, abre un navegador y navega a https://localhost. El navegador mostrará una advertencia indicando que el certificado no es de confianza (por ser self-signed). Ignora la advertencia y procede. Deberías ver la página por defecto de Nginx, confirmando que el cifrado TLS funciona correctamente.

Renovación y Automatización de Certificados

Los certificados TLS tienen fecha de caducidad. certctl simplifica el proceso de renovación. Para renovar el certificado de example.com, ejecuta:

docker exec -it certctl certctl renew example.com

Este comando renueva el certificado y sobrescribe los archivos example.com.crt y example.com.key existentes. Si utilizas Nginx, debes recargar la configuración para que aplique los nuevos archivos:

docker exec nginx-test nginx -s reload

Para automatizar este proceso y evitar que los servicios se queden sin cifrado, programa un cron job que ejecute la renovación periódicamente. Por ejemplo, para renovar los certificados el primer día de cada mes, añade esta línea al crontab del sistema (ejecutando crontab -e):

0 0 1 * * docker exec certctl certctl renew example.com && docker exec nginx-test nginx -s reload

Nota que en el cron job se han omitido las flags -it del comando docker exec, ya que el entorno de cron no es interactivo y su inclusión generaría errores.

Errores Comunes y Resolución de Problemas

  • Error: certctl: command not found: Verifica que certctl esté instalado correctamente y disponible en el PATH del sistema. Si el error ocurre dentro del container, confirma que la imagen se haya descargado de forma completa.
  • Error: x509: certificate signed by unknown authority en el navegador: Este error indica que el navegador no reconoce tu CA self-signed como entidad de confianza. Puedes ignorar la advertencia en entornos de desarrollo, o importar el archivo ca.crt al trust store de tu sistema operativo para eliminar la advertencia por completo.
  • Error: Nginx no utiliza el nuevo certificado después de la renovación: Nginx carga los certificados en memoria al arrancar. Tras renovar un certificado, debes forzar la recarga de la configuración con docker exec nginx-test nginx -s reload.
  • Error: bind: address already in use: El puerto 443 ya está en uso en tu máquina host. Detén cualquier otro servicio que ocupe el puerto 443 antes de levantar los containers con docker-compose up.

Conclusiones con Puntos Clave Operativos

Has configurado un sistema completo para gestionar certificados TLS self-hosted utilizando certctl y Docker Compose. Esta infraestructura de PKI local acelera el desarrollo y garantiza que las comunicaciones entre microservicios estén cifradas desde el primer día.

Puntos clave operativos:

  • Aprovisionamiento rápido: Genera CA y certificados en segundos, eliminando horas de trabajo manual.
  • Automatización del ciclo de vida: El cron job asegura la renovación mensual sin intervención humana, evitando caídas por certificados caducados.
  • Aislamiento: Los containers mantienen las herramientas de PKI separadas del sistema operativo host, reduciendo el riesgo de contaminación.

Recuerda que los certificados self-signed son ideales para entornos de desarrollo y testing. Para producción, debes utilizar certificados emitidos por una CA pública reconocida como Let’s Encrypt o DigiCert para cumplir con los requisitos de confianza de los navegadores y los estándares de seguridad corporativos.

Comparte este artículo:

Escrito por

Rosario Giordano

Rosario Giordano es administrador de sistemas y consultor de TI especializado en c iberseguridad y cloud, con más de 20 años de experiencia en la gestión de infraestructuras Linux empresariales. Sus áreas de especialización incluyen el hardening de SSH, plataformas Kubernetes , bases de datos PostgreSQL, virtualización con VMware/Proxmox y el cumplimiento de los marcos de seguridad NIS2 e ISO 27001.