Quelle approche ?
- Proxy inverse en frontal : nginx, Apache ou Caddy gèrent TLS, l’application Java tourne en HTTP en interne. C’est souvent le plus simple ; certificats et renouvellement restent au proxy. Le générateur de configuration TLS crée une configuration adaptée.
- Tomcat ou Spring Boot directement : utile sans proxy, pour de petits services ou des conteneurs. C’est le sujet de cet article.
Obtenir le certificat
Let's Encrypt valide via HTTP-01 sur le port 80 ou via DNS-01. Si rien ne tourne sur le port 80, le mode standalone de certbot suffit ; sinon webroot ou DNS. L’assistant ACME fournit les commandes. Les fichiers se trouvent ensuite dans /etc/letsencrypt/live/example.com/ :
cert.pem,chain.pem,fullchain.pem: certificat, intermédiaire, et les deux ensembleprivkey.pem: la clé privée. Depuis la version 2.0, certbot crée des clés ECDSA par défaut.
Le piège des droits
Les répertoires live et archive ne sont lisibles que par root. Tomcat et Spring Boot tournent sous leur propre utilisateur et obtiennent « Permission denied ». Plutôt que d’assouplir les droits, un deploy hook copie les fichiers après chaque renouvellement vers un emplacement lisible par l’application :
#!/bin/sh # /etc/letsencrypt/renewal-hooks/deploy/tomcat.sh (à rendre exécutable) 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 avec des fichiers PEM
Tomcat 9, 10 et 11 lisent directement le PEM, sans keystore. Dans 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>
Grâce à certificateChainFile, Tomcat livre aussi l’intermédiaire. Pour recharger le certificat sans redémarrage, utilise le manager : /manager/text/sslReload. L’utilisateur a besoin du rôle manager-script.
Spring Boot avec un SSL bundle
Depuis Spring Boot 3.1, on décrit les certificats sous forme de SSL bundle. Depuis 3.2, Spring Boot les recharge lui-même quand ils changent ; le redémarrage dans le hook devient inutile :
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 et 3.0 n’ont pas encore de bundles, mais le PEM fonctionne quand même :
server.ssl.certificate=file:/opt/app/tls/fullchain.pem server.ssl.certificate-private-key=file:/opt/app/tls/privkey.pem
Versions plus anciennes : créer un keystore
Les anciennes versions de Tomcat ou Spring Boot ont besoin d’un keystore. Le hook le recrée alors à chaque renouvellement :
openssl pkcs12 -export -in "$RENEWED_LINEAGE/fullchain.pem" -inkey "$RENEWED_LINEAGE/privkey.pem" \ -name tomcat -out /opt/app/tls/keystore.p12 -passout pass:secret
server.ssl.key-store=file:/opt/app/tls/keystore.p12 server.ssl.key-store-type=PKCS12 server.ssl.key-store-password=secret server.ssl.key-alias=tomcat
L’assistant keystore Java fait la même chose dans le navigateur : colle certificat et clé, enregistre en PKCS#12.
Le port 443 sans root
Java ne devrait pas tourner en root et ne peut donc pas ouvrir de ports sous 1024. On démarre en général l’application sur 8443 et on redirige 443 dans le pare-feu :
sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443
Autre option : AmbientCapabilities=CAP_NET_BIND_SERVICE dans l’unité systemd. Vérifie ensuite chaîne et protocoles avec la vérification SSL et ajoute le serveur à l’aperçu des expirations.
FAQ
Faut-il redémarrer Tomcat après chaque renouvellement ?
Avec Tomcat oui, ou utilise sslReload dans le manager. Spring Boot 3.2+ avec reload-on-update recharge lui-même les fichiers modifiés.
Let's Encrypt fonctionne-t-il pour des serveurs internes ?
Oui, avec le défi DNS-01. Le serveur n’a pas besoin d’être joignable depuis Internet ; il suffit d’un enregistrement TXT dans le DNS public.
Tomcat affiche « Cannot recover key » ou « keystore password was incorrect ».
Les mots de passe du keystore et de la clé diffèrent, ou l’alias est faux. En PKCS#12, les deux mots de passe doivent être identiques.
Une clé ECDSA fonctionne-t-elle avec Java ?
Oui, toutes les versions actuelles de Java gèrent ECDSA. Pour de très vieux clients, certbot peut obtenir un certificat RSA avec --key-type rsa.