First run, accounts and sign-ups

The first account is the administrator and needs the setup code, the guided setup, the three sign-up modes, who may start campaigns and spend paid AI, account invite codes, room codes as invitations, promoting admins, resetting passwords, Discord sign-in, upload budgets, the deletion grace period, and reports.

Server

The first account

The first account registered on a fresh server becomes its administrator, and creating it takes a one-time , so whoever reaches a fresh server first cannot claim it. While the server has no accounts it prints the code in its log at every start, with a link that fills it in; open the link on the server's computer, or type the code into the sign-up form's Setup code field. Under , docker compose logs | grep -A12 "no accounts yet" shows it. Set ODM_SETUP_CODE to choose the code yourself. The first account cannot be made with Discord: create it with a password and link Discord afterwards. Servers that already have an account are not affected.

The follows the first account: the storyteller, pictures and voice, players, and your own agent, one question at a time, each tested before you move on. It saves ordinary admin settings and can be run again from Admin, Guided setup; an administrator whose storyteller is not answering is offered it on the home screen.

To promote someone later, use the Users tab in the , or from a shell:

node scripts/make-admin.mjs <username>
# under Docker:
docker compose exec open-dungeon-master ./scripts/docker-entrypoint.sh node scripts/make-admin.mjs <username>

Sign-up modes

Admin, Server settings, Accounts, New account :

ModeWho can register
OpenAnyone who reaches the address. Fine on a LAN; close it once your party is in if the server faces the internet.
Invite-onlyPeople with an from you, or people arriving with a live from one of your campaigns, which vouches for them without a separate invite.
ClosedNobody. Existing accounts sign in as before.

The first account always bypasses the policy (it takes the instead). Registration and campaign joining share the login throttle, so guessing costs something, and wrong passwords are also counted per account: 20 misses in 15 minutes lock that name for a while, however many addresses the guesses come from.

Who may start campaigns, and who may spend

The same Accounts section decides who may start campaigns and (everyone, or administrators only; for everyone else New campaign and do not appear) and whose tables may use a paid AI backend, meaning a keyed backend on a public host. The Usage tab keeps a ledger of tokens spent per account and per campaign. Only an administrator can point a campaign at a backend address or key of its own.

Account invites

With set to invite-only, the Accounts section mints codes of the form ODM-XXXXXXXXXX (an alphabet with no lookalike characters), each with a note, a maximum number of uses (1 to 1000) and an optional expiry. Hand one to a new player; the sign-up form asks for it on an invite-only server. The apps show the same field.

Room codes as invitations

A campaign's admits a newcomer to the campaign and, on an server, to an account. The code must name a table that would actually seat them: it exists, has not ended, has a free seat, and is not mid-game with the door shut. Invite links show a preview of the table before sign-in.

Users

The Users tab lists every account: promote or demote administrators, delete an account (immediately), and reset a password, which shows a one-time temporary password the user must replace at their next sign-in. Reports filed at the table land in the Reports tab.

Each account has a daily upload budget, 500 MB and 200 files by default (UPLOAD_DAILY_BYTES, UPLOAD_DAILY_FILES), and uploads stop for everyone before the disk falls under 1 GB free (UPLOAD_MIN_FREE_BYTES). Administrators have no budget. Uploads, generated pictures and audio are served only to signed-in members, and are cached privately.

Discord sign-in

  1. Create an application at discord.com/developers.
  2. Under OAuth2, add the redirect URI <public-url>/api/auth/discord/callback, using the exact address players reach the server on (with the 's scheme and host if there is one).
  3. Paste the client ID and secret into Admin, Server settings, , or set DISCORD_CLIENT_ID and DISCORD_CLIENT_SECRET. Behind a proxy, set the too.

The sign-in button appears once both are set. A survives the Discord round trip, so an invite link still lands on the right table. An account that only ever signed in with Discord can set a password from Settings, which is what the desktop and Android apps need to sign in.

Account deletion

Any user can delete their own account from Account settings. The purge runs after the grace period you set under Accounts: 0 to 90 days, 14 by default. Zero erases immediately. Signing in before the date shows the user a Keep my account banner. Administrators can keep or erase a pending account from the Users tab. What the purge removes is listed in Accounts, friends and notifications.

Server name and public URL

The server name in Settings is what the apps show in their server list before anyone signs in. The is the address players use; it is what share links, QR codes and Discord redirects are built from when the server sits behind a proxy or a .

Checked against desktop and Android app 0.17.2 and server 0.26.2 on 2026-10-11. Something wrong or missing? Open an issue.

Download · v0.17.2
Server app · v0.26.2

Optional. Runs the table for a whole group on one machine that stays on. Everyone else just installs the app.

Free & open source · MIT licensed · served from GitHub releases