// 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: Mikhail Gorbachev
// 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.
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.pemEl 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:
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 systemdAl 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:
# 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/directoryEn 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:
"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/yupdate-ca-certificates; - imágenes Docker — en el
Dockerfilede la misma forma; de lo contrario los servicios dentro de contenedores no podrán comunicarse por HTTPS; - Firefox — política
Certificates.ImportEnterpriseRootso 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»).
certbot certonly --dns-cloudflare --dns-cloudflare-credentials /root/.cf.ini \
-d grafana.int.example.ruVentajas: 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.rues visible para todos vía crt.sh. Si no se desea revelar la lista de servicios internos, emita un wildcard*.int.example.ruy 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-challengea 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
| Tarea | Solución |
|---|---|
| Desarrollo en su propio equipo | mkcert |
| Red doméstica o oficina pequeña, hay dominio público | Let’s Encrypt vía DNS-01, wildcard en el proxy inverso |
| Empresa, muchos servicios, no se pueden revelar nombres, se necesita mTLS | Centro propio con step-ca y ACME con restricción de nombres |
Nombres en .internal o .home.arpa | solo centro propio |
| Dispositivo que no sabe ACME ni subir certificados | proxy 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í.
.localo 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í:
// Related