Self-hosting
Sign-in and accounts
Choose how people sign in to your Oatmilk, who may make an account, and how to manage accounts.
A self-hosted Oatmilk keeps its accounts in your own database by default, with Better Auth. It can use Clerk, a hosted sign-in service, instead. Either way, people's roles and companies are kept in Oatmilk itself.
| Accounts kept here (Better Auth) | Clerk | |
|---|---|---|
| Where accounts live | Your database, in the better_auth schema | Clerk's service |
| Sign-in | Email and password, two-step codes from an authenticator app, backup codes | Everything Clerk offers, such as Google sign-in and passkeys |
| AI apps and the CLI sign in through | Your Oatmilk, at /api/auth | Clerk |
| Works with no internet | Yes | No |
| Choose it | Accounts kept here in setup, or init --auth better-auth | Clerk in setup with its two keys, or init --auth clerk |
Changing the choice rebuilds the image with bun run self-host up. Accounts don't move between the two.
Who can make an account
| Setting | Who | Default |
|---|---|---|
OATMILK_AUTH_SIGNUP=closed | Only people you add, and people with an invitation: to a team, as an outside accountant, or as a contractor | On a server |
OATMILK_AUTH_SIGNUP=open | Anyone who can open the site | On your own computer |
On a server, keep sign-up closed unless you mean to run an open service. Open sign-up asks each new person to confirm their email before they can sign in or create a company, so it needs email. Without email, open sign-up stops and asks the person to contact you.
Add people
The usual way is an invitation from Settings › Team in Oatmilk. With email on, the person gets a link; without it, copy the link and send it yourself. The person makes their account from the link and joins your company with the role you chose.
From the server's command line:
bun run self-host user add --email ada@example.com --first-name Ada --last-name Lovelace # asks for a password
bun run self-host user list
bun run self-host user reset-password --email ada@example.com # signs them out everywhereA person added this way can sign in, then create a company or accept an invitation. In scripts, pipe the password in: echo "$PASSWORD" | bun run self-host user add --email ….
Each person can create up to three companies.
What people manage themselves
In their profile, each person changes their name and password, turns on two-step sign-in, prints backup codes, and signs out devices they no longer use. Ask administrators to turn on two-step sign-in.
Sign-in for AI apps, the CLI and the API
With accounts kept here, your Oatmilk runs its own sign-in server for apps, at /api/auth:
- AI apps connected to
https://<your address>/api/mcpopen your Oatmilk's consent page, where the person approves them. - The CLI signs in with
oatmilk login --host https://<your address>, the same way. See Sign in and choose a company. - API keys from Developers › API keys work as on the hosted Oatmilk:
oat_test_…on an install for one computer,oat_live_…on a server.
Use Clerk instead
- Create an application in Clerk, and copy its publishable key and secret key.
- In Clerk, allow your Oatmilk's address as an origin, and turn on Organizations.
- Run setup and choose Clerk, or:
bun run self-host init --server --domain books.example.com --auth clerk # add --force to rewrite an existing self-host/.envThen add both keys to self-host/.env and start it:
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_…
CLERK_SECRET_KEY=sk_live_…bun run self-host upbun run self-host user only manages accounts kept here. With Clerk, manage people in Clerk's dashboard and invite them in Oatmilk.