Está muy bien pero tiene alguna que otra particularidad que lo hace un poco puñetero.
La EFF ha publicado un cliente para obtener y renovar certificados con el proyecto Let’s Encrypt que simplifica mucho la tarea, especialmente para instalaciones sencillas. Se llama certbot y está empaquetado y disponible para un buen puñado de versiones de servidor web y sistema operativo. Además se dispone de una buena página de documentación donde se cubren casos simples y complejos; con servidores web conocidos o configuraciones extrañas.
El programa certbot puede utilizar varios mecanismos para responder al reto del servidor cuando se crean certificados. El que tengo que emplear, por limitaciones de los otros, es el standalone y tiene algunas peculiaridades algo molestas cuando se encuentra un escenario como el siguiente:
- Un servidor funcionando bajo Apache.
- Múltiples dominios con servidores virtuales con:
- Directorios raíz bajo
/var/www
o bajo/usr/share
dado que pueden ser aplicaciones web instaladas mediante paquete del sistema. - Conexión SSL forzada en todos ellos.
- Directorios raíz bajo
- Un único certificado para todos.
Dado lo anterior no puedo dejar que las peticiones a /.well-known/acme-challenge
se sirvan de cada uno de los directorios raíz de los servidores virtuales. El programa certbot con el mecanismo standalone creará esa ruta físicamente (quieras o no) y guardará allí el token correspondiente al desafío. En algunos casos puede que sí pueda y en otros, al ser directorios de sistema como /usr/share
, pues no.
Como quiero forzar las conexiones seguras en todos los casos (o en su inmensa mayoría) he creado una configuración que se incluye en cada servidor virtual de esta manera:
RewriteEngine on RewriteCond %{HTTPS} !^on$ [NC] RewriteRule . https://%{HTTP_HOST}%{REQUEST_URI} [L]
Pero esto supone que cuando certbot funcione se encontrará con conexiones SSL quiera o no; y, según el estado de los certificados (pueden haber caducado) podrá hacerlo automáticamente o la liará parda y pedirá ayuda al administrador de turno para hacerlo a mano.
Así que a lo anterior tiene que contemplar ese escenario. Primero empleamos un alias para el directorio común de trabajo y le damos permisos concretos. Esto yo lo incluyo en un archivo de configuración en /etc/apache2/conf-available/letsencrypt.conf
tal que así:
Alias /letsencrypt /var/www/letsencrypt <Directory /var/www/letsencrypt> Options None AllowOverride None Require all granted </Directory>
Y en la parte de reescritura le añado antes la siguiente regla:
RewriteEngine on Alias /letsencrypt /var/www/letsencrypt RewriteCond %{REQUEST_URI} ^/\.well\-known/acme\-challenge/ RewriteRule . /letsencrypt%{REQUEST_URI} [PT] [L] RewriteCond %{HTTPS} !^on$ [NC] RewriteCond %{REQUEST_URI} !^/\.well\-known/acme\-challenge/ RewriteRule . https://%{HTTP_HOST}%{REQUEST_URI} [L]
De manera que todas las peticiones que realiza certbot son reconstruídas a /letsencrypt/.well-known/acme-challenge/XXXXXX y entran de nuevo en el motor de URL gracias al parámetro
[PT]
de la reescritura.
Y una vez completado ésto, conseguidos los certificados, sólo queda asegurarse de que tienen los permisos necesarios para que el grupo correspondiente ssl-cert tenga acceso a ellos (el servidor XMPP Prosody, por ejemplo, no funciona como root y necesita poder leerlos), y reiniciar los servicios.
El archivo de configuración de certbot incluye la posibilidad de llamar a un programa después de la renovación con el parámetro post-hook
.
#!/bin/bash # Variables TARGET=/etc/letsencrypt/archive/ SERVICES="prosody apache2 exim4 dovecot" GROUP=ssl-cert # Ajustamos permisos chown -R ${GROUP} ${TARGET} # y reiniciamos servicios systemctl restart ${SERVICES}
Enlaces y referencias