letsencrypt
SSL certificate
Spring Boot
application security
HTTPS setup

How can I set up a letsencrypt SSL certificate and use it in a Spring Boot application?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

To use a Let's Encrypt certificate in a Spring Boot application, you need two separate pieces to work together: certificate issuance and TLS configuration. The certificate is usually obtained with Certbot, then converted into a Java-friendly keystore so Spring Boot can serve HTTPS directly.

Issue the Certificate with Certbot

Let's Encrypt validates that you control the domain before issuing a certificate. The easiest flow is HTTP validation on port 80, so the server must be reachable from the public internet and the DNS record for your domain must already point to the machine.

On a Linux server, install Certbot and request the certificate:

bash
sudo certbot certonly --standalone -d api.example.com

After success, Certbot writes the certificate files under:

text
/etc/letsencrypt/live/api.example.com/

The important files are:

  • 'fullchain.pem for the server certificate plus intermediate chain'
  • 'privkey.pem for the private key'

Spring Boot does not normally read those PEM files directly in older setups, so a common approach is to convert them into a PKCS#12 keystore.

Convert PEM Files into a PKCS#12 Keystore

Java SSL configuration is most straightforward when you provide a .p12 file. openssl can combine the certificate and key into one keystore:

bash
1sudo openssl pkcs12 -export \
2  -in /etc/letsencrypt/live/api.example.com/fullchain.pem \
3  -inkey /etc/letsencrypt/live/api.example.com/privkey.pem \
4  -out /opt/app/keystore.p12 \
5  -name springboot \
6  -passout pass:changeit

Choose a stronger password than changeit in real deployments. The application process must also have permission to read the generated keystore file.

If you prefer not to place private material under the app directory, keep it in a restricted location and point Spring Boot at that path instead.

Configure Spring Boot for HTTPS

Once the keystore exists, enable SSL in application.yml:

yaml
1server:
2  port: 8443
3  ssl:
4    enabled: true
5    key-store: file:/opt/app/keystore.p12
6    key-store-password: changeit
7    key-store-type: PKCS12
8    key-alias: springboot

If you start the application now, it will listen on 8443 and serve HTTPS using the certificate from Let's Encrypt.

For a quick redirect from HTTP to HTTPS inside the app, you can add a second connector in code:

java
1import org.apache.catalina.connector.Connector;
2import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
3import org.springframework.boot.web.server.WebServerFactoryCustomizer;
4import org.springframework.context.annotation.Bean;
5import org.springframework.context.annotation.Configuration;
6
7@Configuration
8public class HttpRedirectConfig {
9    @Bean
10    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> servletContainer() {
11        return factory -> factory.addAdditionalTomcatConnectors(httpConnector());
12    }
13
14    private Connector httpConnector() {
15        Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
16        connector.setScheme("http");
17        connector.setPort(8080);
18        connector.setSecure(false);
19        connector.setRedirectPort(8443);
20        return connector;
21    }
22}

That lets clients hit 8080 and get redirected to the secure port.

Handle Renewal

Let's Encrypt certificates expire frequently, so renewal must be automatic. Certbot already knows how to renew, but your app also needs an updated keystore after renewal.

One practical solution is a deploy hook that rebuilds the .p12 file and restarts the service:

bash
1#!/usr/bin/env bash
2set -e
3
4DOMAIN="api.example.com"
5openssl pkcs12 -export \
6  -in /etc/letsencrypt/live/$DOMAIN/fullchain.pem \
7  -inkey /etc/letsencrypt/live/$DOMAIN/privkey.pem \
8  -out /opt/app/keystore.p12 \
9  -name springboot \
10  -passout pass:changeit
11
12systemctl restart my-spring-app

Then call it from Certbot:

bash
sudo certbot renew --deploy-hook /opt/app/rebuild-keystore.sh

Without this step, the renewed certificate exists on disk but Spring Boot keeps serving the old keystore.

Direct TLS vs Reverse Proxy

Serving HTTPS directly from Spring Boot works, but many production systems terminate TLS at Nginx, Apache, or a cloud load balancer. That design often simplifies renewal, HTTP to HTTPS redirects, compression, static asset caching, and certificate rotation.

If you only need secure transport quickly and run a single service, direct SSL in Spring Boot is acceptable. If you run multiple services or expect traffic growth, a reverse proxy is usually easier to operate.

Common Pitfalls

  • Requesting a certificate before DNS points to the server. Let's Encrypt cannot validate a domain that does not resolve correctly.
  • Forgetting that Spring Boot needs a keystore workflow, not just raw PEM files in older configurations.
  • Renewing the Let's Encrypt certificate without rebuilding the .p12 file. The app continues serving the stale certificate.
  • Locking down file permissions too loosely. privkey.pem and the generated keystore should be readable only by the correct service account.
  • Using port 443 in production without confirming firewall and system service configuration. The app may be correct while the network still blocks HTTPS.

Summary

  • Use Certbot to issue a Let's Encrypt certificate for your domain.
  • Convert fullchain.pem and privkey.pem into a PKCS#12 keystore for Spring Boot.
  • Enable server.ssl in Spring Boot and point it at the keystore.
  • Automate renewal by rebuilding the keystore and restarting the service.
  • Consider a reverse proxy if you want easier certificate management at scale.

Course illustration
Course illustration

All Rights Reserved.