Storing Semi-Structured Data in PostgreSQL

Traditionally, relational databases required all tables to have a fixed data schema, i.e. a set of attributes (such as a “user” table with attributes “firstName”, “lastName” and “email”). You could change the schema by adding and removing attributes, but the available attributes were always know at a given point in time.

For many use cases, this was acceptable. However, some applications have the need to store semi-structured data: entries where the attributes are not known ahead of time.

Since 2012, PostgreSQL allows to store semi-structured data inside tables in the JSON notation:

  "ID": "123",
  "Country": "Denmark",
  "Title": "How to store JSON in PostgreSQL"

This allows having different sets of attributes for different rows in your table while leaving your table schema constant.

Continue reading

Thymeleaf: Best Way to Display Active Navigation Item

This tutorial is about how to highlight the currently active page in your navigation with Thymeleaf and Spring Boot. Highlighting the active page is a known usability pattern and should help users to find their way around your web application.

Consider this example:

In the navigation above, the navigation item “Cronjob Monitoring” is highlighted.

The menu is generated with this Thymeleaf code:

<nav class="mdl-navigation">
    <a th:classappend="${#request.requestURI.startsWith(navItem.getLink()) ? 'mdl-navigation__link-active':''}" th:each="navItem: ${navigation}" th:id="${navItem.getIdentifier()}" class="mdl-navigation__link"
        th:href="@{${navItem.getLink()}}" th:text="${navItem.getName()}"></a>

By using th:each, a link is generated for each navigation entry.

th:classappend is used to conditionally append a CSS class to the <a> element. The class mdl-navigation__link-active in this case simply changes the background color, but you can opt for a less subtle approach.

request.requestURI.startsWith(navItem.getLink()) evaluates to true if the specific navigation item’s URL is currently opened in the user’s web browser. For example:

If is the result of navigation item’s getLink(), an active URL of will evaluate to true, but so will or any other subpath.

This method is very powerful because as long as you add all your controller actions with the same prefix, your navigation works out of the box without having to set any variables in the controller methods.

The accompanying CSS may look like this:

.mdl-navigation__link {
    color: #ffffff;
    font-weight: normal;


.mdl-navigation__link-active {
    font-weight: bold;
    background-color: #554477;

Interested in monitoring your background tasks? is currently launching as a public beta – it is a new web app which helps you monitoring your periodic background tasks (such as backups, data exports, accounting checks etc) and notifies you via email or slack when your services appear unavailable. Check it out – it is completely free.

Configuring Cron Jobs on a Synology NAS

Running regular background tasks on a network-attached storage (NAS) is an essential use case for backups, monitoring and more. With Synology DiskStations, there is an easy GUI-based approach to configure such tasks which still allows you to execute custom scripts.

First, navigate to Control PanelTask Scheduler:

Continue reading

Blue-Green Deployment with Apache and Docker

In a blue-green deployment strategy, there are always two instances of your application running in production. A reverse proxy is used to direct traffic to either the green or the blue version. You then deploy changes to your application by first updating the inactive version and then changing the load balancer config to redirect traffic to the updated instance.

In this video, I will show you how to set up a very simple version of such a blue-green deployment using just Apache, Docker and CentOS 8.

Git: Apply Changes from Branch as Unstaged Changes

Sometimes I want to quickly save some code changes that I am not ready to commit into a real branch. For example, I might be in the middle of a long refactoring and there is a complete mess that I do not want to show up in version control history:

Git has the “stash” command which removes all uncommitted changes and saves them to a local data structure where they can be retrieve later. However, this comes at the disadvantage that stashed changes only live in your local environment – they cannot be synced to tools like GitHub or GitLab.

This is fine for small changes, but when you really need to make sure to keep your changes, there is a more permanent solution that also does not pollute your version control history.

Save Changes

You save your changes by committing them to a “dirty”, temporary branch (let’s call it temp_refactor:

  • git checkout -b temp_refactor
  • git add .
  • git commit -m "some trash commit"
  • git push

Your changes are now reflected in the temp_refactor branch and can be pushed to a remote repository.

Load Changes

When you are ready to continue, change to the branch you actually want your changes to end up at and do the following:

  • git checkout feature/my_normal_feature_branch
  • git checkout temp_refactor -- .

All your changes are now back as unstaged changes and you can continue your work.

Monitor Website Response Times with Zabbix

Zabbix is a great open source tool to monitor operating system and application metrics. You can install it on your web server and out of the box, it is able to show you fancy graphs for things like:

  • Memory availability
  • CPU usage
  • Disk space usage
  • Network bandwidth
  • Free swap space

In this guide, I will show you how to create a dashboard widget that displays the response time for a specific URL over time. You can use this to monitor your production website and make sure there are no performance issues. In the end, it will look like this:

Continue reading

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 
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 -d

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

cd /etc/letsencrypt/live/
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/

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

Either directly append these lines to your 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

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

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.

One more thing:

I’m currently working on a cool side project named – it allows you to monitor the execution of regular background tasks such as backups and notifies you when they are not executed on time. Please check it out and use the invitation code BLOG20 to create an account for free:

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