Extending Coolify Templates with dockerfile_inline: A Keycloak Theme Example

Extending Coolify Templates with dockerfile_inline: A Keycloak Theme Example
Photo by Zoshua Colah / Unsplash

When running self-hosted applications through Coolify, you'll often encounter situations where the default templates need customization. Whether it's adding a custom theme, installing plugins, or bundling additional dependencies, the dockerfile_inline feature in Docker Compose provides an elegant solution without maintaining separate Dockerfile repositories.

In this guide, we'll walk through a practical example: packaging the beautiful Keywind theme for Keycloak as a JAR file and integrating it into a Coolify deployment.


Chapter 1: Building the Keywind Theme JAR

The Keywind theme is a modern, Tailwind CSS-based theme for Keycloak. To use it as a provider JAR (the recommended approach for Keycloak 17+), we need to package it correctly.

Prerequisites

  • Node.js (v18 or later)
  • pnpm (or npm/yarn)
  • Basic command line knowledge

Step 1: Clone and Build the Theme

First, clone the original Keywind repository and install dependencies:

git clone https://github.com/lukin/keywind.git
cd keywind
pnpm install

Build the theme files:

pnpm build

This generates the compiled theme files in the theme/keywind directory.

Step 2: Create the JAR Structure

Keycloak expects theme JARs to follow a specific structure. Create a new directory for packaging:

mkdir -p keycloak-theme-jar/META-INF/keycloak-themes
mkdir -p keycloak-theme-jar/theme/keywind

Step 3: Copy Theme Files

Copy the built theme into the JAR structure:

cp -r theme/keywind/* keycloak-theme-jar/theme/keywind/

Step 4: Create the Theme Descriptor

Keycloak needs a keycloak-themes.json file to recognize the theme. Create it at keycloak-theme-jar/META-INF/keycloak-themes/keycloak-themes.json:

{
  "themes": [
    {
      "name": "keywind",
      "types": ["login"]
    }
  ]
}

This tells Keycloak that our JAR contains a theme named "keywind" that provides a "login" theme type.

Step 5: Package as JAR

Navigate to the packaging directory and create the JAR:

cd keycloak-theme-jar
jar cvf keywind-theme.jar .

Your final directory structure should look like this:

keycloak-theme-jar/
├── META-INF/
│   └── keycloak-themes/
│       └── keycloak-themes.json
├── theme/
│   └── keywind/
│       └── login/
│           ├── resources/
│           │   ├── css/
│           │   └── ...
│           ├── theme.properties
│           └── ...
└── keywind-theme.jar

Step 6: Host the JAR

Upload your keywind-theme.jar to a publicly accessible location. In this example, we're using GitHub:

  1. Create a new repository (e.g., Keycloak-theme)
  2. Upload the JAR file to the repository
  3. Note the raw file URL: https://github.com/YOUR_USERNAME/Keycloak-theme/raw/main/keywind-theme.jar

The complete example is available at github.com/mik9016/Keycloak-theme.


Chapter 2: The Default Coolify Keycloak Template

Coolify provides a ready-to-use Keycloak template. Here's what the default Docker Compose looks like:

services:
  keycloak:
    image: 'quay.io/keycloak/keycloak:26.1'
    command:
      - start
    environment:
      - SERVICE_URL_KEYCLOAK_8080
      - 'TZ=${TIMEZONE:-UTC}'
      - 'KC_BOOTSTRAP_ADMIN_USERNAME=${SERVICE_USER_ADMIN}'
      - 'KC_BOOTSTRAP_ADMIN_PASSWORD=${SERVICE_PASSWORD_ADMIN}'
      - 'KC_HOSTNAME=${SERVICE_URL_KEYCLOAK}'
      - 'KC_HTTP_ENABLED=${KC_HTTP_ENABLED:-true}'
      - 'KC_HEALTH_ENABLED=${KC_HEALTH_ENABLED:-true}'
      - 'KC_PROXY_HEADERS=${KC_PROXY_HEADERS:-xforwarded}'
    volumes:
      - 'keycloak-data:/opt/keycloak/data'
      - './themes/keywind:/opt/keycloak/themes/keywind'
    healthcheck:
      test:
        - CMD-SHELL
        - "exec 3<>/dev/tcp/127.0.0.1/9000; echo -e 'GET /health/ready HTTP/1.1\r\nHost: localhost:9000\r\nConnection: close\r\n\r\n' >&3;cat <&3 | grep -q '\"status\": \"UP\"' && exit 0 || exit 1"
      interval: 5s
      timeout: 20s
      retries: 10

volumes:
  keycloak-data:

This template works great for basic deployments, but has a limitation: the theme volume mount (./themes/keywind) requires the theme files to exist on the host filesystem. In Coolify's managed environment, this isn't practical.


Chapter 3: The Enhanced Template with dockerfile_inline

Here's the modified Docker Compose that automatically downloads and installs our theme JAR:

services:
  keycloak:
    build:
      context: .
      dockerfile_inline: |
        FROM quay.io/keycloak/keycloak:26.1
        ADD --chmod=644 https://github.com/mik9016/Keycloak-theme/raw/main/keywind-theme.jar /opt/keycloak/providers/keywind-theme.jar
        RUN /opt/keycloak/bin/kc.sh build
    command:
      - start
    environment:
      - SERVICE_URL_KEYCLOAK_8080
      - 'TZ=${TIMEZONE:-UTC}'
      - 'KC_BOOTSTRAP_ADMIN_USERNAME=${SERVICE_USER_ADMIN}'
      - 'KC_BOOTSTRAP_ADMIN_PASSWORD=${SERVICE_PASSWORD_ADMIN}'
      - 'KC_HOSTNAME=${SERVICE_URL_KEYCLOAK}'
      - 'KC_HTTP_ENABLED=${KC_HTTP_ENABLED:-true}'
      - 'KC_HEALTH_ENABLED=${KC_HEALTH_ENABLED:-true}'
      - 'KC_PROXY_HEADERS=${KC_PROXY_HEADERS:-xforwarded}'
    volumes:
      - 'keycloak-data:/opt/keycloak/data'
    healthcheck:
      test:
        - CMD-SHELL
        - "exec 3<>/dev/tcp/127.0.0.1/9000; echo -e 'GET /health/ready HTTP/1.1\r\nHost: localhost:9000\r\nConnection: close\r\n\r\n' >&3;cat <&3 | grep -q '\"status\": \"UP\"' && exit 0 || exit 1"
      interval: 5s
      timeout: 20s
      retries: 10

volumes:
  keycloak-data:

Chapter 4: Understanding dockerfile_inline

The dockerfile_inline feature allows you to embed Dockerfile instructions directly within your Docker Compose file. This eliminates the need for a separate Dockerfile while still enabling image customization.

The Syntax

build:
  context: .
  dockerfile_inline: |
    FROM base-image:tag
    # Your Dockerfile instructions here

The | character in YAML indicates a multi-line string, preserving line breaks exactly as written.

Breaking Down Our Dockerfile Instructions

Let's examine each line:

Line 1: FROM quay.io/keycloak/keycloak:26.1

This sets our base image to the official Keycloak 26.1 image. We're extending it rather than replacing it.

Line 2: ADD --chmod=644 https://github.com/.../keywind-theme.jar /opt/keycloak/providers/keywind-theme.jar

The ADD instruction downloads a file from a URL directly into the container. Key points:

  • --chmod=644 sets read permissions for all users (required for Keycloak to load the provider)
  • The URL points to the raw JAR file on GitHub
  • /opt/keycloak/providers/ is Keycloak's provider directory where it automatically discovers JAR extensions

Line 3: RUN /opt/keycloak/bin/kc.sh build

This crucial step runs Keycloak's build command, which:

  • Discovers and registers all providers in the /opt/keycloak/providers/ directory
  • Optimizes the Keycloak installation for production
  • Pre-compiles theme resources for better performance

Key Structural Changes

Original Template Enhanced Template
image: 'quay.io/keycloak/keycloak:26.1' build: with dockerfile_inline
Theme mounted via volume Theme embedded in image
Theme files required on host Self-contained, portable

Why This Approach?

  1. Portability: The entire configuration is self-contained in one file
  2. No External Dependencies: No need to manage theme files on the host
  3. Version Control: Your customizations are documented in the compose file
  4. Coolify Compatibility: Works seamlessly with Coolify's deployment model

Chapter 5: Activating the Theme in Keycloak

After deployment, activate the Keywind theme:

  1. Log into the Keycloak Admin Console
  2. Select your realm (or create a new one)
  3. Navigate to Realm SettingsThemes
  4. Under Login theme, select keywind
  5. Click Save

Your login pages will now use the modern Keywind design.

And here we go we can use our theme for login:


Conclusion

The dockerfile_inline feature bridges the gap between using pre-built templates and needing custom modifications. It's particularly powerful for self-hosted platforms like Coolify where you want the simplicity of templates with the flexibility of custom builds.

This pattern extends beyond themes. You can use the same approach to:

  • Add custom Keycloak providers (authentication, federation, etc.)
  • Install additional plugins for other applications
  • Bundle configuration files or certificates
  • Apply security patches to base images

The key insight is that you don't always need a separate repository or complex CI/CD pipeline. Sometimes, a few inline Dockerfile instructions are all you need.


Have questions or want to share your own dockerfile_inline use cases? Drop a comment below!