Appaloft Docsv685dc5b2b9b264bb9b5749efdc50a341b407289b
Self-Hosting And Operations

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 admin@example.com \
  --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 admin@example.com \
  --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=admin@example.com
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 admin@example.com \
  --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/status

When the status says a first admin is required, a setup flow can call the setup endpoint once:

POST /api/bootstrap/auth/first-admin

Bootstrap 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:

ProviderRequired settings
GitHubAPPALOFT_GITHUB_CLIENT_ID, APPALOFT_GITHUB_CLIENT_SECRET, APPALOFT_GITHUB_REDIRECT_URI
GoogleAPPALOFT_GOOGLE_CLIENT_ID, APPALOFT_GOOGLE_CLIENT_SECRET, APPALOFT_GOOGLE_REDIRECT_URI
OIDCAPPALOFT_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. For 403 product_auth_forbidden, confirm the user belongs to the target organization and has admin or owner role.