¿Qué vía encaja?
- Proxy inverso delante: nginx, Apache o Caddy se encargan de TLS y la aplicación Java funciona internamente por HTTP. Suele ser lo más sencillo; certificados y renovación se quedan en el proxy. El generador de configuración TLS crea una configuración adecuada.
- Tomcat o Spring Boot directamente: útil sin proxy, en servicios pequeños o contenedores. De eso trata este artículo.
Obtener el certificado
Let's Encrypt valida por HTTP-01 en el puerto 80 o por DNS-01. Si no hay nada en el puerto 80, basta el modo standalone de certbot; si no, webroot o DNS. El asistente ACME te da los comandos. Después los archivos están en /etc/letsencrypt/live/example.com/:
cert.pem,chain.pem,fullchain.pem: certificado, intermedio y ambos juntosprivkey.pem: la clave privada. Desde la versión 2.0, certbot crea claves ECDSA por defecto.
La trampa de los permisos
Los directorios live y archive solo los puede leer root. Tomcat y Spring Boot se ejecutan con su propio usuario y reciben «Permission denied». En lugar de relajar permisos, un deploy hook copia los archivos tras cada renovación a un sitio que la aplicación pueda leer:
#!/bin/sh # /etc/letsencrypt/renewal-hooks/deploy/tomcat.sh (hacer ejecutable) for f in cert.pem chain.pem fullchain.pem privkey.pem; do install -o tomcat -g tomcat -m 0600 "$RENEWED_LINEAGE/$f" /opt/tomcat/conf/tls/$f done systemctl restart tomcat
Tomcat con archivos PEM
Tomcat 9, 10 y 11 leen PEM directamente; no hace falta keystore. En conf/server.xml:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
SSLEnabled="true" maxParameterCount="1000">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
<SSLHostConfig protocols="TLSv1.2+TLSv1.3">
<Certificate certificateFile="conf/tls/cert.pem"
certificateKeyFile="conf/tls/privkey.pem"
certificateChainFile="conf/tls/chain.pem" />
</SSLHostConfig>
</Connector>
Con certificateChainFile, Tomcat entrega también el intermedio. Para recargar el certificado sin reiniciar, usa el manager: /manager/text/sslReload. El usuario necesita el rol manager-script.
Spring Boot con un SSL bundle
Desde Spring Boot 3.1 los certificados se describen como SSL bundle. Desde 3.2, Spring Boot los recarga solo cuando cambian y el reinicio en el hook sobra:
server.port=8443 server.ssl.bundle=web spring.ssl.bundle.pem.web.keystore.certificate=file:/opt/app/tls/fullchain.pem spring.ssl.bundle.pem.web.keystore.private-key=file:/opt/app/tls/privkey.pem spring.ssl.bundle.pem.web.reload-on-update=true
Spring Boot 2.7 y 3.0 aún no tienen bundles, pero PEM funciona igualmente:
server.ssl.certificate=file:/opt/app/tls/fullchain.pem server.ssl.certificate-private-key=file:/opt/app/tls/privkey.pem
Versiones antiguas: crear un keystore
Las versiones antiguas de Tomcat o Spring Boot necesitan un keystore. El hook lo vuelve a crear en cada renovación:
openssl pkcs12 -export -in "$RENEWED_LINEAGE/fullchain.pem" -inkey "$RENEWED_LINEAGE/privkey.pem" \ -name tomcat -out /opt/app/tls/keystore.p12 -passout pass:secreto
server.ssl.key-store=file:/opt/app/tls/keystore.p12 server.ssl.key-store-type=PKCS12 server.ssl.key-store-password=secreto server.ssl.key-alias=tomcat
El asistente de keystores Java hace lo mismo en el navegador: pega certificado y clave y guarda como PKCS#12.
El puerto 443 sin root
Java no debería ejecutarse como root y por eso no puede abrir puertos por debajo de 1024. Lo habitual es arrancar la aplicación en 8443 y redirigir el 443 en el cortafuegos:
sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443
Otra opción es AmbientCapabilities=CAP_NET_BIND_SERVICE en la unidad de systemd. Después comprueba cadena y protocolos con el comprobador SSL y añade el servidor al resumen de caducidad.
FAQ
¿Tengo que reiniciar Tomcat tras cada renovación?
Con Tomcat sí, o usa sslReload en el manager. Spring Boot 3.2+ con reload-on-update recarga solo los archivos modificados.
¿Funciona Let's Encrypt para servidores internos?
Sí, con el desafío DNS-01. El servidor no tiene que ser accesible desde Internet; basta un registro TXT en el DNS público.
Tomcat muestra «Cannot recover key» o «keystore password was incorrect».
Las contraseñas del keystore y de la clave son distintas o el alias no coincide. En PKCS#12 ambas contraseñas deben ser iguales.
¿Funciona una clave ECDSA con Java?
Sí, todas las versiones actuales de Java admiten ECDSA. Para clientes muy antiguos, certbot puede obtener un certificado RSA con --key-type rsa.