Documentation

Running a server·Updated 13 Oct 2026

Configuration

Every setting in config.toml and every environment variable the Kribble server reads, with defaults

kribble-web and kribble-builder read one TOML file. Give both the same file. This page lists every setting, section by section.

The file

  • Path. KRIBBLE_CONFIG_PATH, or config.toml in the working directory if it is not set. The units written by install.sh use /opt/kribble/config.toml. In the Docker image it is /app/config.toml.

  • No environment overrides. Settings come from the file only. The environment variables at the end of this page control logging and a few helpers, not settings.

  • Changes take effect on restart of both services: sudo systemctl restart kribble-web kribble-builder, or docker compose restart kribble-web kribble-builder.

  • Secrets. The file holds database, storage, SMTP and API credentials. Keep it owned by the service user with mode 600 (install.sh sets this).

  • Defaults. A missing key, an empty string and 0 all mean "use the default". You can't set a number to 0 this way.

Kribble refuses to start with exit status 2 if the file is missing or isn't valid TOML, if [auth].registration has an unknown value, or if a publish target is incomplete. Both binaries exit with status 1 if [database].dsn is empty. An unusable storage, Redis or LDAP setting stops startup with an error in the log.

A minimal file

[server]
frontend_url = "https://kribble.example.com"

[security]
jwt_secret     = "<openssl rand -hex 32>"
refresh_secret = "<openssl rand -hex 32>"

[database]
dsn = "postgres://kribble:<db-password>@localhost:5432/kribble?sslmode=disable"

[meili]
host = "http://127.0.0.1:7700"
key  = "<meili-master-key>"

[storage]
backend = "disk"
dir     = "/opt/kribble/data"

[storage.s3]
public_bucket_url = "https://kribble.example.com/files-public"

config.toml.example in the release contains every section with comments.

[server]

Key

Default

What it does

mode

"prod"

"prod" or "dev". Dev mode drops the Secure flag from cookies (so plain HTTP works), logs at debug level in console format, also writes logs to ../logs, and serves the API docs at /api/v1/docs. Use "prod" on any real server.

port

"8080"

Port kribble-web listens on, on all interfaces. Keep it behind your proxy.

frontend_dir

"../client/dist"

Directory of the built web app. Only used by binaries built without the embedded web app; release binaries ignore it.

frontend_url

"http://localhost:5173"

The public address of the server, without a trailing slash. Used for links in emails (verification, password reset, invitations) and for the site addresses that the CLI and MCP report for the built-in target. Set it on every server.

trusted_proxies

""

Comma-separated IPs or CIDRs of the reverse proxies whose X-Forwarded-For is believed. Empty trusts proxies on this machine and on private networks (127.0.0.0/8, ::1, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7), which covers a proxy on the same host or in a Docker network. Set it when your proxy reaches Kribble from a public address (Cloudflare, a load balancer). Requests from anywhere else count as their own address, whatever headers they send, so they can't dodge rate limits.

log_request_body

false

Adds request bodies to the access log, capped in size. Sign-in, password and token endpoints are never logged. For debugging only.

log_response_body

false

The same for response bodies. Binary data, HTML, CSS, JS and PDFs are skipped.

[security]

Key

Default

What it does

jwt_secret

none

Signs the 15-minute access tokens, the private-site session cookie and the file-download cookie.

refresh_secret

none

Signs the 7-day refresh tokens.

Use two different random values of at least 32 characters (openssl rand -hex 32). Kribble doesn't check their length or that they were changed from CHANGE_ME, so check them yourself. Changing either one signs everyone out. Access tokens (kb_…) used by the CLI and CI are not affected, because they are random values stored as hashes in the database.

[database]

Key

Default

What it does

dsn

none, required

PostgreSQL connection string, for example postgres://kribble:<password>@localhost:5432/kribble?sslmode=disable. Use sslmode=require or verify-full for a database on another host.

auto_migrate

true

Creates and updates the tables when a binary starts. There is no separate migration command, so leave it on unless you apply schema changes some other way.

Each process opens up to 25 connections.

[meili]

Key

Default

What it does

host

""

Meilisearch URL, for example http://127.0.0.1:7700 (Docker: http://meilisearch:7700).

key

""

The Meilisearch master key, as passed to --master-key or MEILI_MASTER_KEY.

Kribble starts even if Meilisearch can't be reached, and sets up the search index in the background once it can (search: index setup failed; search may be degraded in the log until then). While Meilisearch is unreachable, notes still save, but full-text search fails and the notes changed meanwhile are missing from search until they are saved again or the index is rebuilt. See Troubleshooting.

[email]

Key

Default

What it does

provider

""

"resend", "smtp" or "none". When empty, Kribble picks resend if [email.resend].api_key is set, otherwise smtp if [email.smtp].host is set, otherwise none. An unknown value, or a provider without its settings, falls back to none and logs an error.

from

"noreply@kribble.app"

Sender address. Mail is sent as Kribble <from>. Use an address your mail provider lets you send from.

With no provider, emails are only written to the log, accounts are created without verification, and password reset and email invitations don't reach anyone. Authentication explains what changes.

[email.resend]

Key

Default

What it does

api_key

""

A Resend API key. The from domain must be verified in Resend.

[email.smtp]

Key

Default

What it does

host

""

SMTP server host name. Required for SMTP.

port

"587"

SMTP port, as a string.

username

""

Login for SMTP AUTH (PLAIN). Leave empty for a relay that needs no login.

password

""

Password for username.

encryption

from the port

"tls" (TLS from the start, usual on 465), "starttls" (usual on 587) or "none". When empty: port 465 → tls, 25 → none, anything else → starttls.

insecure_skip_verify

false

Accepts any certificate from the SMTP server. For testing only.

[pdfgen]

Key

Default

What it does

chrome_path

""

Path to the Chrome or Chromium binary used for PDF export. When empty, Kribble uses CHROME_BIN if set, otherwise looks for google-chrome, chrome, chromium and chromium-browser on PATH, the usual /usr/bin paths and the macOS application paths.

Only kribble-web exports PDFs.

[storage]

Key

Default

What it does

backend

"s3"

"disk" keeps files in a local directory. "s3" uses S3-compatible object storage and then requires [storage.s3].

dir

""

Disk backend only, required for it: the root directory. Kribble creates <dir>/private (uploads, private sites) and <dir>/public (public site assets). It must be writable by the service user (see Installing for the systemd sandbox) and shared by kribble-web and kribble-builder.

With the disk backend, every file is served through kribble-web. It works on one host only, unless the directory is a shared mount.

[storage.s3]

Key

Default

What it does

endpoint

""

S3 API endpoint, for example https://<account-id>.r2.cloudflarestorage.com or https://s3.us-east-1.amazonaws.com. Required for s3.

region

"auto"

"auto" suits Cloudflare R2. Use the real region (for example us-east-1) for AWS S3 and some MinIO setups.

access_key_id

""

Access key. Required for s3.

secret_access_key

""

Secret key. Required for s3.

bucket

""

The private bucket: all uploads and private sites. Required for s3.

public_bucket

""

The bucket for public sites' assets. It doesn't need public access, because kribble-web streams it at /files-public/.

public_bucket_url

""

The URL prefix written into public sites for their assets. Set it to https://<your server>/files-public. The disk backend uses it too. If it points elsewhere (the example file has http://localhost:8080/files-public), public sites load without images and icons.

presign_ttl_minutes

10

How long the presigned download links for large files stay valid.

proxy_threshold_bytes

15728640 (15 MiB)

Files up to this size are streamed through kribble-web. Larger ones are sent as a redirect to a presigned URL, so browsers must be able to reach endpoint.

rate_limit_ops_per_sec

1000

Per process: the most write, copy and delete requests sent to S3 per second for user actions.

bg_rate_limit_ops_per_sec

200

Per process: the limit for background work such as site builds, so uploads keep headroom.

The keys must be allowed to read, write, list and delete objects in both buckets.

[builder]

Key

Default

What it does

workers

2

How many sites kribble-builder builds at the same time.

port

"8081"

Port of the builder's health server (/healthz, /readyz).

[downloads]

Key

Default

What it does

dir

"downloads"

Directory with the CLI, editor extensions and desktop apps the server hands out, and their manifest.json. Relative to the working directory: /opt/kribble/downloads with install.sh, /app/downloads in Docker. A missing directory is not an error. The server then offers no downloads. See The CLI and desktop downloads.

[redis]

Key

Default

What it does

url

""

Redis URL, for example redis://localhost:6379/0 (Docker: redis://redis:6379/0). Empty means in-memory caches in each process, which is right for a single kribble-web. When set, Redis holds the caches for workspace versions, unread notification counts, published-site access and space access, so several kribble-web processes agree. If Redis can't be reached at startup, the binary exits.

[auth]

Key

Default

What it does

registration

"open"

"open": anyone can register at /login. "invite_only": registration needs an invitation to an organisation, and the sign-up form is hidden. LDAP logins still create accounts. Any other value stops startup.

[admin]

Key

Default

What it does

emails

[]

Accounts with these emails (case-insensitive) are made instance admins each time a binary starts. Promote-only: removing an email doesn't demote anyone. When the list is empty and there is no admin yet, the next account created becomes an admin.

Authentication covers instance admins in detail.

[[ldap]]

Zero or more LDAP or Active Directory sources. Repeat the block for each. Enabled sources are tried in the order they appear. Authentication explains the login flow and has examples.

Key

Default

What it does

name

""

Label for the source. Shown in the admin panel and stored on accounts it creates.

enabled

false

Only enabled sources are used. An enabled source without url or user_search_base stops startup.

url

""

ldaps://host:636 or ldap://host:389.

bind_dn

""

Service account that searches for users. Empty means an anonymous search.

bind_password

""

The service account's password. Never shown in the admin panel.

user_search_base

""

Base DN searched for users (whole subtree).

user_filter

"(|(uid=%s)(mail=%s))"

Search filter. Every %s is replaced with what the user typed, escaped. It must match exactly one entry.

attr_email

"mail"

Attribute holding the email. Required on the entry.

attr_username

"uid"

Attribute holding the username. Use "sAMAccountName" for Active Directory. Required on the entry.

attr_display_name

"displayName"

Attribute for the display name. Falls back to cn.

attr_first_name

""

Optional. With attr_surname, builds the display name from display_name_format.

attr_surname

""

Optional. See attr_first_name.

display_name_format

"{first} {surname}"

Template using {first} and {surname}. Use "{surname} {first}" for surname-first names. Only used when attr_first_name or attr_surname is set.

tls_skip_verify

false

Accepts any certificate on ldaps://. For testing only.

timeout_seconds

5

Connect and search timeout.

group_search_base

""

Base DN for the group lookup. Empty turns group sync off for this source.

group_member_attribute

"memberUid"

Group attribute listing members: memberUid for posixGroup, member for groupOfNames and Active Directory.

user_group_attribute

"uid"

The user's value that appears in the member attribute. "DN" uses the user's full DN.

group_membership_filter

""

Optional extra filter combined with the group search, for example "(|(cn=devs)(cn=admins))".

[[ldap.team_map]]

Repeat under an [[ldap]] block. Entries missing any of the three keys are ignored.

Key

Default

What it does

group_dn

none

DN of an LDAP group (compared case-insensitively).

org

none

Name of an existing organisation (its URL name, lowercase).

teams

none

Names of existing teams in that organisation, matched exactly.

[[publish_targets.local]], [[publish_targets.ssh]], [[publish_targets.cloudflare_pages]]

Destinations for published sites besides the built-in one. Names must be unique across all three lists. Publish targets explains how they behave.

[[publish_targets.local]]

Key

Default

What it does

name

none, required

Name shown in the publish dialog and stored on each site. Don't rename it once sites use it.

base_dir

none, required

Directory on the Kribble host. Each site goes into a subdirectory of it.

allowed_orgs

[]

Organisation names that may use the target, or ["*"] for all. Empty means nobody.

[[publish_targets.ssh]]

Key

Default

What it does

name

none, required

As above.

hostname

none, required

SSH server.

port

22

SSH port.

username

none, required

Remote user.

private_key_path

none, required

Private key file on the Kribble host.

passphrase

""

The key's passphrase, if it has one.

known_hosts_path

""

known_hosts file with the server's host key. Startup doesn't check it, but every publish fails without it.

remote_base_dir

""

Remote directory. Each site goes into a subdirectory of it.

allowed_orgs

[]

As above.

[[publish_targets.cloudflare_pages]]

Key

Default

What it does

name

none, required

As above.

account_id

none, required

Cloudflare account ID.

api_token

none, required

API token with Cloudflare Pages edit permission.

production_branch

"main"

Branch name for the project and its deployments, so every deployment is a production deployment.

project_prefix

"kribble"

Start of each project name: <prefix>-<name>-<slug>. Lowercased; other characters become -.

allowed_orgs

[]

As above.

api_base_url

"https://api.cloudflare.com/client/v4"

Cloudflare API address. Only change it for testing.

Environment variables

kribble-web and kribble-builder

Variable

Default

What it does

KRIBBLE_CONFIG_PATH

config.toml

Path of the config file.

LOG_LEVEL

info (debug in dev mode)

debug, info, warn or error.

LOG_FORMAT

json (console in dev mode)

Format of the log on standard output.

LOG_DIR

none (../logs in dev mode)

Also write the log as JSON to <LOG_DIR>/app.log, rotated. The directory must be writable, so use a path under /opt/kribble with the default units.

LOG_MAX_SIZE_MB

50

Rotate app.log at this size.

LOG_MAX_BACKUPS

10

Rotated files to keep.

LOG_MAX_AGE_DAYS

28

Delete rotated files older than this.

CHROME_BIN

none

Chromium path, used when [pdfgen].chrome_path is empty.

GIN_MODE

none

Set to release by the systemd units. It quiets the HTTP framework's startup messages.

Set them in a unit drop-in (sudo systemctl edit kribble-web):

[Service]
Environment=LOG_LEVEL=debug

Installers and Docker Compose

Variable

Used by

What it does

INSTALL_DIR

install.sh, install-www.sh

Install location. Default /opt/kribble and /opt/kribble-www.

KRIBBLE_WEB_BIN, KRIBBLE_BUILDER_BIN

install.sh

Paths of the binaries, if they aren't next to the script.

KRIBBLE_PORT, BUILDER_PORT

install.sh

The web and builder ports written into a new config.toml (an existing one keeps its ports).

KRIBBLE_WWW_PORT

install-www.sh

Port of kribble-www (default 8080).

POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB

docker-compose.yml

Create the database in the db container. They must match [database].dsn.

MEILI_KEY

docker-compose.yml

Meilisearch master key. Must match [meili].key.

KRIBBLE_PORT

docker-compose.yml

Host port for kribble-web (default 8080).

kribble-www reads KRIBBLE_WWW_ADDR and KRIBBLE_WWW_DOWNLOADS. See The CLI and desktop downloads.