Accounts
Invite-only registration on a Noite install — bootstrap admin, single-use codes, and admin panels.
Registration is invite-only once the instance is bootstrapped. The first account to sign up needs no code and is promoted to the admin role, so god-mode works without NOITE_ADMIN_EMAIL; every later registration must present a single-use invitation code. Each new account receives INVITES_PER_USER = 2 codes of its own, so an invitee can pass one on without admin rights.
Codes are 12 characters in four-char groups (ABCD-EFGH-JKLM) drawn from an unambiguous alphabet, and a code that is used, revoked or unknown is refused with a specific message before any account is created. Redemption is a single atomic claim (UPDATE ... WHERE usedBy IS NULL), so one code admits exactly one account even under concurrent signups.
- Members read their unused codes in the “Invitations” card on
/account. - Admins mint 1–50 more and revoke unused ones from the Invitations panel in
/god-mode. - The signup form shows the code field only when
GET /api/invite/statusreports the instance is past its first account, so the bootstrap account never sees it.
NOITE_ADMIN_EMAIL promotes the matching account to the admin role at startup; it is documented in Environment variables.
Lost passkey
On the login screen, Lost passkey? emails a six-digit code (valid 10 minutes, five attempts) and, once entered, signs the account in on the page where you add a new passkey. Emailing needs NOITE_EMAIL_WEBHOOK_URL: the control UI POSTs { "email", "otp", "from", "type": "sign-in" } to it, and whatever you point it at (a mail relay, an automation) delivers it. Without a webhook nothing is sent on a real domain: the control UI logs the failure, and the screen still says a code was sent. Use the command below.
An operator who cannot wait for email, or never set a webhook, mints the same code on the server:
cd /opt/noite
docker compose exec noite noite-runner recover # for the instance owner (oldest admin)
docker compose exec noite noite-runner recover --email me@example.com
It prints a code and where to enter it. The code is the same kind the email carries: it works once, expires after 10 minutes, and anyone holding it can sign in as that account, so treat the output like a password. Running it needs a shell in the container, which already holds every secret of the install, so it grants nothing that access did not.