First admin bootstrap
Create the local first admin after self-hosted install, log in to the console, and handle OAuth and recovery safely.
A self-hosted Appaloft instance needs one local admin the first time it starts. This account logs in to the Web console, finishes organization setup, and can manage deploy tokens and members after admin authorization surfaces are available.
The installer can create the first admin from trusted install input:
curl -fsSL https://appaloft.com/install.sh | sudo sh -s -- \
--first-admin-email [email protected] \
--first-admin-name "Admin"When --first-admin-password is not provided, the installer generates a one-time password and
prints it once from trusted handoff output after the Appaloft container becomes healthy. Save it
immediately. If the installer is rerun after an admin or organization owner already exists,
bootstrap is skipped safely and the password is not shown again.
To provide your own initial password, pass:
curl -fsSL https://appaloft.com/install.sh | sudo sh -s -- \
--first-admin-email [email protected] \
--first-admin-password "$APPALOFT_INITIAL_ADMIN_PASSWORD"The installer does not echo a supplied password. Do not place passwords in repository config, shell history, CI logs, issues, pull request comments, or deployment output.
Containers and self-hosted runtimes can also create the first admin during startup from trusted environment variables without writing a handoff file:
APPALOFT_FIRST_ADMIN_EMAIL=[email protected]
APPALOFT_FIRST_ADMIN_DISPLAY_NAME=Admin
APPALOFT_FIRST_ADMIN_ORGANIZATION_NAME="Self-hosted Appaloft"
APPALOFT_FIRST_ADMIN_ORGANIZATION_SLUG=self-hosted-appaloft
APPALOFT_FIRST_ADMIN_PASSWORD="$APPALOFT_INITIAL_ADMIN_PASSWORD"Startup bootstrap only runs automatically when both email and password are configured. If no
password is supplied, configure APPALOFT_BOOTSTRAP_FIRST_ADMIN_OUTPUT_FILE so the generated
one-time password has a trusted handoff destination.
If the installer did not receive a first-admin email, open the printed console URL after install.
The console checks bootstrap status and sends first-time visitors to
/bootstrap/auth/first-admin. You can also open that setup path directly. The page reads bootstrap
status first; if the instance already has an admin, it sends you to /login instead of creating
another account.
CLI bootstrap uses the same application command/query path:
appaloft auth bootstrap-status
appaloft auth bootstrap-first-admin \
--email [email protected] \
--display-name "Admin"The installer prints the console URL. Without a domain, it is usually the server's 3721 port. With
--domain, use that HTTPS domain.
Log in with the configured account email and password. After login, Appaloft recognizes your user session
and protects product mutations by organization role. A mutation without a session returns
401 product_auth_missing; a logged-in user outside the organization or without enough role returns
403 product_auth_forbidden.
To end the browser session, use the Sign out control in the console header or user menu. The
console clears its cached session state and returns to /login.
Install and console setup flows can read the public bootstrap status:
GET /api/bootstrap/auth/statusWhen the status says a first admin is required, a setup flow can call the setup endpoint once:
POST /api/bootstrap/auth/first-adminBootstrap status is intentionally public. The setup endpoint is available only until first setup is
complete. After an admin or organization owner exists, Web no longer shows a create-admin action,
direct setup-page visitors return to login, and the setup endpoint returns
404 first_admin_bootstrap_disabled without dispatching the create command, creating another admin,
or returning a password.
Google, GitHub, or generic OIDC can be configured later. When the client id, client secret, callback URL, or trusted origin is missing, OAuth login should stay disabled, but local first-admin login should still work.
Use the local admin for the first login. After the console is reachable, add OAuth configuration:
| Provider | Required settings |
|---|---|
| GitHub | APPALOFT_GITHUB_CLIENT_ID, APPALOFT_GITHUB_CLIENT_SECRET, APPALOFT_GITHUB_REDIRECT_URI |
APPALOFT_GOOGLE_CLIENT_ID, APPALOFT_GOOGLE_CLIENT_SECRET, APPALOFT_GOOGLE_REDIRECT_URI | |
| OIDC | APPALOFT_OIDC_CLIENT_ID, APPALOFT_OIDC_CLIENT_SECRET, APPALOFT_OIDC_DISCOVERY_URL, APPALOFT_OIDC_REDIRECT_URI |
Callback URLs use the auth API origin. GitHub and Google default to
<APPALOFT_BETTER_AUTH_URL>/api/auth/callback/<provider>, and generic OIDC defaults to
<APPALOFT_BETTER_AUTH_URL>/api/auth/oauth2/callback/oidc. Configure the browser console origin
through APPALOFT_WEB_ORIGIN so it is trusted by the auth runtime.
Do not manually edit database user, member, or organization rows to bypass first login.
The first admin becomes the owner of the initial organization. After login, use
Organization team management to read the
current organization context, invite members, update non-owner roles, transfer ownership, remove
non-owner members, and recover from
401 product_auth_missing or 403 product_auth_forbidden.
If the generated one-time password is lost, rerunning the installer will not show the old password again. Prefer an existing admin session or a formal admin recovery flow when available. For early self-hosted instances with no usable admin, restore from a trusted backup instead of editing auth database tables directly.
If you cannot log in after install:
- Confirm you are using the console URL printed by the installer, not a project resource domain.
- Check that the first-admin email matches the install input.
- Check whether installer output says bootstrap was skipped; if it was skipped, the instance already has an admin or owner.
- For
401 product_auth_missing, log in again. For403 product_auth_forbidden, confirm the user belongs to the target organization and has admin or owner role.