by: Helge, published: Jan 25, 2025, in

Budibase: Self-Hosted Low-Code Platform With SSO & Automatic HTTPS

This article explains how to set up Budibase in a Docker container with automatic HTTPS via Caddy. This post is part of my series on home automation, networking & self-hosting that shows how to install, configure, and run a home server & network with dockerized or virtualized services.

About Budibase

What is Budibase?

Budibase is an open-source low-code platform that is available on a free plan suitable for self-hosting.

My Take on Budibase

I ended up not using Budibase for the following reasons:

  • Steep learning curve
  • Not targeted at end users but at developers
  • Very high memory usage

Preparation

I’m assuming that you’ve set up Docker as described in the previous articles in this series.

Enable Memory Overcommit

Redis requires larger buffers than are normally available in Linux (source). Add the following to /etc/sysctl.conf:

vm.overcommit_memory=1

Reboot and check the values with the following commands:

sysctl vm.overcommit_memory

Budibase Installation in a Docker Container

Dockerized Budibase Directory Structure

This is what the directory structure will look like when we’re done:

rpool/
 └── encrypted/
     └── docker/
         └── budibase/
             ├── data/
                 ├── couchdb/
                 ├── minio/
                 └── redis/
             ├── container-vars.env
             ├── container-vars-couchdb.env
             ├── container-vars-minio.env
             ├── container-vars-proxy.env
             ├── container-vars-redis.env
             └── docker-compose.yml

We’re placing the configuration on the encrypted ZFS dataset (rpool/encrypted).

Create the directories:

mkdir -p /rpool/encrypted/docker/budibase/data/couchdb
mkdir -p /rpool/encrypted/docker/budibase/data/minio
mkdir -p /rpool/encrypted/docker/budibase/data/redis

Budibase Docker Compose File

We’re following the official Docker Compose documentation while keeping the architecture notes about the product’s services in mind.

Create docker-compose.yml with the following content:

services:

  budibase-app:
    container_name: budibase-app
    hostname: budibase-app
    image: budibase.docker.scarf.sh/budibase/apps
    restart: unless-stopped
    networks:
      backend:
    expose:
      - 4002
    environment:
      PORT: 4002
    env_file:
      - container-vars-couchdb.env
      - container-vars-minio.env
      - container-vars-redis.env
      - container-vars.env
    depends_on:
      - budibase-worker
      - budibase-redis

  budibase-worker:
    container_name: budibase-worker
    hostname: budibase-worker
    image: budibase.docker.scarf.sh/budibase/worker
    restart: unless-stopped
    networks:
      backend:
    expose:
      - 4003
    environment:
      PORT: 4003
    env_file:
      - container-vars-couchdb.env
      - container-vars-minio.env
      - container-vars-redis.env
      - container-vars.env
    depends_on:
      - budibase-redis
      - budibase-minio

  budibase-minio:
    container_name: budibase-minio
    hostname: budibase-minio
    image: minio/minio
    restart: unless-stopped
    networks:
      backend:
    expose:
      - 4003
    env_file:
      - container-vars-minio.env
    volumes:
      - ./data/minio:/data
    command: server /data --console-address ":9001"
    healthcheck:
      test: "timeout 5s bash -c ':> /dev/tcp/127.0.0.1/9000' || exit 1"
      interval: 30s
      timeout: 20s
      retries: 3

  budibase-proxy:
    container_name: budibase-proxy
    hostname: budibase-proxy
    image: budibase/proxy
    restart: unless-stopped
    networks:
      backend:
      caddy_caddynet:
    expose:
      - 10000
    env_file:
      - container-vars-couchdb.env
      - container-vars-minio.env
      - container-vars-proxy.env
      - container-vars.env
    depends_on:
      - budibase-minio
      - budibase-worker
      - budibase-app
      - budibase-couchdb

  budibase-couchdb:
    container_name: budibase-couchdb
    hostname: budibase-couchdb
    image: budibase/couchdb
    restart: unless-stopped
    networks:
      backend:
    expose:
      - 5984
    env_file:
      - container-vars-couchdb.env
    volumes:
      - ./data/couchdb:/opt/couchdb/data

  budibase-redis:
    container_name: budibase-redis
    hostname: budibase-redis
    image: redis
    restart: unless-stopped
    networks:
      backend:
    expose:
      - 6379
    volumes:
      - ./data/redis:/data

networks:
  caddy_caddynet:
    external: true
  backend:
    driver: bridge

Budibase Environment Files

Generate Passwords and Secrets

Generate random alphanumeric strings and store them as container environment variables in container-vars.env:

cd /rpool/encrypted/docker/budibase/
echo "# Secrets" >> container-vars.env
echo "API_ENCRYPTION_KEY=$(tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1)" >> container-vars.env
echo "JWT_SECRET=$(tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1)" >> container-vars.env
echo "INTERNAL_API_KEY=$(tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1)" >> container-vars.env

Generate random alphanumeric strings and store them as container environment variables in container-vars-minio.env:

echo "# Secrets" >> container-vars-minio.env
echo "MINIO_ACCESS_KEY=budibase" >> container-vars-minio.env
echo "MINIO_SECRET_KEY=$(tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1)" >> container-vars-minio.env
echo "MINIO_ROOT_USER=\${MINIO_ACCESS_KEY}" >> container-vars-minio.env
echo "MINIO_ROOT_PASSWORD=\${MINIO_SECRET_KEY}" >> container-vars-minio.env

Generate random alphanumeric strings and store them as container environment variables in container-vars-couchdb.env:

echo "# Secrets" >> container-vars-couchdb.env
echo "COUCH_DB_USER=budibase" >> container-vars-couchdb.env
echo "COUCH_DB_USERNAME=\${COUCH_DB_USER}" >> container-vars-couchdb.env
echo "COUCHDB_USER=\${COUCH_DB_USER}" >> container-vars-couchdb.env
echo "COUCH_DB_PASSWORD=$(tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1)" >> container-vars-couchdb.env
echo "COUCHDB_PASSWORD=\${COUCH_DB_PASSWORD}" >> container-vars-couchdb.env

Additional Container Environment Variables

Edit container-vars.env so that it looks like the following:

# Secrets
API_ENCRYPTION_KEY=YOUR_PASSWORD_HERE
JWT_SECRET=YOUR_PASSWORD_HERE
INTERNAL_API_KEY=YOUR_PASSWORD_HERE

# Ports
CLUSTER_PORT=10000

# Budibase
SELF_HOSTED=1
APPS_URL=http://budibase-app:4002
WORKER_URL=http://budibase-worker:4003
BUDIBASE_ENVIRONMENT=PRODUCTION
LOG_LEVEL=info
ENABLE_ANALYTICS=false                 # Disable telemetry

# For the proxy
APPS_UPSTREAM_URL=${APPS_URL}
WORKER_UPSTREAM_URL=${WORKER_URL}

Edit container-vars-minio.env so that it looks like the following:

# Secrets
MINIO_ACCESS_KEY=budibase
MINIO_SECRET_KEY=YOUR_PASSWORD_HERE

# Minio
MINIO_BROWSER=off                    # disable web access
MINIO_URL=http://budibase-minio:9000

# For the proxy
MINIO_UPSTREAM_URL=${MINIO_URL}

Edit container-vars-couchdb.env so that it looks like the following:

# Secrets
COUCH_DB_USER=budibase
COUCH_DB_USERNAME=${COUCH_DB_USER}
COUCHDB_USER=${COUCH_DB_USER}
COUCH_DB_PASSWORD=YOUR_PASSWORD_HERE
COUCHDB_PASSWORD=${COUCH_DB_PASSWORD}

# CouchDB
COUCH_DB_URL=http://${COUCH_DB_USER}:${COUCH_DB_PASSWORD}@budibase-couchdb:5984
TARGETBUILD=docker-compose

# For the proxy
COUCHDB_UPSTREAM_URL=http://budibase-couchdb:5984

Create container-vars-redis.env so that it looks like the following:

REDIS_URL=budibase-redis:6379

Create container-vars-proxy.env so that it looks like the following:

RESOLVER=127.0.0.11

Start the Budibase Container

Navigate into the directory with docker-compose.yml and run:

docker compose up -d

Inspect the container logs for errors with the command docker compose logs --tail 100 --timestamps.

Budibase Let’s Encrypt Certificate via Caddy

Caddyfile

Add the following to Caddyfile (details):

budibase.{$MY_DOMAIN} {
	reverse_proxy budibase-proxy:10000 {
	}
	tls {
		dns cloudflare {env.CLOUDFLARE_API_TOKEN}
	}
}

DNS A Record

Add the following A record to your DNS domain:

budibase.home.yourdomain.com 192.168.0.4     # replace with your Docker host's IP address

Try to resolve the name on a machine in your network (e.g., nslookup budibase.home.yourdomain.com).

Reload Caddy’s Configuration

Instruct Caddy to reload its configuration by running:

docker exec -w /etc/caddy caddy caddy reload

You should now be able to access the Portelia web interface at https://budibase.home.yourdomain.com without getting a certificate warning from your browser.

Initial Budibase Configuration

Open https://budibase.home.yourdomain.com in your browser. You’re asked to create an admin user and your first app (select any name, e.g., Test).

Navigate to Settings > Organisation. Choose a name for your organization (e.g., Home) and set the Platform URL to the actual URL you use to access Budibase (e.g., https://budibase.home.yourdomain.com).

SSO via Authelia: Budibase OAuth Authentication

This section describes how to set up single sign-on to ownCloud via OpenID Connect authentication to Authelia. It is based on the Authelia Budibase integration guide.

Authelia: Configure OpenID Connect IdP

Client Secret

The shared secret between Budibase and Authelia is entered as plaintext in the Budibase UI but as a hash of the plaintext in Authelia’s configuration. Create a new secret by running the following command (docs):

docker run authelia/authelia:latest authelia crypto hash generate pbkdf2 --random --random.length 32 --random.charset alphanumeric

The command’s output looks as follows:

Random Password: v0e1zWJhvKQYud1lVUx4XhLibOwp0zyd
Digest: $pbkdf2-sha512$310000$vFbvgWgmhAIdZCbcLsrrXA$yRENW40rZpWLUP2ABQglEAhIHgpl7QAJ3eq8ZDEMmEHDL9Rro3eGwQ/4u05JsSLsEO5NIw.iAWVbo7EsiL8V1w

From the above output, the following two strings are required:

  • Plaintext secret: v0e1zWJhvKQYud1lVUx4XhLibOwp0zyd
  • Hashed secret: $pbkdf2-sha512$310000$vFbvgWgmhAIdZCbcLsrrXA$yRENW40rZpWLUP2ABQglEAhIHgpl7QAJ3eq8ZDEMmEHDL9Rro3eGwQ/4u05JsSLsEO5NIw.iAWVbo7EsiL8V1w

Note: do not use the above values. Create your own!

YAML Configuration File

Add the following to Authelia’s configuration file config/configuration.yml (details):

    clients:
      - client_id: budibase
        client_name: Budibase
        client_secret: '$pbkdf2-sha512$310000$vFbvgWgmhAIdZCbcLsrrXA$yRENW40rZpWLUP2ABQglEAhIHgpl7QAJ3eq8ZDEMmEHDL9Rro3eGwQ/4u05JsSLsEO5NIw.iAWVbo7EsiL8V1w'  # Replace with your own hashed secret
        redirect_uris:
          - budibase.home.yourdomain.com/api/global/auth/oidc/callback  # Replace with your proper URL
        scopes:
          - openid
          - profile
          - email
          - offline_access
        response_types:
          - code
        token_endpoint_auth_method: client_secret_post
        userinfo_signed_response_alg: none

Restart Authelia

We changed the container’s environment, which makes it necessary to recreate the container (stopping and starting is not enough). Navigate into the authelia directory and run:

docker compose down
docker compose up -d

Inspect the container logs for errors with the command docker compose logs --tail 30 --timestamps.

Budibase: Enable OAuth Authentication

In Budibase’s UI, navigate to Settings > Auth > OpenID Connect and set the following values:

  • Config URL: https://auth.home.yourdomain.com/.well-known/openid-configuration
  • Client ID: budibase
  • Client secret: [paste the plaintext secret you generated above]
  • Scopes: openid profile email offline_access
  • Activated: [enabled]

Save the settings.

Log In via OAuth

In a different browser, access https://budibase.home.yourdomain.com. Click Login with OIDC.

Automatic Provisioning

Note that OIDC users are auto-provisioned in Budibase (docs).

Previous Article Firmware-Update beim Steinel Multisensor True Presence KNX