From 4c8a95bcca53500204c857b3d6bade92e3f14dcb Mon Sep 17 00:00:00 2001 From: henriquejsza Date: Sat, 25 Apr 2026 12:21:05 -0300 Subject: [PATCH 1/3] Document SSL reloading with Let's Encrypt See gh-50222 Signed-off-by: henriquejsza --- .../modules/reference/pages/features/ssl.adoc | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/ssl.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/ssl.adoc index 938d5be755b9..5c079eab21f8 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/ssl.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/ssl.adoc @@ -181,3 +181,31 @@ A file watcher is then watching the files and if they change, the SSL bundle wil This in turn triggers a reload in the consuming component, e.g. Tomcat rotates the certificates in the SSL enabled connectors. You can configure the quiet period (to make sure that there are no more changes) of the file watcher with the configprop:spring.ssl.bundle.watch.file.quiet-period[] property. + +[[features.ssl.reloading.lets-encrypt]] +=== Reloading SSL Bundles With Let's Encrypt + +If you use certificates issued by https://letsencrypt.org/[Let's Encrypt] and renewed by an external tool, such as https://certbot.eff.org/[Certbot], you can configure a PEM bundle to use the files from the `live` directory and enable reloading: + +[configprops,yaml] +---- + spring: + ssl: + bundle: + pem: + web-server: + reload-on-update: true + keystore: + certificate: "file:/etc/letsencrypt/live/example.com/fullchain.pem" + private-key: "file:/etc/letsencrypt/live/example.com/privkey.pem" + server: + ssl: + bundle: "web-server" +---- + +Spring Boot does not request or renew Let's Encrypt certificates. +When Certbot or another ACME client updates the configured files, the SSL bundle is reloaded. +Compatible consumers, such as Tomcat and Netty web servers, can then use the updated certificate without restarting the application. + +The files in `/etc/letsencrypt/live` are typically symbolic links to files in `/etc/letsencrypt/archive`. +The file watcher follows symbolic links so that updates to the target files can trigger a reload. From f53d9571ebfa5c2253949dcd0cfc252691ba551d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Sat, 30 May 2026 12:00:43 +0200 Subject: [PATCH 2/3] Polish "Document SSL reloading with Let's Encrypt" See gh-50222 --- .../docs/antora/modules/reference/pages/features/ssl.adoc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/ssl.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/ssl.adoc index 5c079eab21f8..c3e14b6dcbaa 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/ssl.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/ssl.adoc @@ -185,7 +185,9 @@ You can configure the quiet period (to make sure that there are no more changes) [[features.ssl.reloading.lets-encrypt]] === Reloading SSL Bundles With Let's Encrypt -If you use certificates issued by https://letsencrypt.org/[Let's Encrypt] and renewed by an external tool, such as https://certbot.eff.org/[Certbot], you can configure a PEM bundle to use the files from the `live` directory and enable reloading: +If you use certificates issued by https://letsencrypt.org/[Let's Encrypt] and renewed by an external tool, such as https://certbot.eff.org/[Certbot], you can configure a PEM bundle to use the generated files and enable reloading. +Certbot typically stores these in `/etc/letsencrypt/live/` under a directory named after your domain. +The following example shows how to configure a PEM bundle for `example.com`: [configprops,yaml] ---- @@ -193,14 +195,14 @@ If you use certificates issued by https://letsencrypt.org/[Let's Encrypt] and re ssl: bundle: pem: - web-server: + webserver: reload-on-update: true keystore: certificate: "file:/etc/letsencrypt/live/example.com/fullchain.pem" private-key: "file:/etc/letsencrypt/live/example.com/privkey.pem" server: ssl: - bundle: "web-server" + bundle: "webserver" ---- Spring Boot does not request or renew Let's Encrypt certificates. From 1a092b779f4cb9f2f75e1db973849fe9e6001d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Sat, 30 May 2026 12:59:18 +0200 Subject: [PATCH 3/3] Handle Gson explicitly in CodecsAutoConfigurationTests The change in gh-50447 added gson on the runtime classpath, which broke a test that looks for "any" JSON support, but only filtered Jackson and Jackson 2. This commit adds an explicit optional dependency to gson and adapt the test accordingly. See gh-50447 --- module/spring-boot-http-codec/build.gradle | 1 + .../http/codec/autoconfigure/CodecsAutoConfigurationTests.java | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/module/spring-boot-http-codec/build.gradle b/module/spring-boot-http-codec/build.gradle index eb60c2b976ff..10e6a15fff8d 100644 --- a/module/spring-boot-http-codec/build.gradle +++ b/module/spring-boot-http-codec/build.gradle @@ -30,6 +30,7 @@ dependencies { optional(project(":core:spring-boot-autoconfigure")) optional(project(":core:spring-boot-test")) + optional(project(":module:spring-boot-gson")) optional(project(":module:spring-boot-jackson")) optional(project(":module:spring-boot-jackson2")) optional(project(":module:spring-boot-kotlinx-serialization-json")) diff --git a/module/spring-boot-http-codec/src/test/java/org/springframework/boot/http/codec/autoconfigure/CodecsAutoConfigurationTests.java b/module/spring-boot-http-codec/src/test/java/org/springframework/boot/http/codec/autoconfigure/CodecsAutoConfigurationTests.java index 4e58f4404ad9..6c221bcbd685 100644 --- a/module/spring-boot-http-codec/src/test/java/org/springframework/boot/http/codec/autoconfigure/CodecsAutoConfigurationTests.java +++ b/module/spring-boot-http-codec/src/test/java/org/springframework/boot/http/codec/autoconfigure/CodecsAutoConfigurationTests.java @@ -20,6 +20,7 @@ import java.util.Map; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; import kotlinx.serialization.json.Json; import org.junit.jupiter.api.Test; import tools.jackson.databind.json.JsonMapper; @@ -150,7 +151,7 @@ void kotlinSerializationUsesLimitedPredicateWhenOtherJsonConverterIsAvailable() @Test void kotlinSerializationUsesUnrestrictedPredicateWhenNoOtherJsonConverterIsAvailable() { FilteredClassLoader classLoader = new FilteredClassLoader(JsonMapper.class.getPackage().getName(), - ObjectMapper.class.getPackage().getName()); + ObjectMapper.class.getPackage().getName(), Gson.class.getPackage().getName()); this.contextRunner.withClassLoader(classLoader) .withUserConfiguration(KotlinxJsonConfiguration.class) .run((context) -> {