SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor

Instalar Certbot para Apache en Ubuntu 24.04

Obtén un certificado Let's Encrypt con un solo comando. Ubuntu 24.04 incluye Certbot 2.9.0 por apt; evita snap y corrige el error por falta de ServerName.

Qué va a configurar

Un sitio de Apache en Ubuntu 24.04 que responde por HTTPS con un certificado gratuito de Let's Encrypt, de confianza para los navegadores, emitido por Certbot y renovado automáticamente mediante un temporizador de systemd que no tendrá que volver a supervisar. El comando que realiza el trabajo ocupa una sola línea. Todo lo que puede fallar falla antes de esa línea: un vhost sin ServerName, el puerto 80 bloqueado por el firewall del proveedor o el DNS que todavía apunta al servidor antiguo. Por eso, esta guía dedica la mayor parte del contenido a las condiciones previas e indica la cadena de error exacta que muestra cada fallo.

Dos notas sobre el alcance. Si su servidor web es nginx, el flujo general es el mismo, pero el plugin y las configuraciones son diferentes; use la versión de esta guía para nginx. Si el servicio que quiere proteger sólo es accesible internamente, por ejemplo un panel de administración en una dirección privada o un servidor de staging que nadie más visita, no necesita una autoridad certificadora; un certificado autofirmado requiere menos configuración y funciona sin conexión.

Requisitos previos y las tres formas en que esto falla antes de que Certbot se ejecute

  • Apache ya debe servir el sitio mediante HTTP sin cifrar. El complemento de Apache de Certbot modifica un sitio existente; no crea uno. Si parte de un VPS vacío, configure primero la pila LAMP en Ubuntu 24.04 y vuelva después: esta guía es su capítulo de TLS pendiente.
  • Un dominio público con un registro A que apunte a la dirección de su VPS. El desafío HTTP-01 de Let's Encrypt requiere que sus servidores de validación se conecten al servidor desde Internet: no sirve un homelab detrás de NAT sin redirección de puertos ni nombres .local. HTTP-01 puede validar una IP sin dominio, pero Let's Encrypt sólo emite certificados para IP mediante su perfil shortlived opcional (con una vigencia de 160 horas), y el Certbot 2.9.0 de apt no puede solicitar perfiles ACME ni direcciones IP. Por tanto, esta guía necesita un nombre de dominio. dig +short example.com debe devolver la dirección de su VPS. Si cambió el DNS durante la última hora, espere a que caduque el TTL del registro anterior antes de emitir el certificado.
  • Si existe un registro AAAA, debe ser correcto. Let's Encrypt siempre intenta usar IPv6 primero cuando se publica un registro AAAA. Si la conexión agota el tiempo de espera, reintenta mediante IPv4, pero ningún otro error tiene esa segunda oportunidad: un AAAA que apunte a una dirección que rechaza conexiones, o a un servidor activo que no sea este, hace que la validación falle aunque curl funcione correctamente desde su portátil, probablemente mediante IPv4. Publique un AAAA correcto o no publique ninguno.

Los puertos 80 y 443 deben estar abiertos en ufw y en el firewall de red de su proveedor; la mayoría de los paneles de alojamiento tienen un segundo firewall que el sistema operativo no puede ver. HTTP-01 valida específicamente mediante el puerto 80; no puede ejecutar este procedimiento sólo con 443.

sudo ufw allow "Apache Full"
sudo ufw status

Con estos requisitos cumplidos, todo el proceso dura quince minutos, de los cuales diez se dedican a leer.

¿Certbot con Snap o con apt? En 24.04, apt ya es una opción adecuada

Certbot pasó a distribuirse mediante snap hace años por un motivo válido: los paquetes de las distribuciones quedaron obsoletos. Ubuntu 20.04 incluía Certbot 0.40 y nunca lo actualizó, y el proyecto se cansó de depurar errores de cinco años de antigüedad. En 24.04 ese motivo ya no existe: el archivo de paquetes incluye Certbot 2.9.0, una versión publicada en febrero de 2024 perteneciente a la línea moderna 2.x, y unattended-upgrades instala las actualizaciones de seguridad que Ubuntu publique para ese paquete. Desde entonces, el proyecto original ha avanzado a la serie 5.x, pero esta guía no necesita esa versión. Mi recomendación para este sistema operativo es usar apt. Se evita el daemon snapd, el plugin de Apache se instala en la misma transacción y el temporizador de renovación se integra con systemd de la forma habitual en Debian.

sudo apt update
sudo apt install -y certbot python3-certbot-apache
certbot --version

Resultado correcto: certbot 2.9.0. El paquete python3-certbot-apache es el plugin que lee y modifica las configuraciones de Apache. Sin él, certbot --apache falla con The requested apache plugin does not appear to be installed.

Snap sigue siendo la opción adecuada en dos casos: si quiere la versión más reciente de Certbot el mismo día que se publica, o si necesita un plugin DNS que sólo se distribuya como snap (varios plugins de proveedores certbot-dns-* se distribuyen así). Si elige esa opción:

sudo apt remove -y certbot python3-certbot-apache
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Elija la opción que elija, no ejecute nunca ambas. Dos instalaciones implican dos programadores de renovación que compiten por /etc/letsencrypt, y el certbot que el shell encuentra en PATH puede no ser el que gestiona sus certificados. La línea apt remove anterior no es un adorno opcional.

El vhost que edita Certbot debe existir previamente; ServerName es lo que determina todo

certbot --apache funciona buscando el host virtual del puerto 80 cuyo ServerName o ServerAlias coincide con cada dominio -d que se proporciona. Después demuestra el control del dominio mediante ese host y escribe un equivalente SSL de ese vhost. Si no hay ningún ServerName coincidente, no hay coincidencia. Además, el 000-default.conf predeterminado de Ubuntu incluye ServerName comentado. Esa única línea comentada es la causa más habitual de que falle el comando grande de esta guía.

Por tanto, antes de usar Certbot, asigne al sitio un vhost basado en nombre correctamente configurado. Cree /etc/apache2/sites-available/example.com.conf:

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com
    ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
    CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>

Habilítelo y confirme que Apache analiza la configuración y dirige el nombre a ese vhost:

sudo a2ensite example.com.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
sudo apache2ctl -S

configtest debe mostrar Syntax OK. Si también muestra AH00558: apache2: Could not reliably determine the server's fully qualified domain name, se trata de una advertencia sobre el ServerName global, no sobre su vhost. Aquí no causa problemas y se silencia con echo "ServerName $(hostname -f)" | sudo tee /etc/apache2/conf-available/servername.conf && sudo a2enconf servername && sudo systemctl reload apache2.

La salida de -S es la comprobación importante. Debe aparecer una línea como port 80 namevhost example.com (/etc/apache2/sites-enabled/example.com.conf:1) con alias www.example.com debajo. Apache informa del enlace simbólico sites-enabled que leyó realmente, no del archivo que editó en sites-available. Si example.com no aparece asociado al puerto 80, Certbot tampoco lo encontrará.

Emitir el certificado: certbot --apache

sudo certbot --apache -d example.com -d www.example.com

La primera ejecución solicita tres datos: una dirección de correo electrónico (Let's Encrypt ya no la almacena con su cuenta de ACME ni envía avisos de vencimiento, por lo que debe supervisar las renovaciones), la aceptación de los términos de Let's Encrypt y si desea compartir su correo electrónico con la EFF. Ya no se pregunta por la redirección: desde Certbot 1.0, el instalador de Apache redirige HTTP a HTTPS de forma predeterminada (la pregunta se eliminó en 1.4), que es lo que necesita. Pase --no-redirect si realmente necesita que HTTP sin cifrar siga sirviendo contenido.

El resultado correcto es el siguiente. Debe leerlo, no limitarse a examinarlo por encima:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.com/privkey.pem
This certificate expires on 2027-01-09.

Deploying certificate
Successfully deployed certificate for example.com to /etc/apache2/sites-available/example.com-le-ssl.conf
Successfully deployed certificate for www.example.com to /etc/apache2/sites-available/example.com-le-ssl.conf
Congratulations! You have successfully enabled HTTPS on https://example.com and https://www.example.com

Detrás de ese mensaje, Certbot hizo cuatro cosas: habilitó el módulo ssl de Apache si aún no estaba habilitado, escribió example.com-le-ssl.conf, una copia de su vhost en *:443 con SSLEngine on y las rutas de los certificados, lo habilitó y añadió un bloque RewriteRule al vhost original del puerto 80 que redirige todo a HTTPS con 301. El archivo de su vhost original se modifica, no se reemplaza, y la copia SSL queda junto a él para que pueda leer cada línea que se añadió.

Dónde se encuentra realmente el certificado y por qué nunca debe copiarlo

Todo se guarda en /etc/letsencrypt/live/example.com/: fullchain.pem (el certificado y la cadena intermedia, que es lo que deben usar los servidores), privkey.pem (la clave privada, legible sólo por root), además de cert.pem y chain.pem para el software que necesita los componentes por separado. Son enlaces simbólicos a /etc/letsencrypt/archive/. Esta indirección es el mecanismo de renovación: la renovación escribe archivos nuevos en archive/ y vuelve a apuntar los enlaces simbólicos. Configure cualquier otro software para usar las rutas live/ y recibirá las renovaciones automáticamente. Si copia los archivos en otra ubicación, provocará una interrupción del servicio 90 días después.

El otro archivo que debe conocer es /etc/letsencrypt/renewal/example.com.conf. Registra cómo se emitió este certificado, authenticator = apache, installer = apache y los dominios, para que la renovación pueda repetir el proceso sin intervención, incluida la recarga posterior de Apache.

La renovación ya está programada: verifíquela, no la configure

Los certificados de Let's Encrypt duran actualmente 90 días por diseño, y el paquete apt ya instaló la infraestructura necesaria: un temporizador de systemd que ejecuta Certbot dos veces al día en horarios aleatorios y renueva cualquier certificado al que le queden menos de 30 días para caducar. No añada una tarea de cron: un segundo programador sólo genera ruido en los registros y aumenta la exposición a los límites de tasa. Let's Encrypt ha anunciado que, a partir del 10 de febrero de 2027, los certificados nuevos tendrán una vigencia predeterminada de 64 días. La ventana de 30 días seguirá funcionando con ellos; la renovación se producirá aproximadamente el día 34 en lugar del día 60. Por tanto, no es necesario cambiar nada en este servidor.

systemctl list-timers certbot.timer
sudo certbot renew --dry-run

El primer comando muestra el temporizador activo, con una hora NEXT dentro de las próximas 24 horas. La programación es de dos ejecuciones diarias con un retraso aleatorio, por lo que la hora exacta es deliberadamente impredecible (en la instalación mediante snap, el temporizador es snap.certbot.renew.timer). La ejecución de prueba realiza un ensayo completo de renovación contra el entorno de staging de Let's Encrypt: usa un desafío real, no emite ningún certificado y no consume el límite de tasa. El resultado correcto termina con:

Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/example.com/fullchain.pem (success)

Si la ejecución de prueba falla, la renovación real dentro de ~60 días fallará de la misma forma. Corrija el problema ahora, mientras el certificado actual todavía conserva toda su vigencia. La causa habitual es una regla del firewall añadida después de la emisión que volvió a cerrar el puerto 80.

Verifique con curl qué respuesta debe devolver y qué debe mostrar el candado

curl -sI http://example.com | head -n 3
curl -I https://example.com
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -issuer -dates

El primero debe devolver HTTP/1.1 301 Moved Permanently con una cabecera Location: https://example.com/. Esa es la redirección que instaló Certbot. El segundo debe devolver HTTP/1.1 200 OK sin que curl muestre errores relacionados con TLS. El tercero muestra el emisor, una línea O = Let's Encrypt con un CN corto como YE1 o YE2 (claves ECDSA) o YR1 o YR2 (claves RSA), y notAfter aproximadamente 90 días después. Un certificado emitido antes de que Let's Encrypt retirara sus intermediarios antiguos todavía puede mostrar un CN como R12 o E7 hasta su próxima renovación. Esto no es un error. En un navegador aparece el candado y, al hacer clic en él, se muestra el mismo emisor. Si curl funciona y el navegador muestra una advertencia, casi con total seguridad está viendo una página almacenada en caché o el nombre de host incorrecto, no un problema con el certificado.

Varios sitios: un certificado SAN o un certificado por sitio

Ambas opciones funcionan y se renuevan de la misma forma. Para sitios no relacionados en el mismo servidor, ejecute el comando de emisión una vez por sitio. Cada uno tendrá su propio directorio en live/ y su propia configuración de renovación. Un problema con un dominio nunca impedirá renovar los demás. Esta es mi opción predeterminada.

Para un sitio con varios nombres, inclúyalos en un solo certificado SAN. Un certificado puede incluir hasta 100 nombres. Ya lo hizo antes con example.com y www.example.com. Para añadir un nombre a un certificado existente más adelante, vuelva a emitirlo indicando el nombre del certificado y la lista nueva completa:

sudo certbot --apache --cert-name example.com -d example.com -d www.example.com -d blog.example.com

Certbot detecta que el conjunto de dominios ha cambiado, le pide que confirme la ampliación y reemplaza el certificado en la misma ruta live/. Por tanto, no es necesario modificar nada más. Tenga en cuenta que la lista reemplaza a la anterior; no se amplía. Si omite www de ese comando, el nuevo certificado lo elimina silenciosamente.

Los comodines requieren DNS-01 y, normalmente, no necesita un certificado comodín

HTTP-01 no puede emitir *.example.com. Colocar un archivo en un servidor web demuestra el control de un nombre de host, no de todo un espacio de nombres. Los comodines requieren el desafío DNS-01: Certbot establece un registro TXT en _acme-challenge.example.com. En la práctica, esto significa usar un plugin certbot-dns-* con credenciales de API del proveedor DNS, o editar manualmente los registros TXT en cada renovación con --manual (es una opción poco práctica; no base su planificación en ella). La guía completa, desde el funcionamiento de los registros TXT hasta un plugin que renueva los certificados sin intervención, está en certificados comodín con Certbot mediante DNS-01. Recomendación práctica: si conoce cuatro subdominios, un certificado SAN que incluya los cuatro es más sencillo que un comodín y no requiere almacenar claves de API de DNS en el servidor.

Modos de fallo y mensajes que verá

Certbot no puede iniciarse porque la configuración de Apache está dañada.

The apache plugin is not working; there may be problems with your existing configuration.
The error was: MisconfigurationError('Error while running apache2ctl configtest.\n\nAction \'configtest\' failed.\nThe Apache error log may have more information.\n\nAH00526: Syntax error on line 12 of /etc/apache2/sites-enabled/example.com.conf')

El plugin ejecuta configtest antes de modificar nada y se detiene si Apache tiene algún problema. Los \n aparecen literalmente porque Certbot muestra la representación de la excepción. Ejecute sudo apache2ctl configtest manualmente: indica el archivo y la línea. Normalmente se trata de un error tipográfico al editar a mano, un SSLCertificateFile que apunta a una ruta que ya no existe o un módulo referenciado pero no habilitado. Corrija el problema hasta que muestre Syntax OK y vuelva a ejecutar Certbot.

Ningún vhost coincide con el dominio.

Unable to find a virtual host listening on port 80 which is currently the only challenge port.

Este es el fallo de ServerName que se describió antes y que se detecta al emitir el certificado. Certbot buscó en todos los vhost habilitados del puerto 80 un ServerName/ServerAlias que coincidiera con su -d, pero no encontró ninguno. sudo apache2ctl -S muestra cómo enruta realmente Apache las peticiones. Añada la línea ServerName al vhost correcto, recargue Apache y vuelva a intentarlo. Un caso parecido ocurre cuando la validación llega al vhost equivocado: la respuesta al desafío devuelve Invalid response ... 404 porque otro sitio recibió la petición. El diagnóstico y la herramienta son los mismos: apache2ctl -S.

La validación agota el tiempo de espera.

Certbot failed to authenticate some domains (authenticator: apache).
...
Detail: ...: Timeout during connect (likely firewall problem)

Let's Encrypt no pudo abrir una conexión TCP al puerto 80 en la dirección que anuncia su DNS. Por orden de probabilidad: el firewall de red del proveedor, independiente de ufw y configurado en el panel de alojamiento; un conjunto de reglas de ufw que permite sólo 443 o sólo SSH; o un DNS que todavía apunta a un servidor anterior. Un registro AAAA obsoleto por sí solo normalmente no provoca este fallo, porque cuando se agota el tiempo de espera del intento IPv6, Let's Encrypt vuelve a intentarlo mediante IPv4. Los problemas con AAAA suelen aparecer como Connection refused o Invalid response desde el servidor equivocado. Pruebe desde fuera del VPS: curl -I http://example.com ejecutado desde su portátil reproduce lo que ve el validador de Let's Encrypt.

Ha alcanzado un límite de solicitudes tras varios reintentos.

Error creating new order :: too many failed authorizations (5) for "example.com" in the last 1h0m0s, retry after ... UTC: see https://letsencrypt.org/docs/rate-limits/...

Let's Encrypt permite 5 validaciones fallidas por nombre de host, cuenta y hora, mediante un límite que se repone y recupera aproximadamente un reintento cada 12 minutos. Reintentar repetidamente contra un firewall averiado agota este límite con rapidez. Esperar funciona, pero la solución real es cambiar el procedimiento: después de cualquier fallo, depure el problema con el entorno de staging hasta que la validación funcione.

sudo certbot certonly --apache --dry-run -d example.com -d www.example.com

Tenga en cuenta certonly: --dry-run sólo se acepta con los subcomandos certonly y renew. La forma independiente certbot --apache --dry-run no se ejecuta y muestra --dry-run currently only works with the 'certonly' or 'renew' subcommands. La prueba en seco valida contra staging, que tiene sus propios límites más amplios y no emite certificados reales, por lo que puede fallar allí durante toda la tarde. Vuelva a ejecutar el comando real sólo cuando staging funcione. Los otros límites, 50 certificados por dominio registrado y semana y 5 duplicados del mismo conjunto de nombres por semana, sólo se alcanzan si un script vuelve a emitir certificados en un bucle.

Cuando HTTPS ya funcione, recuerde que el certificado protege el transporte, no el servidor: el puerto 22 seguirá recibiendo intentos de contraseña durante todo el día. Combinar esta configuración con Fail2ban en Ubuntu 24.04 es el siguiente paso natural y lleva unos treinta minutos.

FAQ

¿Debo instalar Certbot con snap o apt para Apache en Ubuntu 24.04?

Use apt. Ubuntu 24.04 incluye Certbot 2.9.0, que es suficientemente actual para todo lo que se explica en esta guía, recibe las actualizaciones de seguridad que Ubuntu publica mediante unattended-upgrades y no requiere snapd. Elija snap sólo si necesita de inmediato la versión más reciente o un plugin DNS distribuido exclusivamente como snap. Si cambia, ejecute primero apt remove certbot python3-certbot-apache para que nunca coexistan dos planificadores de renovación.

¿Por qué Certbot muestra «Unable to find a virtual host listening on port 80»?

Porque no hay ningún vhost habilitado en el puerto 80 que tenga un ServerName o ServerAlias coincidente con el dominio que indicó mediante -d. El vhost predeterminado de Ubuntu incluye ServerName comentado. Ejecute sudo apache2ctl -S, localice o cree el vhost que debe gestionar ese nombre, añada ServerName example.com, recargue Apache y vuelva a ejecutar Certbot.

¿Cómo corrijo «Timeout during connect (likely firewall problem)»?

Let's Encrypt no pudo acceder al puerto 80 en la dirección que publica su DNS. Compruebe el firewall de red del panel de su proveedor y también ufw. Confirme que dig +short example.com devuelve este VPS y corrija o elimine cualquier registro AAAA obsoleto, ya que la validación intenta usar IPv6 primero y sólo cambia a IPv4 después de un tiempo de espera. Confirme la corrección desde fuera del servidor con curl -I http://example.com y haga una prueba con sudo certbot certonly --apache --dry-run -d example.com antes de emitir el certificado real.

¿Certbot renueva los certificados automáticamente en Ubuntu 24.04?

Sí. El paquete apt instala certbot.timer, un temporizador de systemd que se ejecuta dos veces al día y renueva cualquier certificado al que le queden menos de 30 días de validez. Después recarga Apache. snap usa snap.certbot.renew.timer para la misma tarea. Verifique la configuración con systemctl list-timers certbot.timer y haga una prueba con sudo certbot renew --dry-run. No añada su propio trabajo de cron.

¿Cómo obtengo un certificado comodín con Certbot y Apache?

Los certificados comodín requieren el desafío DNS-01. Certbot debe crear un registro TXT en _acme-challenge.example.com, lo que requiere un plugin certbot-dns-* con credenciales de API del proveedor DNS. La alternativa --manual requiere editar manualmente los registros TXT en cada renovación. Si sólo tiene unos pocos subdominios conocidos, un certificado SAN que los enumere explícitamente es más sencillo y evita almacenar las claves de la API DNS en el servidor.