Book a Demo

Quick start: Cabinee Community Installer

Docker Compose service names, installer environment variables (UNIBPM_DOMAIN, and similar), and Keycloak realm/client IDs in the current Community installer retain historical unibpm-* names from the shared codebase. The product you install and operate is Cabinee.

Cabinee Community Installer

This guide describes a quick launch of Cabinee Community using an all-in-one Docker Compose distribution.

What is included

  • PostgreSQL (including a database for Keycloak)
  • Kafka
  • Keycloak
  • Cabinee backend (unibpm)
  • Cabinee frontend (unibpm-frontend)
  • Cabinee Engine (unibpm-engine)
  • Nginx gateway for domains/HTTPS (in Edge mode)
  • Certbot for Let’s Encrypt (only if TLS is enabled)

Prerequisites

Required

  • Docker Engine 20+
  • Docker Compose v2 (docker compose version)

For Edge + TLS (Let’s Encrypt)

  • A public VM IP
  • Open ports:
    • 80/tcp (required for Let’s Encrypt HTTP-01)
    • 443/tcp (for HTTPS)
  • DNS A records pointing to the VM IP (see below)

Two launch modes

  1. Local — access via localhost ports
  2. Edge — access via domains and (optionally) TLS through Let’s Encrypt

In Edge, Cabinee and Keycloak must have an external URL (otherwise OAuth2 redirects will not match). Camunda does not have to be exposed externally.


Quick start

git clone https://github.com/Reunico/unibpm-community-installer.git
cd unibpm-community-installer

cp .env.example .env
nano .env

chmod +x install.sh prepare.sh
./install.sh

Login credentials

login=admin
password=admin

Verification:

docker compose ps
docker compose logs -f unibpm
docker compose logs -f keycloak
docker compose logs -f unibpm-engine

Mode A — Local

Minimal .env settings

DEPLOY_MODE=local

FRONT_PUBLIC_PORT=8080
BACKEND_PUBLIC_PORT=8099
KEYCLOAK_PUBLIC_PORT=8082
CAMUNDA_PUBLIC_PORT=8081

URLs after installation

  • Cabinee UI: http://localhost:8080/
  • Keycloak: http://localhost:8082/keycloak/
  • Camunda (webapp): http://localhost:8081/

Mode B — Edge (VM/cloud with DNS)

1) Publication schemes: subdomain vs path

Edge supports two routing schemes, set with the EDGE_ROUTING_MODE variable.

Separate domains:

  • UI: https://<CABINEE_DOMAIN>/
  • Keycloak: https://<KEYCLOAK_DOMAIN><KEYCLOAK_PATH>/ (usually /keycloak)
  • Camunda (optional): https://<CAMUNDA_DOMAIN>/ (only if EXPOSE_CAMUNDA=true)
Option 2 — path (everything on one domain)

A single domain:

  • UI: https://<CABINEE_DOMAIN>/
  • Keycloak: https://<CABINEE_DOMAIN><KEYCLOAK_PATH>/
  • Camunda (optional): https://<CABINEE_DOMAIN><CAMUNDA_PATH>/

In both options, KEYCLOAK_PATH and CAMUNDA_PATH must start with /.


2) DNS (required)

Subdomain:

  • UNIBPM_DOMAIN (Cabinee UI domain; legacy installer variable name) → VM IP
  • KEYCLOAK_DOMAIN → VM IP
  • CAMUNDA_DOMAIN → VM IP (only if EXPOSE_CAMUNDA=true)

Path:

  • UNIBPM_DOMAIN (Cabinee public domain; legacy installer variable name) → VM IP

DNS check:

dig +short <CABINEE_DOMAIN>
dig +short <KEYCLOAK_DOMAIN>

3) Firewall / Security Group

Open:

  • 80/tcp (always, if Let’s Encrypt)
  • 443/tcp (if HTTPS)

Quick check (important for Let’s Encrypt):

curl -I http://<CABINEE_DOMAIN>/
curl -I http://<KEYCLOAK_DOMAIN>/

4) Example .env for Edge (subdomain + TLS)

DEPLOY_MODE=edge

# subdomain | path
EDGE_ROUTING_MODE=subdomain

UNIBPM_DOMAIN=cabinee.example.com
KEYCLOAK_DOMAIN=auth.example.com

# Expose Camunda via DNS? (optional)
EXPOSE_CAMUNDA=false
CAMUNDA_DOMAIN=camunda.example.com

# Public paths
KEYCLOAK_PATH=/keycloak
CAMUNDA_PATH=/camunda

# TLS (Let’s Encrypt HTTP-01)
ENABLE_TLS=true
LETSENCRYPT_EMAIL=admin@example.com

NGINX_HTTP_PORT=80
NGINX_HTTPS_PORT=443

# Extra origins for WebSocket/CORS (comma-separated)
EXTRA_ALLOWED_ORIGINS=

Launch:

./install.sh

URLs after installation:

  • Cabinee: https://<CABINEE_DOMAIN>/ (or http://... if ENABLE_TLS=false)
  • Keycloak:
    • subdomain: https://<KEYCLOAK_DOMAIN>/keycloak/
    • path: https://<CABINEE_DOMAIN>/keycloak/
  • Camunda:
    • if EXPOSE_CAMUNDA=true:
      • subdomain: https://<CAMUNDA_DOMAIN>/
      • path: https://<CABINEE_DOMAIN>/camunda/
    • if EXPOSE_CAMUNDA=false: it runs inside the docker network; for access use the CAMUNDA_PUBLIC_PORT port (if it is open) or an SSH tunnel/port forward

Security note: the backend is published on BACKEND_PUBLIC_PORT (8099) by default. In Edge, usually close this port on the firewall if it is not needed from the outside.


How the installer works (briefly)

The main command is install.sh. It can be run repeatedly: data in volumes is not deleted.

Sequence:

  1. Loads .env
  2. Computes and exports:
    • PUBLIC_SCHEME (http/https)
    • KEYCLOAK_EXTERNAL_URL (external Keycloak URL for the browser/redirects)
  3. Generates generated/nginx/default.conf from nginx/conf/*.tpl templates (depending on the mode)
  4. Starts infrastructure: postgres, kafka, keycloak
  5. Runs prepare.sh, which:
    • waits for Keycloak to become ready
    • obtains an admin token
    • extracts client secrets
    • generates:
      • generated/unibpm/application.yaml
      • generated/engine/application.yaml
    • (optionally) updates client redirect/web origins in Keycloak (depends on the mode and flags)
  6. Starts unibpm, unibpm-engine, unibpm-frontend
  7. In Edge, starts nginx
  8. In Edge + TLS, issues Let’s Encrypt certificates and restarts nginx

Important about Keycloak URLs: internal vs external

The stand uses several different Keycloak URLs at the same time, and they must not be mixed up:

  1. KEYCLOAK_BASE_URL (internal) — how containers reach Keycloak inside the docker network.

    • edge + subdomain: https://auth.example.com/keycloak
    • edge + path: https://cabinee.example.com/keycloak
    • local: http://keycloak:8080/keycloak
  2. KEYCLOAK_INTERNAL_URL (host) — how prepare.sh, which runs on the host, reaches Keycloak. Usually this is the published port: http://localhost:8082/keycloak.

  3. KEYCLOAK_EXTERNAL_URL (public/frontchannel) — how Keycloak is seen by the browser and where OAuth2 redirect_uri values must go. This value is computed by install.sh (from DEPLOY_MODE, EDGE_ROUTING_MODE, ENABLE_TLS, domains, and paths), for example:

    • edge + subdomain: https://auth.example.com/keycloak
    • edge + path: https://cabinee.example.com/keycloak
    • local: http://localhost:8082/keycloak

Why this matters:

  • if a container (unibpm/unibpm-engine) tries to reach http://localhost:8082/... → you get Connection refused;
  • if the browser is redirected to an internal URL (http://keycloak:8080/...) → OAuth2 breaks;
  • if the issuer (iss value in the token) does not match issuer-uri in the applications → the applications start rejecting JWTs.

Officially: in Keycloak you can (and often should) set the public URL (frontend) and the internal/backchannel separately, especially behind a reverse proxy.

What is used where in this distribution

Cabinee (unibpm) generated generated/unibpm/application.yaml uses:

  • spring.security.oauth2.resourceserver.jwt.issuer-uri → KEYCLOAK_EXTERNAL_URL (iss validation),
  • ...jwk-set-uri and ...token-uri → KEYCLOAK_BASE_URL (obtaining keys/tokens via the internal address).

Engine (unibpm-engine) generated generated/engine/application.yaml uses:

  • authorization-uri → KEYCLOAK_EXTERNAL_URL (browser login),
  • token-uri/jwk-set-uri → KEYCLOAK_BASE_URL (internal calls),
  • redirect-uri is built from CAMUNDA_BASE_URL.

This is a normal and common scheme: frontchannel goes through the public URL, backchannel uses the internal address.


WebSocket (/stomp), CORS, and UI embedding

Cabinee uses a WebSocket endpoint (by default /stomp). To avoid browser errors (including Safari) and issues when working through DNS/TLS/iframe, ws.allowed-origins must include:

  • http://localhost:3001 (dev)
  • http://localhost:<BACKEND_PUBLIC_PORT> (local backend)
  • https://<CABINEE_DOMAIN> (edge)
  • any additional portals/domains if the UI is embedded or proxied

The installer generates origins from .env; set additional values via EXTRA_ALLOWED_ORIGINS.


Common issues

1) Let’s Encrypt does not issue a certificate

Check:

  • the domains actually resolve to the VM IP (dig +short ...)
  • port 80 is open from the outside
  • nothing else is listening on port 80 (Apache/old nginx)

Check:

curl -I http://<CABINEE_DOMAIN>/
curl -I http://<KEYCLOAK_DOMAIN>/
docker compose logs -f nginx

2) Keycloak error: Invalid parameter: redirect_uri

This means that the Keycloak client has redirectUris that do not match the actual login URL (domain/path/scheme).

Where to fix:

  • Keycloak Admin Console → Realm unibpm (legacy realm name; the product is Cabinee)
  • Clients:
    • unibpm-front (Cabinee UI; legacy client id)
    • camunda-identity-service (Camunda SSO, if you expose Camunda externally)

What must be in Redirect URIs:

UI (unibpm-front)

  • Edge: https://<CABINEE_DOMAIN>/* (or http://.../* without TLS)
  • Local: http://localhost:<FRONT_PUBLIC_PORT>/*

Camunda (camunda-identity-service) — only if EXPOSE_CAMUNDA=true

  • Local:
    • http://localhost:<CAMUNDA_PUBLIC_PORT>/*
    • http://localhost:<CAMUNDA_PUBLIC_PORT>/login/oauth2/code/keycloak
  • Edge subdomain:
    • https://<CAMUNDA_DOMAIN>/*
    • https://<CAMUNDA_DOMAIN>/login/oauth2/code/keycloak
    • https://<CAMUNDA_DOMAIN><CAMUNDA_PATH>/login/oauth2/code/keycloak (if you use a path structure inside the application)
  • Edge path:
    • https://<CABINEE_DOMAIN><CAMUNDA_PATH>/*
    • https://<CABINEE_DOMAIN>/login/oauth2/code/keycloak
    • https://<CABINEE_DOMAIN><CAMUNDA_PATH>/login/oauth2/code/keycloak

If you changed the domain/path/scheme from http to https — update .env and run:

./install.sh

How to regenerate configs correctly (and why prepare.sh cannot be run “as is”)

prepare.sh expects the KEYCLOAK_EXTERNAL_URL variable to already be computed (this is done by install.sh).

Correct order after changing .env:

  1. If you changed domains/paths/mode/HTTPS → run the full scenario:
./install.sh
  1. If you changed only application parameters (for example, CORS/WS origins) and did not touch domains/paths/mode:
./install.sh
# or (alternative) export KEYCLOAK_EXTERNAL_URL manually and run prepare.sh,
# but this is for experienced users.

Recommendation for a stable issuer behind a reverse proxy

To make Keycloak always issue tokens with the expected iss (and not depend on who called it and at which address), in edge mode it is recommended to set the Keycloak hostname/URL (for example, via KC_HOSTNAME/hostname settings). This is especially important with EDGE_ROUTING_MODE=path and when publishing through nginx.


Update and restart

Restart everything:

docker compose restart

Recreate configs after editing .env:

./prepare.sh
docker compose restart unibpm unibpm-engine

If you changed domains/paths/edge settings, it is more convenient to run the full scenario:

./install.sh

Stop/remove

Stop:

docker compose down

Stop and remove the Postgres volume (⚠️ this deletes data):

docker compose down -v