Qué es HTTPS y qué aporta TLS en Apache
HTTPS es HTTP encapsulado dentro de TLS. TLS aporta cifrado (evita que terceros lean el tráfico), integridad (detecta modificaciones) y autenticación (el servidor demuestra su identidad mediante un certificado). En Apache, HTTPS se implementa normalmente con el módulo mod_ssl y un VirtualHost en el puerto 443.
Componentes clave: certificado, clave privada y cadena
- Clave privada (
.key): secreto del servidor. Debe estar protegida por permisos estrictos. - Certificado del servidor (
.crto.pem): contiene la clave pública y el nombre (CN/SAN) del sitio. - Cadena de certificados (intermedios): certificados que enlazan el certificado del servidor con una CA raíz confiable. En muchos casos se entrega como
fullchain.pem(servidor + intermedios).
En validación TLS, el cliente verifica: (1) que el nombre del sitio coincide con el certificado (SAN), (2) que la cadena es confiable, (3) que el certificado no está caducado o revocado (según cliente), y (4) que los parámetros criptográficos son aceptables.
Habilitar SSL/TLS en Apache
Debian/Ubuntu (a2enmod)
sudo a2enmod ssl headers rewrite http2Activa mod_ssl (TLS), mod_headers (cabeceras de seguridad), mod_rewrite (redirecciones) y mod_http2 (HTTP/2, si aplica).
RHEL/CentOS/Alma/Rocky
En estas familias suele venir mod_ssl como paquete separado.
sudo dnf install -y mod_sslVerifica que el módulo esté cargado (según distribución):
- Escuche el audio con la pantalla apagada.
- Obtenga un certificado al finalizar.
- ¡Más de 5000 cursos para que explores!
Descargar la aplicación
apachectl -M | grep -E 'ssl|headers|rewrite|http2'Certificados: laboratorio (autofirmado) vs público (CA)
Opción A: certificado autofirmado para laboratorio
Útil para pruebas internas. Los navegadores mostrarán advertencia porque no hay una CA confiable detrás. Aun así, permite practicar configuración, redirecciones y endurecimiento TLS.
Paso 1: crear directorio seguro para claves
Usa una ruta fuera del DocumentRoot y con permisos restrictivos. Un patrón común:
sudo install -d -m 0750 /etc/ssl/apachePaso 2: generar clave privada y certificado (con SAN)
Los navegadores modernos requieren SAN (Subject Alternative Name). Crea un archivo de configuración mínimo para OpenSSL, por ejemplo /tmp/openssl-san.cnf:
[req]distinguished_name = dnreq_extensions = req_extprompt = no[dn]CN = ejemplo.local[req_ext]subjectAltName = @alt_names[alt_names]DNS.1 = ejemplo.localDNS.2 = www.ejemplo.localGenera clave y certificado (válido 365 días):
sudo openssl req -x509 -newkey rsa:2048 -sha256 -days 365 -nodes -keyout /etc/ssl/apache/ejemplo.local.key -out /etc/ssl/apache/ejemplo.local.crt -config /tmp/openssl-san.cnfAjusta permisos (la clave debe ser legible solo por root y el grupo de Apache si lo necesitas):
sudo chown root:root /etc/ssl/apache/ejemplo.local.key /etc/ssl/apache/ejemplo.local.crtsudo chmod 0600 /etc/ssl/apache/ejemplo.local.keysudo chmod 0644 /etc/ssl/apache/ejemplo.local.crtSi tu Apache corre como usuario/grupo específico y requiere leer la clave (depende de cómo esté configurado), puedes asignar grupo y permisos mínimos:
sudo chgrp www-data /etc/ssl/apache/ejemplo.local.keysudo chmod 0640 /etc/ssl/apache/ejemplo.local.keyAdapta www-data al grupo real del servicio (por ejemplo apache en RHEL-like).
Opción B: certificado público (pauta práctica)
Para producción, usa una CA pública. El flujo típico es:
- Generar una clave privada en el servidor.
- Crear un CSR (Certificate Signing Request) con SAN.
- Validar dominio con la CA (HTTP-01/DNS-01 u otros métodos).
- Recibir certificado del servidor y intermedios (cadena).
Ejemplo para generar clave y CSR con SAN (sin autofirmar). Crea /tmp/csr-san.cnf:
[req]distinguished_name = dnreq_extensions = req_extprompt = no[dn]CN = midominio.com[req_ext]subjectAltName = @alt_names[alt_names]DNS.1 = midominio.comDNS.2 = www.midominio.comGenera clave y CSR:
sudo openssl req -new -newkey rsa:2048 -nodes -keyout /etc/ssl/apache/midominio.com.key -out /etc/ssl/apache/midominio.com.csr -config /tmp/csr-san.cnfTras emitir el certificado, muchas CAs entregan archivos como:
cert.pem(certificado del servidor)chain.pem(intermedios)fullchain.pem(certificado + intermedios)
En Apache suele ser más simple apuntar SSLCertificateFile a fullchain.pem (si existe) y SSLCertificateKeyFile a la clave.
Montar un VirtualHost en 443 (HTTPS)
A continuación tienes un ejemplo de VirtualHost en 443 con parámetros recomendados. Ajusta ServerName, rutas y logs según tu sitio.
Ejemplo de configuración (SSL + HTTP/2 + cabeceras)
<IfModule mod_ssl.c><VirtualHost *:443> ServerName ejemplo.local ServerAlias www.ejemplo.local DocumentRoot /var/www/ejemplo/public ErrorLog ${APACHE_LOG_DIR}/ejemplo-ssl-error.log CustomLog ${APACHE_LOG_DIR}/ejemplo-ssl-access.log combined SSLEngine on # Certificado (laboratorio: .crt; público: idealmente fullchain.pem) SSLCertificateFile /etc/ssl/apache/ejemplo.local.crt SSLCertificateKeyFile /etc/ssl/apache/ejemplo.local.key # Si tu CA entrega cadena separada y NO tienes fullchain, puedes usar: # SSLCertificateChainFile /etc/ssl/apache/chain.pem # Protocolos recomendados (ajusta según compatibilidad requerida) SSLProtocol -all +TLSv1.2 +TLSv1.3 # Cifrados: en TLSv1.3 no aplica SSLCipherSuite; en TLSv1.2 sí. SSLCipherSuite HIGH:!aNULL:!MD5:!3DES:!RC4 SSLHonorCipherOrder off # Rendimiento y seguridad adicional SSLCompression off SSLSessionTickets off # OCSP Stapling (útil con CA pública; requiere mod_ssl) SSLUseStapling on SSLStaplingCache "shmcb:/var/run/apache2/ssl_stapling(32768)" # HTTP/2 (si mod_http2 está habilitado) Protocols h2 http/1.1 # Cabeceras de seguridad (ajusta según tu aplicación) Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains" Header always set X-Content-Type-Options "nosniff" Header always set X-Frame-Options "SAMEORIGIN" Header always set Referrer-Policy "strict-origin-when-cross-origin" # Opcional: desactivar "Server" y otros detalles se gestiona a nivel global en hardening <Directory /var/www/ejemplo/public> Options -Indexes AllowOverride All </Directory></VirtualHost></IfModule>Nota sobre HSTS: habilítalo cuando estés seguro de que el sitio funcionará siempre por HTTPS. En entornos de laboratorio puedes omitirlo para evitar “bloquearte” en HTTPS durante pruebas.
Redirección HTTP → HTTPS
La forma más limpia es un VirtualHost en 80 que solo redirige. Esto evita reglas dispersas y hace el comportamiento predecible.
VirtualHost en 80 para redirigir
<VirtualHost *:80> ServerName ejemplo.local ServerAlias www.ejemplo.local # Redirección permanente a HTTPS Redirect permanent / https://ejemplo.local/</VirtualHost>Si necesitas preservar host y URI automáticamente (por ejemplo múltiples alias), usa mod_rewrite:
<VirtualHost *:80> ServerName ejemplo.local ServerAlias www.ejemplo.local RewriteEngine On RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]</VirtualHost>Ubicación y permisos seguros de key/crt
Buenas prácticas
- Guarda claves en rutas como
/etc/ssl/...o/etc/pki/tls/..., nunca dentro del DocumentRoot. - Permisos típicos: clave
0600(o0640con grupo del servicio), certificado0644. - Evita copias de la clave en directorios temporales o repositorios.
- Si usas automatización, valida que el proceso de renovación no deje archivos con permisos laxos.
Tabla rápida: qué archivo va en cada directiva
| Directiva | Qué espera | Ejemplo |
|---|---|---|
SSLCertificateKeyFile | Clave privada del servidor | /etc/ssl/apache/sitio.key |
SSLCertificateFile | Certificado del servidor o fullchain | /etc/ssl/apache/fullchain.pem |
SSLCertificateChainFile | Intermedios (si no usas fullchain) | /etc/ssl/apache/chain.pem |
Validaciones y pruebas
1) Comprobar sintaxis y recargar Apache
sudo apachectl configtestsudo systemctl reload apache2En algunas distribuciones el servicio se llama httpd:
sudo systemctl reload httpd2) Verificar el handshake y la cadena con openssl s_client
Prueba el sitio indicando el nombre (SNI). Esto es clave si hay varios sitios en el mismo IP:443.
openssl s_client -connect ejemplo.local:443 -servername ejemplo.local -showcertsQué mirar en la salida:
subject=yX509v3 Subject Alternative Namedeben incluir el hostname.Verify return code: 0 (ok)indica cadena confiable (solo ocurrirá si el cliente confía en la CA; en autofirmado no será 0).- Versión TLS negociada y cipher seleccionado.
Para forzar una versión y comprobar compatibilidad:
openssl s_client -connect ejemplo.local:443 -servername ejemplo.local -tls1_2openssl s_client -connect ejemplo.local:443 -servername ejemplo.local -tls1_33) Probar redirección HTTP→HTTPS
curl -I http://ejemplo.local/Debes ver 301 o 308 y un Location: https://....
4) Probar cabeceras de seguridad
curl -I https://ejemplo.local/Verifica la presencia de Strict-Transport-Security (si la activaste) y otras cabeceras configuradas con mod_headers.
Configuración de protocolos y cifrados: recomendaciones por entorno
Entorno moderno (recomendado)
- Permitir solo
TLSv1.2yTLSv1.3. - Deshabilitar compresión TLS.
- Preferir suites fuertes en TLS 1.2 (en TLS 1.3 el conjunto es fijo y seguro por diseño).
Ejemplo:
SSLProtocol -all +TLSv1.2 +TLSv1.3SSLCipherSuite HIGH:!aNULL:!MD5:!3DESSSLCompression offEntorno con clientes legacy (solo si es imprescindible)
Si necesitas compatibilidad con clientes antiguos, podrías habilitar configuraciones menos estrictas, pero esto aumenta el riesgo. En ese caso, documenta el motivo y limita el alcance (por ejemplo, solo en un sitio específico).
# Ejemplo conservador (evalúa con tu equipo de seguridad)SSLProtocol -all +TLSv1.2Evita reactivar TLS 1.0/1.1 salvo requisitos muy específicos y temporales.
Fallos típicos y cómo resolverlos
1) “Certificado inválido” en navegador
- Causa común (laboratorio): certificado autofirmado no confiable.
- Solución: importar la CA/Certificado en el almacén de confianza del sistema (solo laboratorio) o usar un certificado de CA pública en producción.
- Causa común (público): falta la cadena intermedia.
- Solución: usa
fullchain.pemenSSLCertificateFileo configuraSSLCertificateChainFilecon los intermedios correctos.
2) Hostname mismatch (CN/SAN no coincide)
- Síntoma: el certificado es válido pero no para
wwwo para el dominio exacto. - Diagnóstico: revisa SAN con
openssl s_client -showcertso inspecciona el certificado. - Solución: reemitir el certificado incluyendo todos los nombres necesarios en SAN (por ejemplo
midominio.comywww.midominio.com).
3) Apache no arranca: error leyendo la clave
- Síntoma: en el log aparece “Permission denied” o “unable to load private key”.
- Causas: permisos demasiado restrictivos para el usuario/grupo del proceso, ruta incorrecta, formato inválido, clave cifrada con passphrase sin soporte de arranque automático.
- Solución: verifica ruta, propietario y permisos; asegúrate de que el proceso pueda leer la clave sin exponerla. Si la clave tiene passphrase, considera usar mecanismos de gestión de secretos o una clave sin passphrase en servidores con controles adecuados.
4) Se sirve el certificado equivocado (SNI/VirtualHost)
- Síntoma: al conectar a un dominio, el certificado corresponde a otro sitio del mismo servidor.
- Diagnóstico: prueba con
-servernameenopenssl s_client. - Solución: asegúrate de que cada
<VirtualHost *:443>tengaServerNamecorrecto y su par deSSLCertificateFile/KeyFile. Revisa el orden de carga de sitios y que no haya un vhost “por defecto” capturando tráfico.
5) Redirección en bucle (HTTP↔HTTPS)
- Causa: reglas de redirección duplicadas (en vhost 80 y también en 443) o aplicación detrás de proxy que no detecta HTTPS.
- Solución: mantén la redirección solo en el vhost 80. Si hay proxy inverso, revisa cabeceras como
X-Forwarded-Protoy la configuración de la aplicación.