Docs Start

Self-hosting

For a team, run the Turnkeel server with Postgres and sign-in. The server is configured by environment variables and by nothing else. At start it checks them, and refuses to start when one that is needed is missing or half set, naming every problem in one message. Telemetry is off.

Run it with Docker

The repository holds a Dockerfile, which builds Turnkeel as one image, and a docker compose file. The code opens at launch.

docker build --tag turnkeel .

The image runs as a user that is not root. It needs TURNKEEL_PUBLIC_URL and TURNKEEL_AUTH_SECRET, and DATABASE_URL for Postgres. Without TURNKEEL_PUBLIC_URL it stops and says so. Its health check is /healthz.

The compose file holds Postgres, an S3-compatible object store and a mail catcher, with Turnkeel as the service app behind the profile app:

docker compose --profile app up --build -d --wait

This starts Turnkeel with sign-in at http://localhost:4400, wired to the three. The passwords in the compose file are for development alone; a real install sets its own.

Environment variables

Variable What it sets When it is not set
TURNKEEL_PUBLIC_URL The address people and agents use, in mail links, sign-in callbacks and the changelog feed. Setting it turns sign-in on. Local mode, on the loopback address only
TURNKEEL_AUTH_SECRET Signs sessions and sign-in links. At least 32 characters, for example from openssl rand -base64 32. Needed whenever sign-in is on
TURNKEEL_HOST, TURNKEEL_PORT The bind address and the port 127.0.0.1 and 4400
DATABASE_URL Postgres, as postgres://… PGlite in the data folder
DATABASE_URL_DIRECT A direct Postgres connection for migrations and the event listener, when DATABASE_URL goes through a pooler DATABASE_URL
TURNKEEL_DATA_DIR The data folder ~/.turnkeel
TURNKEEL_SECRETS_KEY Encrypts connector secrets and the assistant's key before they are stored. At least 32 characters. No connector with secrets can be installed, and no assistant key can be saved
SMTP_URL, MAIL_FROM Outbound mail, as smtp://… or smtps://… Links are written to the server log
GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET Sign-in with GitHub Not offered
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET Sign-in with Google Not offered
TURNKEEL_OPEN_SIGNUP true lets anyone who reaches the server make an account and a workspace Accounts come by invitation only
TURNKEEL_TRUSTED_PROXIES Your reverse proxies' addresses or ranges, such as 10.0.0.0/8, so sign-in limits count the real client address No proxy is trusted
S3_ENDPOINT, S3_BUCKET, S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY Object storage Files are kept in a folder under the data folder
TURNKEEL_MAX_FILE_BYTES The largest upload 100 MB

Pairs are set together: each client id with its secret, SMTP_URL with MAIL_FROM, and the S3 settings all at once. Open Turnkeel at the address in TURNKEEL_PUBLIC_URL; sign-in refuses any other address of the machine.

Sign-in and mail

The sign-in page shows only the methods the server has set up.

Method Offered when
Sign-in link by mail Always, once sign-in is on. A link works once, for 10 minutes.
GitHub, Google Their client id and secret are set. Both are built, and not yet verified against the providers.
Passkey The person added one in their account, after a first sign-in another way

Mail is plain text, and Turnkeel sends two kinds only: sign-in links and invitations. It sends no notification mail. Without SMTP_URL, the recipient and the link are written to the server log, and the sign-in page says "Mail is not configured. The link is in the server log." An install that other people sign in to sets SMTP_URL.

The first Owner and invitations

On an install with no accounts, the first person to sign in becomes the Owner of a new workspace, which they name. Sign in before you give the address to anyone. After that, an account is made only by accepting an invitation, unless TURNKEEL_OPEN_SIGNUP=true.

An Owner or Admin invites by email from the workspace menu, Members. Only an Owner invites an Owner, and nobody invites to a role above their own. An invitation expires after 7 days, works once, can be revoked, and is accepted only by a signed-in person whose verified email is the one invited.

Role Can
Owner Everything, including deleting or handing over the workspace
Admin Everything but deleting or handing over the workspace and managing Owners: members, agents and tokens, connectors, the assistant's settings, money settings
Member Create and edit cards, builds, posts, releases and links; pass gates; sync; propose assets and decisions; triage the inbox
Reviewer Decide assets, decisions and posts; write asset notes and status lines
Viewer Read everything in their projects
Tester Only Testing, in the projects they are invited to

An invitation can give a role in one project only; a Tester invitation always names a project.

A local install stays local: what local mode holds cannot be moved to a server with sign-in, and a server with sign-in does not start on a local-mode database.

File storage

Uploads (screenshots, assets, evidence, doc images, receipts) go to S3-compatible storage when the S3_ variables are set, and otherwise to a folder under the data folder, served by the server.

  • S3_PUBLIC_ENDPOINT is the store's address as a browser reaches it, when that differs from S3_ENDPOINT. Signed upload and download addresses are made for it.
  • S3_FORCE_PATH_STYLE=true is for stores that need path-style addresses.
  • The bucket needs a CORS rule that lets a browser PUT to it from Turnkeel's address.

The assistant

The assistant is optional. It drafts and summarises text when a person presses a control, such as Catch me up on a card. It is off in every workspace until an Owner or Admin sets it up in the workspace menu, Assistant, and until then the server sends nothing to any model. It has no tools and changes nothing; a person saves what it suggests. No agent can start it. Each workspace has a daily cap of calls, 100 unless an Owner or Admin sets another. The demo workspace has no assistant.

It works with any server that speaks the OpenAI chat API, which includes a model server on the same machine, such as Ollama or LM Studio, with no key. It also has an adapter for one hosted API. On a server with sign-in, the settings page does not take a local address, so whoever runs the server sets an install-wide default in the environment:

TURNKEEL_ASSISTANT_PROVIDER=openai-compatible
TURNKEEL_ASSISTANT_BASE_URL=http://127.0.0.1:11434/v1
TURNKEEL_ASSISTANT_MODEL=<model>

TURNKEEL_ASSISTANT_API_KEY holds a key when the provider needs one, and TURNKEEL_ASSISTANT_DAILY_CAP limits the calls a day that all workspaces make with this default. A workspace uses the default only after an Owner or Admin chooses it and turns the assistant on there. With TURNKEEL_OPEN_SIGNUP=true the default is offered to no workspace.

The compose file has a model server, Ollama, behind the profile assistant. It pulls no model; you pull one by hand.

The source of this page will be on GitHub when the repository opens. Something wrong or unclear? Write to us.