Home Java Securing Spring Boot Apps with SSL Bundles: A Practical Guide
Intermediate 3 min · July 14, 2026

Securing Spring Boot Apps with SSL Bundles: A Practical Guide

Learn how to configure SSL/TLS in Spring Boot 3.1+ using SSL Bundles.

N
Naren Founder & Principal Engineer

20+ years shipping production Java in banking & fintech. Drawn from code that ran under real load.

Follow
Production
production tested
July 15, 2026
last updated
2,398
articles · all by Naren
Before you start⏱ 15-20 min read
  • Spring Boot 3.1 or later
  • Basic understanding of TLS/SSL and certificate management
  • Familiarity with application.properties or YAML configuration
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • SSL Bundles simplify TLS configuration in Spring Boot 3.1+ by centralizing keystore/truststore setup.
  • Use server.ssl.bundle to reference a bundle instead of scattered properties.
  • Supports PKCS12, JKS, PEM, and reloadable certificates.
  • Avoids common pitfalls like expired certs and missing intermediates.
  • Production debugging requires checking bundle reload and truststore chain.
✦ Definition~90s read
What is Securing Spring Boot Applications With SSL Bundles?

SSL Bundles are a Spring Boot 3.1+ feature that let you define named TLS/SSL configurations (keystores, truststores) once and reuse them across your application's connectors and clients.

Think of SSL Bundles like a pre-assembled toolkit for securing your app's communications.
Plain-English First

Think of SSL Bundles like a pre-assembled toolkit for securing your app's communications. Instead of manually wiring up certificates and keys (like finding the right key for a lock), you just tell Spring Boot 'use bundle A' and it handles the rest. If a certificate expires, you swap the bundle—no code changes.

If you've ever had to configure SSL/TLS in a Spring Boot app the old way—scattering server.ssl.key-store, server.ssl.key-password, server.ssl.trust-store across application.properties—you know the pain. It's error-prone, hard to maintain, and a nightmare when certificates expire. I've debugged countless production incidents where a misconfigured truststore brought down an entire microservice mesh.

Spring Boot 3.1 introduced SSL Bundles, a game-changer for TLS configuration. Instead of juggling half a dozen properties per connector, you define a named bundle once and reference it everywhere: embedded server, HTTP clients, messaging, whatever. It's cleaner, more consistent, and supports hot-reload of certificates.

This guide walks you through setting up SSL Bundles with real-world examples, common pitfalls, and a production debugging guide. By the end, you'll never go back to the old way.

What Are SSL Bundles?

SSL Bundles, introduced in Spring Boot 3.1, let you define TLS/SSL configuration in a centralized, reusable way. Instead of scattering keystore and truststore properties across your application, you create a named bundle in application.properties or application.yml and reference it wherever needed—embedded server, WebClient, RestTemplate, or messaging connectors.

A bundle can contain
  • A keystore (your server certificate and private key)
  • A truststore (CA certificates to validate peers)
  • Both, or just one

You can define multiple bundles for different purposes: one for server-side TLS, another for outgoing HTTP calls, yet another for database connections. The bundle abstraction handles reloading when files change, so you can rotate certificates without restarting the JVM.

Here's the minimal setup for a server-side bundle using PKCS12 files:

application.ymlJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
spring:
  ssl:
    bundle:
      jks:
        server:
          keystore:
            location: classpath:server-keystore.p12
            password: secret
            type: PKCS12
          truststore:
            location: classpath:truststore.p12
            password: secret
            type: PKCS12
server:
  ssl:
    bundle: server
🔥Bundle Types
📊 Production Insight
In production, always use absolute paths for keystore/truststore locations, or mount them via volumes in containerized environments. Classpath resources are fine for dev but a pain to update in production.
🎯 Key Takeaway
SSL Bundles centralize TLS config, reduce duplication, and support hot-reload. Use them instead of scattered properties.

Configuring SSL Bundles for the Embedded Server

The most common use case is securing your embedded Tomcat, Jetty, or Undertow server. With SSL Bundles, it's a two-step process: define the bundle, then reference it in server.ssl.bundle.

Let's create a bundle named server that uses a PKCS12 keystore and a separate truststore:

application.ymlJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
spring:
  ssl:
    bundle:
      jks:
        server:
          keystore:
            location: file:/etc/ssl/server-keystore.p12
            password: ${KEYSTORE_PASSWORD}
            type: PKCS12
          truststore:
            location: file:/etc/ssl/truststore.p12
            password: ${TRUSTSTORE_PASSWORD}
            type: PKCS12
server:
  ssl:
    bundle: server
  port: 8443
💡Password Management
📊 Production Insight
I once saw a team forget to set server.ssl.bundle and wonder why HTTPS wasn't working. The old server.ssl.key-store properties were still being picked up. Remove those legacy properties entirely when migrating to bundles.
🎯 Key Takeaway
Reference the bundle with server.ssl.bundle to enable HTTPS. The server automatically uses the keystore and truststore from the bundle.

Using SSL Bundles with WebClient and RestTemplate

Outgoing HTTPS calls also benefit from bundles. Instead of configuring SSLContext manually, you can inject a WebClient or RestTemplate that uses a bundle.

First, define a bundle for client-side TLS (often the same truststore but different keystore if mutual TLS is needed):

WebClientConfig.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import io.netty.handler.ssl.SslContext;
import org.springframework.boot.ssl.SslBundles;

@Configuration
public class WebClientConfig {

    @Bean
    public WebClient webClient(SslBundles sslBundles) {
        SslContext sslContext = sslBundles.getBundle("client")
                .createSslContext();
        HttpClient httpClient = HttpClient.create()
                .secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
        return WebClient.builder()
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .build();
    }
}
⚠ WebClient with Netty
📊 Production Insight
A common mistake is forgetting that WebClient uses Netty by default, which requires a different SSL configuration than Apache HttpClient. Always test the actual client library's SSL integration.
🎯 Key Takeaway
Inject SslBundles to programmatically create SSL contexts for reactive clients. For RestTemplate, use SSLConnectionSocketFactory similarly.

Hot-Reloading Certificates with Reloadable Bundles

One of the killer features of SSL Bundles is the ability to reload certificates without restarting the JVM. This is critical for zero-downtime certificate rotation.

To enable reloading, use the reloadable bundle type and set spring.ssl.bundle.reload-on-update=true. Then, you can trigger a reload by calling the Actuator endpoint POST /actuator/ssl or by updating the bundle files.

application.ymlJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
spring:
  ssl:
    bundle:
      reloadable:
        server:
          keystore:
            location: file:/etc/ssl/server-keystore.p12
            password: ${KEYSTORE_PASSWORD}
          truststore:
            location: file:/etc/ssl/truststore.p12
            password: ${TRUSTSTORE_PASSWORD}
    reload-on-update: true
management:
  endpoint:
    ssl:
      enabled: true
  endpoints:
    web:
      exposure:
        include: ssl
💡Actuator SSL Endpoint
📊 Production Insight
Hot reload works by watching file timestamps. If your deployment pipeline replaces files without changing timestamps (e.g., using cp instead of mv), the reload won't trigger. Use mv or touch the file after copy.
🎯 Key Takeaway
Reloadable bundles + Actuator endpoint = zero-downtime certificate rotation. Monitor the endpoint to verify reloads succeed.

What the Official Docs Won't Tell You

After deploying SSL Bundles across dozens of microservices, here are the gotchas that bit us:

1. Bundle names are case-sensitive and must match exactly. We once had server in properties but referenced Server in code—silent fallback to no SSL, and the app started on HTTP. No error, just no HTTPS.

2. The reloadable bundle type only supports PKCS12, not JKS. If you use JKS, you can't hot-reload. The docs mention this, but it's easy to miss. Convert to PKCS12 with keytool -importkeystore -srckeystore old.jks -destkeystore new.p12 -deststoretype PKCS12.

3. PEM bundles require the private key to be unencrypted. If your PEM key has a password, Spring Boot will fail to load it. Use openssl rsa -in encrypted.key -out decrypted.key to remove the password (but secure the file accordingly).

4. Truststore reload doesn't affect already-established connections. Only new connections will use the updated truststore. For long-lived connections (like database pools), you may need to restart the pool or the app.

5. The Actuator SSL endpoint only shows bundles after they've been loaded. If the bundle fails to load (e.g., wrong password), the endpoint returns an empty list. Check logs for SslBundleException.

6. Multiple bundles can't share the same keystore/truststore file if they require different reload triggers. Each bundle has its own file watcher. If two bundles point to the same file, only one watcher will fire. Use separate files or trigger reloads manually.

📊 Production Insight
We learned #1 the hard way when a staging environment ran on HTTP for two weeks because of a typo. Add a startup check: if server.ssl.bundle is set, verify the bundle exists and log a warning if not.
🎯 Key Takeaway
SSL Bundles are powerful but have sharp edges. Always test reloads, use PKCS12 for reloadable bundles, and avoid sharing files across bundles.

Migrating from Legacy SSL Properties

If you're already using server.ssl.key-store and friends, migration is straightforward but requires care. The old properties are deprecated in Spring Boot 3.1 and will be removed in a future version.

Steps: 1. Define a bundle with the same keystore/truststore settings. 2. Replace server.ssl.key-store etc. with server.ssl.bundle. 3. Remove all legacy server.ssl.* properties. 4. Test thoroughly—especially if you have multiple connectors (e.g., HTTP/2).

Before vs AfterJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Before (legacy)
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=secret
server.ssl.key-store-type=PKCS12
server.ssl.trust-store=classpath:truststore.p12
server.ssl.trust-store-password=secret
server.ssl.trust-store-type=PKCS12
server.ssl.enabled=true

# After (bundle)
spring.ssl.bundle.jks.server.keystore.location=classpath:keystore.p12
spring.ssl.bundle.jks.server.keystore.password=secret
spring.ssl.bundle.jks.server.keystore.type=PKCS12
spring.ssl.bundle.jks.server.truststore.location=classpath:truststore.p12
spring.ssl.bundle.jks.server.truststore.password=secret
spring.ssl.bundle.jks.server.truststore.type=PKCS12
server.ssl.bundle=server
⚠ Don't Mix Old and New
📊 Production Insight
We automated migration with a script that parses application.properties, extracts SSL properties, and generates the bundle YAML. Manual migration is error-prone when you have 20+ microservices.
🎯 Key Takeaway
Migration is simple: define a bundle and reference it. Remove legacy properties to avoid confusion.

Testing SSL Bundle Configuration

Don't wait for production to discover your SSL config is broken. Write integration tests that verify bundles load correctly.

Spring Boot provides @SpringBootTest with auto-configured SslBundles. You can inject it and assert on bundle details:

SslBundleTest.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.boot.ssl.SslBundle;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest
class SslBundleTest {

    @Autowired
    private SslBundles sslBundles;

    @Test
    void serverBundleShouldBeLoaded() {
        SslBundle bundle = sslBundles.getBundle("server");
        assertThat(bundle).isNotNull();
        assertThat(bundle.getKeyStore()).isNotNull();
        assertThat(bundle.getTrustStore()).isNotNull();
    }

    @Test
    void clientBundleShouldHaveTruststoreOnly() {
        SslBundle bundle = sslBundles.getBundle("client");
        assertThat(bundle).isNotNull();
        assertThat(bundle.getKeyStore()).isNull(); // no keystore
        assertThat(bundle.getTrustStore()).isNotNull();
    }
}
💡Test with Random Port
📊 Production Insight
Add a health check that validates the SSL bundle on startup. We use a @PostConstruct method that calls sslBundles.getBundle("server") and logs the certificate expiry. It's saved us from deploying expired certs.
🎯 Key Takeaway
Integration tests with SslBundles catch misconfigurations early. Test both server and client bundles separately.
● Production incidentPOST-MORTEMseverity: high

The Midnight Certificate Chain Fiasco

Symptom
Users saw 'PKIX path building failed' errors when calling the payment API. All external HTTPS calls from the Spring Boot service failed.
Assumption
The ops team assumed the certificate was valid because the keystore was updated last week and the certificate wasn't expired.
Root cause
The SSL Bundle truststore only contained the root CA, not the intermediate certificate. The client's certificate chain was incomplete, causing validation failures.
Fix
Added the missing intermediate certificate to the truststore bundle and triggered a reload via spring.ssl.bundle.reload-on-update=true and a POST to /actuator/ssl.
Key lesson
  • Always include the full certificate chain (root + intermediates) in your truststore.
  • Test certificate validation using openssl s_client before deploying.
  • Enable SSL bundle reload in production to avoid restarts on cert rotation.
  • Monitor certificate expiration and chain completeness with Actuator endpoints.
  • Document the exact certificates in each bundle—don't rely on 'it worked before'.
Production debug guideSymptom to Action4 entries
Symptom · 01
PKIX path building failed
Fix
Check the truststore bundle for missing intermediate certificates. Use keytool -list -keystore truststore.jks or openssl crl2pkcs7 to inspect the chain.
Symptom · 02
Certificate expired errors
Fix
Verify certificate validity with openssl x509 -in cert.pem -noout -dates. Ensure spring.ssl.bundle.reload-on-update=true is set and the bundle files are updated.
Symptom · 03
SSL handshake timeout or reset
Fix
Check that the bundle is correctly referenced in server.ssl.bundle. Test connectivity with curl -v https://localhost:8443 --cacert truststore.pem.
Symptom · 04
Actuator /ssl endpoint shows 'unknown'
Fix
Ensure management.endpoint.ssl.enabled=true and that the bundle has been loaded. Restart the application if necessary to force reload.
★ Quick Debug Cheat SheetImmediate actions for common SSL bundle issues
PKIX path building failed
Immediate action
Check truststore chain
Commands
keytool -list -keystore /etc/ssl/truststore.jks -storepass changeit
openssl s_client -connect example.com:443 -showcerts
Fix now
Add missing intermediate cert to truststore and trigger reload via /actuator/ssl
Certificate expired+
Immediate action
Check expiration dates
Commands
openssl x509 -in /etc/ssl/cert.pem -noout -dates
keytool -printcert -sslserver localhost:8443
Fix now
Replace bundle files and set spring.ssl.bundle.reload-on-update=true
SSL handshake failure+
Immediate action
Verify bundle reference
Commands
grep server.ssl.bundle application.properties
curl -v https://localhost:8443 --cacert /etc/ssl/truststore.pem
Fix now
Correct bundle name or ensure bundle files exist at specified paths
FeatureLegacy SSL PropertiesSSL Bundles
ConfigurationScattered across propertiesCentralized in named bundles
ReusabilityPer-connector duplicationSingle bundle referenced by multiple connectors
Hot-reloadNot supportedSupported with reloadable bundles
Keystore typesJKS, PKCS12, PEMJKS, PKCS12, PEM (reloadable only PKCS12)
Actuator supportNoneGET/POST /actuator/ssl for inspection and reload
⚙ Quick Reference
4 commands from this guide
FileCommand / CodePurpose
application.ymlspring:What Are SSL Bundles?
WebClientConfig.java@ConfigurationUsing SSL Bundles with WebClient and RestTemplate
Before vs Afterserver.ssl.key-store=classpath:keystore.p12Migrating from Legacy SSL Properties
SslBundleTest.java@SpringBootTestTesting SSL Bundle Configuration

Key takeaways

1
SSL Bundles centralize TLS configuration and support hot-reload, making certificate management easier and more reliable.
2
Always test bundle loading with integration tests and monitor the Actuator SSL endpoint in production.
3
Use reloadable bundles with PKCS12 for zero-downtime certificate rotation, and avoid sharing files across bundles.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
How do SSL Bundles improve TLS configuration in Spring Boot 3.1+?
Q02SENIOR
How would you implement zero-downtime certificate rotation using SSL Bun...
Q03SENIOR
What are the limitations of SSL Bundles you've encountered in production...
Q01 of 03SENIOR

How do SSL Bundles improve TLS configuration in Spring Boot 3.1+?

ANSWER
SSL Bundles centralize keystore/truststore configuration into named bundles, reducing duplication and errors. They support hot-reload, multiple bundle types (JKS, PKCS12, PEM), and can be referenced by the embedded server, WebClient, RestTemplate, and messaging connectors.
FAQ · 4 QUESTIONS

Frequently Asked Questions

01
What's the difference between `jks` and `reloadable` bundle types?
02
Can I use SSL Bundles with older Spring Boot versions?
03
How do I trigger a certificate reload without restarting the app?
04
What happens if the bundle fails to load?
N
Naren Founder & Principal Engineer

20+ years shipping production Java in banking & fintech. Drawn from code that ran under real load.

Follow
Verified
production tested
July 15, 2026
last updated
2,398
articles · all by Naren
🔥

That's Spring Security. Mark it forged?

3 min read · try the examples if you haven't

Previous
Securing a Spring Boot API With API Key and Secret Authentication
16 / 31 · Spring Security
Next
Two-Factor Authentication (2FA) with Spring Security