Saltar al contenido

// Engineering Log

HTTPS y servidor web en la práctica: Parte 6 — HTTPS en la red interna: mkcert, tu propia autoridad certificadora step-ca y Let's Encrypt a través de DNS

Publicado el 11.11.2026 · Autor:

// Ruta rápida

Este artículo pertenece al tema Seguridad y proteccion.

Los servicios internos — Grafana, Proxmox, NAS, interfaz web del router, banco de pruebas — a menudo funcionan por HTTP o con un certificado autofirmado, y los usuarios se acostumbran a pulsar «Ir de todas formas». Es una mala costumbre: la contraseña del administrador viaja en texto plano por la red, y nadie notará una verdadera suplantación de certificado. Además, los navegadores son cada vez más estrictos con HTTP: algunas capacidades (Service Workers, acceso al portapapeles, cámara, Secure-cookie) solo funcionan en un contexto protegido, es decir por HTTPS o en localhost. Abajo hay tres maneras de obtener certificados adecuados para la red interna y cómo elegir entre ellas.

Elección de la zona de dominio

Primero — cómo nombrar los hosts internos. De esto depende qué certificados se pueden obtener.

  • Subdominio de su dominio público (grafana.int.example.ru) — la mejor opción. Para él se puede obtener un certificado de Let’s Encrypt, y en DNS los nombres internos pueden resolverse solo para clientes internos (split DNS).
  • .internal — zona que ICANN reservó en 2024 para redes privadas: nunca aparecerá en Internet. Los centros públicos no emiten certificados para ella — se necesita un centro propio.
  • .home.arpa — zona para redes domésticas (RFC 8375), también requiere un centro propio.
  • No use .local (ocupada por mDNS/Bonjour — habrá conflictos de resolución de nombres), zonas inventadas como .lan, .corp, .office (cualquiera de ellas puede delegarse en Internet, como ocurrió con .dev) ni dominios ajenos.

Método 1. mkcert — para desarrollo en su propio equipo

mkcert crea una autoridad certificadora local, la añade a los almacenes del sistema y de los navegadores y emite certificados para cualquier nombre.

bash
brew install mkcert nss          # macOS; nss es necesario para Firefox
mkcert -install                  # crear CA y añadirlo a los de confianza
mkcert app.test localhost 127.0.0.1 ::1
# creará app.test+3.pem y app.test+3-key.pem

El certificado se conecta al servidor de desarrollo (Vite: server.https, Nginx: ssl_certificate), y el navegador abre https://app.test sin advertencias.

Limitaciones:

  • solo para su equipo: en otros dispositivos no existe esa CA;
  • la clave privada de la CA está en $(mkcert -CAROOT) — no la comparta con nadie y no use mkcert para servidores compartidos;
  • para abrir el sitio desde el teléfono, habrá que instalar la CA también en el teléfono — para eso el método 2 suele ser más adecuado.

Método 2. Centro certificador propio con step-ca

step-ca (Smallstep) es un centro certificador de código abierto que emite certificados mediante el mismo protocolo ACME que Let’s Encrypt. Para servicios internos obtiene la misma automatización — certbot, Caddy, Traefik, cert-manager — pero desde su propio centro.

Instalación e inicialización:

bash
step ca init --name "Example Internal CA" --dns ca.example.internal \
  --address :9000 --provisioner admin@example.ru
step ca provisioner add acme --type ACME
step-ca $(step path)/config/ca.json      # iniciar; para funcionamiento permanente — servicio systemd

Al inicializar se crean certificados raíz e intermedio. El raíz se puede guardar offline, y el centro firmará certificados con el intermedio.

Emisión de certificado vía ACME:

bash
# certbot debe confiar en tu CA
export REQUESTS_CA_BUNDLE=/usr/local/share/ca-certificates/example-internal-root.crt

certbot certonly --standalone -d grafana.example.internal \
  --server https://ca.example.internal:9000/acme/acme/directory

En Caddy basta indicar el centro en la configuración global:

{
    acme_ca https://ca.example.internal:9000/acme/acme/directory
    acme_ca_root /etc/ssl/example-internal-root.crt
}
grafana.example.internal {
    reverse_proxy 127.0.0.1:3000
}

Plazos cortos. Por defecto step-ca emite certificados por 24 horas. Eso está bien: la renovación es automática (certbot renew, ACME integrado o step ca renew --daemon), y el plazo corto elimina el problema del revocado. Si algún servicio solo permite subir el certificado manualmente (interfaz web de un switch, UPS), para ese servicio se aumenta el plazo en la configuración del centro o se emite un certificado aparte.

Restricción de nombres. Limite obligatoriamente el centro a sus zonas — así, incluso si su clave se filtra, no podrá firmar un certificado para sberbank.ru o google.com. En step-ca esto se hace con una política en ca.json:

json
"policy": {
  "x509": {
    "allow": { "dns": ["*.example.internal", "*.int.example.ru"] }
  }
}

Para protección completa, es mejor escribir la restricción de nombres (name constraints) también en el propio certificado intermedio al emitirlo — así lo comprobarán los clientes, no solo el centro.

Distribución del certificado raíz. El raíz debe añadirse a los de confianza en todos los dispositivos:

  • Windows — directivas de grupo (Configuración del equipo → Plantillas administrativas → Parámetros de seguridad → Políticas de clave pública → Autoridades de certificación raíz de confianza);
  • macOS e iOS — perfiles MDM;
  • servidores Linux — con Ansible o en la imagen: archivo en /usr/local/share/ca-certificates/ y update-ca-certificates;
  • imágenes Docker — en el Dockerfile de la misma forma; de lo contrario los servicios dentro de contenedores no podrán comunicarse por HTTPS;
  • Firefox — política Certificates.ImportEnterpriseRoots o importación separada;
  • Java — keytool -importcert -cacerts.

Cómo instalar certificados raíz en distintos sistemas está explicado en detalle usando el ejemplo del certificado del Ministry of Digital Development en el artículo «Qué es el certificado del Ministry of Digital Development».

Método 3. Let’s Encrypt vía DNS-01 para nombres internos

Si los hosts internos están nombrados como subdominios de un dominio público, no hace falta un centro propio. La verificación DNS-01 no requiere acceso al servidor desde Internet — solo la capacidad de crear un registro TXT en la zona pública («Certificados Let’s Encrypt: ACME, verificaciones de dominio, CAA y Certificate Transparency»).

bash
certbot certonly --dns-cloudflare --dns-cloudflare-credentials /root/.cf.ini \
  -d grafana.int.example.ru

Ventajas: todos los dispositivos confían en los certificados sin instalar el raíz, incluidos teléfonos de invitados, televisores, equipos de terceros.

Desventajas:

  • los nombres aparecen en los registros de Certificate Transparency. Cada certificado para grafana.int.example.ru es visible para todos vía crt.sh. Si no se desea revelar la lista de servicios internos, emita un wildcard *.int.example.ru y repártalo en el proxy interno;
  • se necesita la API de su proveedor DNS con una clave que se almacena en la red interna; limite la clave a una sola zona o delegue _acme-challenge a una zona separada;
  • los registros A de los nombres internos no deben apuntar a direcciones internas en el DNS público — use un servidor DNS interno (split DNS) o solo responda desde el resolvedor interno.

Esquema conveniente: un único proxy inverso en la red interna (Caddy, Traefik, Nginx) con un certificado wildcard, detrás de él todos los servicios por HTTP. El certificado se renueva en un solo sitio y los servicios no necesitan implementar TLS.

Qué elegir

TareaSolución
Desarrollo en su propio equipomkcert
Red doméstica o oficina pequeña, hay dominio públicoLet’s Encrypt vía DNS-01, wildcard en el proxy inverso
Empresa, muchos servicios, no se pueden revelar nombres, se necesita mTLSCentro propio con step-ca y ACME con restricción de nombres
Nombres en .internal o .home.arpasolo centro propio
Dispositivo que no sabe ACME ni subir certificadosproxy inverso delante de él

Errores típicos

  • Certificado autofirmado en cada servicio y la costumbre de confirmar advertencias — se pierde la protección contra suplantación.
  • Centro propio sin restricción de nombres — su clave permite firmar certificados para cualquier sitio en Internet en todos los equipos de la empresa.
  • Raíz instalado en estaciones de trabajo, pero no en imágenes Docker ni en Java — los servicios no pueden comunicarse entre sí.
  • .local o zona inventada para nombres internos — conflictos con mDNS y riesgo de que la zona sea delegada en Internet.
  • Certificado Let’s Encrypt para cada nombre interno — la lista completa de servicios internos es públicamente accesible vía registros CT.
  • La clave CA de mkcert o step-ca está en una carpeta compartida o en el repositorio.

// Tarea parecida

Si estás resolviendo algo parecido

Este artículo pertenece a uno de los temas principales de trabajo. Puedes seguir leyendo sobre el tema, ir a la página principal para entender a qué me dedico o abrir directamente los servicios.

Tema del artículo

Seguridad y proteccion

SSL, hardening, accesos, proteccion de servicios y configuraciones seguras.

Tareas frecuentes de este tema

  • Configurar SSL, certificados y conexiones seguras
  • Restringir accesos y cerrar puntos de entrada innecesarios
  • Reforzar la configuracion del servidor y los servicios

// Siguiente paso

Si necesitas ayuda con este tema y no solo otro artículo, es mejor ir directo a la página del servicio. La página principal y la selección de materiales quedan como rutas secundarias.

Abrir servicios

// Contact

¿Necesitas ayuda?

Escríbeme y te ayudaré a resolver el problema

Respondo en un día laborable (03:00-13:00 GMT)

O deje su solicitud aquí:

Confirme que no es un bot.

Escribir y recibir una respuesta rápida