Configuration
For platform operators. These tasks affect the whole deployment. Have server access or platform admin rights as the task requires. Start with the administrator manual.
OpenBot can run as many instances. An instance is one running OpenBot server process. All instances of one deployment use the same database. This page lists the few values that each instance reads when it starts. It also shows where every other setting lives.
The rule
Section titled “The rule”There are two kinds of settings:
- Instance settings belong to one instance. No other instance needs the same
value. They come from environment variables or from files in
/run/secrets. - Shared settings must be the same on every instance. They live in PostgreSQL. You change them through the API, and every instance uses the change at once.
There are two exceptions: OPENBOT_SECRET_KEYS and OPENBOT_CLUSTER_SECRET.
Every node needs the same values. They protect stored data and private node
messages, so each node reads them from its environment or secret files.
If a required value is missing or wrong, OpenBot does not start. It writes a configuration error to the log.
Instance settings
Section titled “Instance settings”This is the complete list of environment variables that the server reads.
| Variable | Required | Default | Meaning |
|---|---|---|---|
OPENBOT_HOST |
No | 127.0.0.1 |
The network address that the server listens on. |
OPENBOT_PORT |
No | 3000 |
The port that the server listens on. |
OPENBOT_CLUSTER_SECRET |
Yes | The shared private RPC secret. At least 32 characters. | |
OPENBOT_CLUSTER_HOST |
No | Bound address | The host that other nodes can reach on the server port. |
OPENBOT_DATABASE_URL |
Yes | A PostgreSQL connection URL. | |
OPENBOT_SECRET_KEYS |
Yes | The keys that encrypt secrets in the database. See below. | |
OPENBOT_OUTBOUND_ALLOW |
No | Private hosts and IP ranges that OpenBot may connect to. See below. |
The Docker image sets OPENBOT_HOST=0.0.0.0 and OPENBOT_PORT=3000, so the
server can take traffic from outside the container.
Private node calls use /internal/executions/rpc. Keep this path inside your
private network. Give every node the same random secret. Set a distinct
reachable host for each node when you use more than one node. The private RPC
client is separate from the App network guard.
Database
Section titled “Database”OPENBOT_DATABASE_URL looks like this:
postgres://openbot:secret@db.example.com:5432/openbot. The server, the
migration program, and the setup program all read it.
When the server starts, it checks that all tables exist. If they do not exist, it stops. Run the migration program first. See Deploy.
OpenBot serves plain HTTP only. It has no HTTPS of its own. To serve HTTPS, put a reverse proxy in front of it, such as Caddy or nginx. The proxy holds the certificate and sends the traffic to OpenBot. See Deploy.
Outbound connections
Section titled “Outbound connections”OpenBot connects to addresses that people give it, such as model provider endpoints, SSO issuers, custom Channels, and Apps. An attacker could use this to reach your own network. This attack is called server-side request forgery (SSRF).
So OpenBot connects only to public addresses. It blocks these targets:
- loopback addresses, such as
127.0.0.1,::1, andlocalhost, - private networks, such as
10.0.0.0/8,172.16.0.0/12,192.168.0.0/16, andfc00::/7, - link-local addresses and cloud metadata services, such as
169.254.169.254, - other special ranges, such as shared, test, multicast, and reserved ones.
OpenBot checks the real address of every new connection, after the DNS lookup. It also checks each redirect. A host name that points to a private address is blocked, too.
To open a private target on purpose, list it in OPENBOT_OUTBOUND_ALLOW.
Separate the entries with commas. Each entry is one of these:
| Entry | Example | What it opens |
|---|---|---|
| An IP address | 127.0.0.1, ::1 |
This one address. |
| An IP range | 10.20.0.0/16, fd00::/8 |
Every address in the range, for any host name. |
| A host name | localhost, ollama.internal |
This exact name, whatever address it points to. No other name. |
There are no wildcards and no ports. If an entry is wrong, OpenBot does not start.
# A model server on the same machine, and one internal network.OPENBOT_OUTBOUND_ALLOW=localhost,10.20.0.0/16When OpenBot blocks a connection, the error and the log name the host and
OPENBOT_OUTBOUND_ALLOW.
Secret keys
Section titled “Secret keys”OpenBot stores some secrets in the database. It encrypts them with the keys in
OPENBOT_SECRET_KEYS. These secrets are:
- the private data of App connections, such as App credentials, private settings, and sign-in state,
- the API keys of model providers,
- the client secrets of SSO connections,
- the sign-in secret of the platform, which signs the sign-in cookies,
- the client secret of the platform OpenID Connect provider.
OPENBOT_SECRET_KEYS is a list of keys with commas between them:
OPENBOT_SECRET_KEYS=k2:<64 hexadecimal characters>,k1:<64 hexadecimal characters>- Each entry is
<id>:<key>. - The key is exactly 64 hexadecimal characters (32 bytes).
- The ID is 1 to 32 characters. It can use lowercase letters, digits,
_and-. - The first key encrypts new secrets.
- Every key in the list can decrypt. OpenBot stores the key ID next to each secret, so it knows which key to use.
Make a key once:
echo "k1:$(openssl rand -hex 32)"Give every instance the same list. Keep the keys together with your database backups. If you lose them, OpenBot cannot read the secrets in the database.
Change the keys
Section titled “Change the keys”You can add a new key without losing the old secrets:
- Make a new key, for example
k2. - Put it first in the list, and keep the old key after it:
k2:<new>,k1:<old>. - Give the new list to every instance and start them again.
OpenBot now seals new secrets with k2. Secrets that k1 sealed still open.
Keep the old key in the list as long as the database holds secrets that it
sealed.
Secrets as files
Section titled “Secrets as files”When an environment variable is not set, OpenBot reads the file
/run/secrets/<NAME> instead. For example, it reads OPENBOT_SECRET_KEYS from
/run/secrets/OPENBOT_SECRET_KEYS. Docker and Compose put secrets in this
folder.
- An environment variable always comes first, even when the file exists.
- OpenBot removes spaces and line breaks at the start and end of the file.
- An empty file counts as not set. A missing file or folder also counts as not set.
This works for every variable on this page. It is most useful for secrets,
because environment variables show in docker inspect, and files do not.
First setup
Section titled “First setup”A new database has no shared settings. Before people can use OpenBot, you run the setup program once. It writes the first platform settings and the first platform admins.
Until then, the server starts, but every route except /health answers 503
with this body:
{ "_tag": "SetupRequired" }The log also tells you to run setup. See Platform for all flags and Deploy for the commands.
Where every other setting lives
Section titled “Where every other setting lives”Every other setting is a shared setting in the database. Two documents hold most of them:
- The platform settings at
/v1/platform/settings. Only platform admins can change them. See Platform. - The organization settings at
/v1/organization/settings. Each organization has its own. See Organization.
Older versions of OpenBot read more environment variables. OpenBot ignores them now. This table shows where each value went:
| Old variable | New place |
|---|---|
OPENBOT_PUBLIC_ORIGIN |
publicOrigin in the platform settings. Setup writes it with --public-origin. |
OPENBOT_OIDC_ISSUER |
identityProvider.issuer in the platform settings. Setup writes it with --oidc-issuer. |
OPENBOT_OIDC_CLIENT_ID |
identityProvider.clientId in the platform settings. Setup writes it with --oidc-client-id. |
OPENBOT_OIDC_CLIENT_SECRET |
identityProvider.clientSecret in the platform settings, encrypted. Setup writes it with --oidc-client-secret. |
BETTER_AUTH_SECRET |
The sign-in secret. Setup makes a random one and stores it encrypted. You never set it. |
OPENBOT_APP_ENCRYPTION_KEY |
OPENBOT_SECRET_KEYS. |
OPENBOT_OWNER_EMAILS |
Platform admins. Setup adds them with --admin-email. Change them with /v1/platform/admins. |
OPENBOT_ALLOWED_EMAIL_DOMAINS |
Verified domains of each organization, with joinByDomain in its settings. See SSO. |
OPENBOT_MODEL_ENDPOINT |
Model providers of an organization or of the platform. See Models. |
OPENBOT_MODEL_API_KEY |
Model providers, encrypted. |
OPENBOT_MODEL_ID |
A model that a model provider links, and the model of each Bot. |
OPENBOT_DEV_MODE |
The development entry point decides. See Development. |
Some values were options in code before. They are settings now, too:
| Old option | New place |
|---|---|
appRestrictions |
appRestrictions in the platform settings. |
appReadRules |
appReadRules in the organization settings. |
bots.helperModel |
rulesModel and botMemoryModel in the organization settings. |
bots.requestTimeout |
requestTimeoutMs in the organization settings. |
bots.memory |
botMemory in the organization settings. |
sessions.memory.defaults |
Nothing. The learned memory of each Session is gone. |
allowedEmailDomains, defaultRoles (API) |
Verified domains, and defaultRoles in the organization settings. |
How a change reaches every instance
Section titled “How a change reaches every instance”Each settings read uses the committed database row. A change works like this:
- The API writes the new settings in a transaction.
- PostgreSQL sends
NOTIFYonopenbot_settingswhen that transaction commits. - Subscribers use the notice to react to the change. The next read sees the row even if a notice is lost.
There is no settings cache that can keep old access rights. A failed read fails the action. App restrictions do not become empty when their store is down. A list reads one restriction snapshot, so all its entries use the same rules.
If the listener connection breaks, it logs the failure and listens again after one second. Reads still use the database while the listener reconnects.
A change to publicOrigin, to the platform identity provider, or to the sign-in
secret changes how sign-in works. Each instance reads these values when it uses
them, so the next request uses the new values. Sign-in gets a new setup for
them, and the old setup closes a few minutes after its last request. Nothing
starts again: requests and Turns that are running go on.
Production Compose
Section titled “Production Compose”The Compose file deploy/docker/compose.production.yaml reads these variables.
Only OPENBOT_DATABASE_URL, OPENBOT_SECRET_KEYS, and OPENBOT_OUTBOUND_ALLOW
reach OpenBot.
| Variable | Required | Default | Meaning |
|---|---|---|---|
POSTGRES_PASSWORD |
Yes | The password of the PostgreSQL user openbot. Use URL-safe characters. |
|
OPENBOT_DATABASE_URL |
Yes | The template fills it in from POSTGRES_PASSWORD. |
|
OPENBOT_SECRET_KEYS |
Yes | The secret keys. See Secret keys. | |
OPENBOT_OUTBOUND_ALLOW |
No | Private targets to open. See Outbound connections. | |
OPENBOT_RELEASE |
Yes | The image tag to run. | |
OPENBOT_PUBLISHED_PORT |
No | 8080 |
The port on 127.0.0.1 where your reverse proxy finds OpenBot. |
PROTOCOL_TEST_PUBLIC_ORIGIN |
Yes | The public HTTPS origin of the protocol test service. | |
PROTOCOL_TEST_ALLOWED_ORIGINS |
No | PROTOCOL_TEST_PUBLIC_ORIGIN |
Browser origins that the protocol test service accepts. |
The Compose file gives OPENBOT_DATABASE_URL and OPENBOT_SECRET_KEYS to
OpenBot as files in /run/secrets. It gives OPENBOT_OUTBOUND_ALLOW as an
environment variable. The openbot service has no other environment variables.
See Deploy. A full template is in
deploy/docker/production.env.example.
Development
Section titled “Development”devenv shell -- pnpm dev:setup makes the file .env.development from
.env.development.example. It fills in OPENBOT_SECRET_KEYS with one new
random key named dev.
| Variable | Default | Meaning |
|---|---|---|
OPENBOT_SECRET_KEYS |
dev:<random key>. dev:setup fills it in. |
|
OPENBOT_DEV_DATABASE_NAME |
openbot |
The name of the development database. |
devenv then sets these values for you. devenv picks each port: it starts at the
base port and takes the next free one. It gives the values with a port only to
the OpenBot process, not to devenv shell.
| Variable | Value |
|---|---|
OPENBOT_DEV_PUBLIC_ORIGIN |
http://localhost |
OPENBOT_HOST |
127.0.0.1 |
OPENBOT_PORT |
a free port, from 3000 |
OPENBOT_DATABASE_URL |
postgres://openbot_dev:openbot_dev@127.0.0.1:<port>/openbot, with a free port from 5433 |
OPENBOT_DEV_S3_ENDPOINT |
http://127.0.0.1:<port>, with a free port from 9000 |
OPENBOT_DEV_S3_BUCKET |
openbot |
The devenv proxy serves OpenBot at http://localhost, on port 80. Development
needs no HTTPS. Browsers and curl keep the secure sign-in cookie on localhost,
also without HTTPS.
The proxy listens on port 80. If another program uses it, give the proxy another
port in your shell, such as DEVENV_PROXY_LISTEN=127.0.0.1:8080. Then set
OPENBOT_DEV_PUBLIC_ORIGIN=http://localhost:8080 in .env.development. With a
port above 1023, the proxy needs no sudo.
Only the development entry point reads OPENBOT_DEV_PUBLIC_ORIGIN. It needs no
setup step. At each start, it writes the platform settings for this origin
itself. It makes the local account developer@localhost.test a platform admin,
and it turns on the local test sign-in. See
Authentication.
The production program never uses the local test account. There is no switch for it.
The development server blocks private targets, too. To use a model server on
your machine, such as Ollama, set OPENBOT_OUTBOUND_ALLOW=localhost in
.env.development. See Outbound connections.
devenv also starts RustFS, a small object storage, for
files. It runs in Docker. Its data lives in the Docker
volume openbot-dev-rustfs. At each start, the development entry point makes
the bucket openbot and writes the storage into the platform settings. RustFS
is at 127.0.0.1, a private address. So the development entry point opens that
one host for itself. You do not need to add it to OPENBOT_OUTBOUND_ALLOW.
To use another database, set OPENBOT_DATABASE_URL in .env.development. See
Contributing.
Example
Section titled “Example”This is a full production environment file for one instance:
OPENBOT_DATABASE_URL=postgres://openbot:secret@db.example.com:5432/openbotOPENBOT_SECRET_KEYS=k1:<output of openssl rand -hex 32>Every other setting comes from the setup program and the API.