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
# 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
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.
$ 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.
3. Maven
3.1 Standard Spring Boot dependencies.
<?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.
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.
<!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
# 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
$ 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
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.
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
Great tutorial. I’m wondering if this configuration will work when the springboot app is hosted on AWS?
I believe it should work given that you open the port 8443, you can also configure a reverse proxy with NGINX to forward requests from 443 to port 8443 and enforce https 🙂
Hi MKYong,
Great tuto,
I’m facing the below exception after configured SSL.
Caused by: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
Idea please?
OpenJDK11
Ubuntu 16
Regards,
Elgsylvain85
It seemed to me that the “OpenJDK” version did not correctly refer to the preinstalled Java certificates so my solution was to uninstall the “OpenJDK” version, download the Oracle version, unzip it then manually add all the references in the variables environments (JAVA_HOME …).
Unable to start embedded Tomcat server when i try to generate own p12 file
Thank you very much! Very usefull.
Regards from Brazil.
TY!!!
Thank you for this.
Hi MKYong, i would like to have the java source code to include .jks or .keystore in java code and send it to network as when i am adding .jks file to java/cacerts, i m getting No SSL client certificate present, ski pping SSL user authentication …at Network.
Thanks in Advance,
RK.
Hi MKYong Sir,
Great tutorial……..👍 👍👍👍👍👍👍👍👍👍👍👍👍👍
#Spring Boot version “2.1.0.RELEASE” Keys->
server.ssl.key-alias=mkyong
server.ssl.key-store-type=JKS
server.ssl.key-password=mkyong
server.ssl.key-store=classpath:nameOfJks.jks
#Spring Boot version “2.4.5” Keys->
server.ssl.key-alias=mkyong
server.ssl.keyStoreType=JKS
server.ssl.key-store-password=mkyong
server.ssl.key-store=classpath:nameOfJks.jks
Thank you for the updates us and also much appreciated
Great tutorial, thanks