Spring Boot SSL (HTTPS) examples

In this tutorial, we will show you how to enable SSL (HTTPS) support for a Spring Boot web application (mvc + thymeleaf).

Tested with

  • Maven 3
  • Java 8
  • Spring Boot 2.2.4.RELEASE
  • Spring Boot default embedded Tomcat 9
  • Self-signed certificate (PKCS12)

To enable SSL or HTTPS for Spring Boot web application, puts the certificate file .p12 or .jks in the resources folder, and declares the server.ssl.* values in the application.properties

application.properties

# SSL
server.port=8443
server.ssl.key-store=classpath:cert.p12
server.ssl.key-store-password=123456

# JKS or PKCS12
server.ssl.keyStoreType=PKCS12

# Spring Security
# security.require-ssl=true

Done, starts the Spring Boot, and access https://localhost:8443

PEM file
The .pem is a popular certificate format for Apache and Nginx, but not supported in Java, here is an example to convert .pem into a .p12 format with OpenSSL.

1. Self-signed Certificate

For this example, we will use the JDK’s keytool to generate a self-sign certificate in PKCS12 format. The below command will create a PKCS12 cert, name mkyong.p12, puts this file into the resources folder.

Terminal

$ keytool -genkeypair -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore mkyong.p12 -validity 365

Enter keystore password:  
Re-enter new password:
What is your first and last name?
  [Unknown]:  yong
What is the name of your organizational unit?
  [Unknown]:  mkyong
What is the name of your organization?
  [Unknown]:  mkyong
What is the name of your City or Locality?
  [Unknown]:         
What is the name of your State or Province?
  [Unknown]:  
What is the two-letter country code for this unit?
  [Unknown]:  
Is CN=yong, OU=mkyong, O=mkyong, L=Unknown, ST=Unknown, C=Unknown correct?
  [no]:  yes

Note
More keytool usages

2. Project Directory

2.1 A standard Maven project structure.

project directory

3. Maven

3.1 Standard Spring Boot dependencies.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mkyong</groupId>
    <artifactId>spring-boot-ssl</artifactId>
    <version>1.0</version>

    <name>spring-boot-ssl</name>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.4.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- debugging -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

    </dependencies>

    <build>

        <finalName>spring-boot-web</finalName>

        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

4. Spring Boot

4.1 @SpringBootApplication to start and also a controller to return a page.

StartApplication.java

package com.mkyong;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@SpringBootApplication
@Controller
public class StartApplication {

    @GetMapping("/")
    public String index(final Model model) {
        model.addAttribute("title", "Spring Boot + SSL (HTTPS)");
        model.addAttribute("msg", "Welcome to the SSL!");
        return "index";
    }

    public static void main(String[] args) {
        SpringApplication.run(StartApplication.class, args);
    }

}

4.2 A thymeleaf page.

index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"/>
    <link data-th-href="@{/css/main.css}" rel="stylesheet">
    <title>Spring Boot SSL Examples</title>
</head>
<body>

<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
    <a class="navbar-brand" href="#">Mkyong.com</div></a>
</nav>

<main role="main" class="container">
    <div class="starter-template">
        <h1 th:text="${title}">Default title.</h1>
        <p th:text="${msg}">Default text.</p>
    </div>
</main>

<script data-th-src="@{/js/main.js}"></script>
</body>

</html>

5. application.properties

application.properties

# SSL
server.port=8443
server.ssl.key-store=classpath:mkyong.p12
server.ssl.key-store-password=123456

# PKCS12 or JKS
server.ssl.keyStoreType=PKCS12

# Spring Security
# security.require-ssl=true

6. Run Spring Boot + SSL

Terminal

$ cd project
$ mvn clean package
$ java -jar target/spring-boot-web.jar

...
com.mkyong.StartApplication              : No active profile set, falling back to default profiles: default
o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8443 (https)
o.apache.catalina.core.StandardService   : Starting service [Tomcat]
org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.30]
o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 571 ms
o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page template: index
o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8443 (https) with context path ''
com.mkyong.StartApplication              : Started StartApplication in 1.297 seconds (JVM running for 1.65)

Access https://localhost:8443

output 1

output 2

Due to the self-sign certificate, the browser will show a warning stated the certificate is invalid, ignore it, and clicks "advanced…continue" to continue.

Note
To solve the browser warning issue, get a free cert from Let’s Encrypt, or buy a cert from the trusted CA like Comodo or GeoTrust. Read more about SSL Certificate Authorities.

7. FAQs

Redirect all traffic from port 8080 to 8443.

StartApplication.java

package com.mkyong;

import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class StartApplication {
    public static void main(String[] args) {
        SpringApplication.run(StartApplication.class, args);
    }

    // spring boot 2.x
    @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(redirectConnector());
        return tomcat;
    }

    private Connector redirectConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(8080);
        connector.setSecure(false);
        connector.setRedirectPort(8443);
        return connector;
    }

}

Download Source Code

$ git clone https://github.com/mkyong/spring-boot
$ cd spring-boot-ssl
$ mvn clean package
$ java -jar target/spring-boot-web.jar
access https://localhost:8443

References

author image

mkyong

Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities. Read all published posts by

Comments

avatar
newest oldest most voted
Pascal
Guest
Pascal

Great tutorial. I’m wondering if this configuration will work when the springboot app is hosted on AWS?