Let’s Encrypt SSL Certificates for Dockerized Spring Boot in 2020

Learn how to add HTTPS encryption to your Spring Boot application running inside a Docker container.

Since the arrival of free Let’s Encrypt certificates, there is really no excuse not to use HTTPS for encrypting your application traffic.

Obtaining and integrating a free HTTPS certificate is easy and only requires three simple steps. This article shows the integration for a CentOS 8 web server with a Dockerized Spring Boot application.

Registering a Certificate

On your web server, obtain certbot, the official registration tool from Let’s Encrypt:

git clone https://github.com/certbot/certbot 
cd certbot

Create a certificate using a standalone web server for the HTTP challenge (replace your domain name accordingly – also make sure your port 80 is currently free):

./certbot-auto certonly -a standalone -d example.com -d www.example.com

Change to the created directory and convert the obtained files to the PKCS12 format which is needed for Spring Boot:

cd /etc/letsencrypt/live/example.com
openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out keystore.p12 -name tomcat -CAfile chain.pem -caname root

Adding the Certificate to your Docker Image

Depending on how you build your Docker image, you need to somehow add the generated certificate file to your image. In my case, I simply add an “ADD” statement to the Dockerfile:

ADD keystore.p12 /etc/letsencrypt/live/www.example.com/keystore.p12

Make sure that you copy the generated p12 file to the same folder where the Dockerfile is located because the “ADD” command expects a relative path as a first argument.

Adapting your application.properties

Either directly append these lines to your application.properties or add the corresponding keys as environment variables as described in this article (the keys need to be transformed to underscore-separated capitalised letters – e.g., SERVER_SSL_KEYSTORE="..."):

server.ssl.keyStoreType: PKCS12
server.ssl.keyAlias: tomcat

Certificate Renewals

You need to renew your Let’s Encrypt certificate regularly. Use the certbot tool with the following parameters:

certbot-auto certonly -a standalone -d subdomain.example.org

and copy the resulting certificate to the same location used before. Then restart your Docker container and you are done – your certificate has been renewed.

Also make sure your port 80 is still free – if you have an application running on that port, stop it for a few seconds (you can restart it immediately after the invocation of certbot-auto) – otherwise the renewal process might fail.


You can verify whether the certificate works by running your application and targeting your browser to its URL with the https:// prefix – you should see the following HTTPS information:

Why using HTTP GET for Deletions is a Security Risk

Ignoring the semantics of HTTP methods such as GET and POST can have disastrous security repercussions. You might think that using GET methods for deleting entities is fine since you only need to pass a single identifier and do not want to set up its own HTML form for doing so. Please let me convince you of the opposite.

HTTP Semantics

Before we can go into detail why this distinction matters for web application security, we need to grasp the semantics of HTTP methods.

MDN lists HTTP GET as an HTTP method that needs to be safe and idempotent. If you want to conform to their interpretation of REST principles (and I believe this to be a very good idea), you need to fulfil those two properties in all your GET methods.

Continue reading

How to Install Java OpenJDK 14 on macOS Catalina

In this article, I will demonstrate how to install Java OpenJDK 14 on macOS Catalina in 2020.

Download and Install OpenJDK 14

Download the .tar.gz version of OpenJDK 14 from jdk.java.net/14/.

sudo mv openjdk-14.0.1_osx-x64_bin.tar.gz /Library/Java/JavaVirtualMachines/
cd /Library/Java/JavaVirtualMachines/
sudo tar -xzf openjdk-14.0.1_osx-x64_bin.tar.gz
sudo rm openjdk-14.0.1_osx-x64_bin.tar.gz

Next, execute the following command to find out where JDK 14 is located:

$ /usr/libexec/java_home -v14

and append the resulting path as an export into your .bash_profile:

echo -n "\nexport JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-14.0.1.jdk/Contents/Home" >> ~/.bash_profile

and make sure to apply the changes:

source ~/.bash_profile

Test Java

You should now be able to run java:

java -version

Depending on your security settings, the following warning needs to be accepted by clicking “Open”:

You should then see an output similar to the following:

openjdk version "14.0.1" 2020-04-14
OpenJDK Runtime Environment (build 14.0.1+7)
OpenJDK 64-Bit Server VM (build 14.0.1+7, mixed mode, sharing)

Congratulations! You have installed OpenJDK 14.

Using the Open Weather Map API with Python

In this post, I am showing you how to use the freely available Open Weather Map API to retrieve hourly weather forecasts 48 hours into the future for a given place using Python without external packages.

Continue reading if you need an easy and flexible way to obtain weather data in your python application and you want to avoid using third-party dependencies for the task. You will use the free tier of the Open Weather Map API. The resulting weather data includes:

  • temperature
  • sunrise and sunset time
  • “feels like” temperature
  • pressure
  • humidity
  • wind speed
  • cloudiness

All the above data points are returned hourly for the next 48 hours in JSON format for free.

We will use Python to query the API without using any dependencies except for the requests and json packages so you can easily adapt it to suit your particular needs. Let’s get started!

Continue reading

How to set a Flash Message in Spring Boot with Thymeleaf

Flash messages (one-time notifications) are commonly used to display the result of an operation to your users:

Spring Boot offers this exact functionality in the RedirectAttributes interface. It uses the FlashMap data structure to store the flash messages as key-value pairs. Thymeleaf automatically supports reading those attributes in the template files the same way it handles ordinary model attributes.

One handy feature of flash messages is that they survive redirects (in contrast to normal model attributes). Have a look at the following example:

public String somePostAction(Model model, RedirectAttributes redirAttrs) {
    if (!everythingOkay()) {
        redirAttrs.addFlashAttribute("error", "The error XYZ occurred.");
        return "redirect:/settings/";

    redirAttrs.addFlashAttribute("success", "Everything went just fine.");
    return "redirect:/settings/";

public String index(Model model) {

    return "settings/index";

The somePostAction endpoint either sets the success (informing the user, that everything went fine) or the error flash attribute (a specific error has occurred).

Notice that a redirect to the /settings/ endpoint follows in either case. Since the flash messages survive redirects, they are available in the template of the /settings/ endpoint as well.

There, they can be used like other attributes:

<div class="alert alert-primary" role="alert" th:text="${success}" th:if="${success}"></div>
<div class="alert alert-danger" role="alert" th:text="${error}" th:if="${error}"></div>

Obviously you need a more sophisticated error management system for larger applications, but the subdivision into a “success” and multiple “error” states is often sufficient for small prototypes.

Pitfalls when Integrating Spring Sessions with Spring Security

Spring Sessions allows you to persist user sessions into a database. Combined with Spring Security, it is easy to create a setup where each logged in user is represented by a row in a SPRING_SESSION table. Externalising sessions into a database is also a prerequisite for a zero-downtime deployment strategy where users can stay logged in while a new application version is deployed.

On paper, the integration of those two Spring components is very easy. Assuming you have a working Spring Security setup, just add this dependency:


and add this line to your application.properties:


and you should be good to go!

Value too long for column PRINCIPAL_NAME

In my case, the setup was unfortunately not working out of the box. After login, I noticed the following exception:

org.h2.jdbc.JdbcSQLDataException: Value too long for column """PRINCIPAL_NAME"" VARCHAR(100)": "STRINGDECODE('Customer{id=123, email=''email@example.org'', firstName=''Jane'', lastName=''Doe'', company='... (179)"; SQL statement:

As stated in the exception, the data format of one of the newly created database tables did not expect a PRINCIPAL_NAME to exceed 100 characters. The principal in Spring Security is your user object (e.g., a class named “User” or something similar that is used in the login process). Therefore, this error means that there is some problem when Spring Security tries to create the user session in the database.

Continue reading

Environment-Dependent Code Execution with Spring Boot and Docker

Different deployment environments (e.g., development, testing, staging and production) often require that different pieces of code are switched on and off. For example, you only want to send real emails in production and write to an email log in all other environments instead. Or your code to initialise the database should only run in the staging environment.

A simple but hard to maintain way for such conditional code executions is to define a globally available variable such as isProductionSystem and write code such as this:

if (isProductionSystem) {
} else {

This is hard to maintain because you end up with large if statements if you have multiple environments. Also, the only way you can adapt in your environment is to change the isProductionSystem variable, which means you either have all of the “production-only” features or none of them.

The @ConditionalOnProperty Annotation

Spring offers a much better way to handle conditional code execution. You can annotate the beans that should only execute depending on an environment flag with the ConditionalOnProperty annotation:

@ConditionalOnProperty(value = "emails.enabled")
public EmailJob emailJob() {
    return new EmailJob();

In the above example, the email job is only started when the property-value emails.enabled is set to true.

Profile-dependent execution

The code execution can also be dependent on the application profile:

public emailJob emailJob() {
    return new EmailJob();

As already mentioned, this removes some level of flexibility because you can no longer decide to activate or deactivate individual features at configuration time on the respective environment.

Overriding Configuration Flags in Docker

When using Docker, you can override the default values for the properties by using environment variables with the -e flag of the docker run command:

docker run -it -e SPRING_JPA_DATABASE_PLATFORM=org.hibernate.dialect.PostgreSQLDialect myimage:latest

Spring translates environment variables into the dot-syntax for property-names by substituting dots with underscores and capitalising everything. If you want to override the value of my.property, you need to set the environment variable MY_PROPERTY.

In the above example, you can control whether to actually send emails with the following command:

docker -it -e EMAILS_ENABLED=1 myapp:latest

Conditional Execution on Application Startup

There is another interesting use case for an overridable configuration switch: code that is executed on application startup. For example, a method that creates test instances in an empty database in the staging system but is skipped in production.

This is more verbose but is still readable. Simply extract the configuration value with the @Value annotation (with the default false) into a private variable and check it in a method annotated with the @EventListener annotation listening to the ApplicationReadyEvent:

public class PostStartService {

    private boolean initEmptyDb;

    public void createTestData() {
        if (!initEmptyDb) {

        // execute your code here

In the above code snippet, you can control whether the body of createTestData is executed via setting the following environment variable in Docker:

docker -it -e INIT_EMPTY_DB=1 myapp:latest


In this article, I presented several techniques to run code depending on the deployment environment. Let me know how what works best for you or if you have different ways of achieving the correct environment configuration.

A More Powerful macOS Alternative to Outlook Quick Parts – Boosting Email Productivity

Stop repeating yourself.

Emails and messages in general often consist of repeated content blocks that never change. Greetings and signatures are perfect examples: some people even try to eliminate such “noise” from messages (for example, the “nohello”-movement).

While it is unrealistic that such changes to the human interaction protocol will ever be universally accepted, there is something else a productivity-minded person can do in order to lose less time each day typing the same phrases over and over again.

Outlook Quick Parts

The idea is simple. Instead of typing a long phrase (e.g., your signature containing your name, phone number and email address), you create a building block with a certain name. Quick parts then expands this name into the full description:

Screenshot from https://www.youtube.com/watch?v=h_JVTjhwsy4

For example, you set your name to “byelong”, press F3 and let Outlook expand the name to a signature:

Best regards,
Bernhard Knasmüller

Quick parts can also contain formatting and images and are an easy way to manage reusable content in Outlook.

A More Powerful macOS Alternative

Continue reading

Measure Code Execution Time Accurately in Python

Measuring code execution times is hard. Learn how to eliminate systematic and random measurement errors and obtain more reliable results.

We often need to measure how long a specific part of code takes to execute. Unfortunately, simply measuring the system time before and after a function call is not very robust and susceptible to systematic and random measurement errors. This is especially true for measuring very short intervals (< 100 milliseconds).

Systematic and Random Errors

So what is wrong with the following way of measuring?

time_start = time.perf_counter()
time_end = time.perf_counter()
execution_time = time_end - time_start

First, there is a systematic error: by invoking time.perf_counter(), an unknown amount of time is added to the execution time of my_function(). How much time? This depends on the OS, the particular implementation and other uncontrollable factors.

Second, there is a random error: the execution time of the call to my_function() will vary to a certain degree.

We can combat the random error by just performing multiple measurements and taking the average of those. However, it is much more challenging to remove the systematic error.

Continue reading

Thymeleaf: Output Size of List

Question: In my Thymeleaf template, I want to output the size of a list of objects. For example, for the list

List<String> list = Arrays.asList("Go", "Python", "Scala");

the result should be 3. How is this possible using just Thymeleaf syntax?

You can use the following expression:

<span th:text="${#lists.size(myList)}">[Number of Elements]</span>

And just in case you want to check if the list is empty, there is also an easy method for that:

<span th:if="${#lists.isEmpty(myList)}">This list is empty</span>