owlette docs
self-hosting

firebase setup

Firebase provides Owlette's browser authentication, Firestore control/state database, and Firebase Storage bucket. Cloudflare R2 is configured separately for roost project content; see environment variables for the complete runtime variable list.


step 1: create the firebase project

  1. Open the Firebase Console.
  2. Select Add project.
  3. Name the project, for example owlette-prod or owlette-dev.
  4. Disable Google Analytics unless you explicitly need it.
  5. Finish project creation and open Project settings.

Use separate Firebase projects for development, staging, and production.


step 2: create the firestore database

  1. In the Firebase Console, open Firestore Database.
  2. Select Create database.
  3. Choose Start in production mode. The repository rules are deployed in a later step.
  4. Pick the Firestore location closest to the operators and machines you manage.
  5. Select Enable.

Do not manually create collections during setup. Owlette creates application documents through the dashboard, API routes, agents, and trusted server code.


step 3: enable authentication

  1. Open Authentication.
  2. Select Get started.
  3. Enable these sign-in providers:
    • Email/Password
    • Google, if you want Google sign-in in the dashboard
  4. In Authentication -> Settings -> Authorized domains, add the production dashboard domain and any preview/staging domains that will host the web app.

Passkeys use Firebase custom tokens created by the Owlette server; they do not require a separate Firebase provider toggle.


step 4: enable firebase storage

Firebase Storage is required for full Owlette functionality. The current web and agent flows use it for installer binaries, screenshots, chat images, and user avatars.

  1. Open Storage.
  2. Select Get started.
  3. Start in production mode.
  4. Keep the default bucket unless you have a deployment-specific reason to use another bucket.

The bucket name becomes NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET. New Firebase projects commonly use <project-id>.firebasestorage.app; older projects may use <project-id>.appspot.com. Copy the exact value from the Firebase web app configuration in the next step.


step 5: create a web app and copy client config

  1. Open Project settings -> General.
  2. Under Your apps, select Add app -> Web.
  3. Register the app, for example owlette dashboard.
  4. Copy the Firebase config values into the web deployment environment:
NEXT_PUBLIC_FIREBASE_API_KEY=...
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-project.firebasestorage.app
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=123456789012
NEXT_PUBLIC_FIREBASE_APP_ID=1:123456789012:web:abc123

These values are public browser configuration. Access control comes from Firebase Auth, Firestore rules, Storage rules, and server-side authorization.


step 6: create service account credentials

Owlette server routes use the Firebase Admin SDK for privileged operations such as verifying sessions, creating agent custom tokens, writing server-only collections, and coordinating Storage uploads.

  1. Open Project settings -> Service accounts.
  2. Select Generate new private key.
  3. Download the JSON file.
  4. Extract these three fields into separate server-side environment variables:
JSON fieldenvironment variable
project_idFIREBASE_PROJECT_ID
client_emailFIREBASE_CLIENT_EMAIL
private_keyFIREBASE_PRIVATE_KEY
FIREBASE_PROJECT_ID=your-project-id
FIREBASE_CLIENT_EMAIL=firebase-adminsdk-xxxxx@your-project-id.iam.gserviceaccount.com
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"

Keep the service account private

Never commit the downloaded JSON file or the extracted private key. In Railway and similar platforms, wrap FIREBASE_PRIVATE_KEY in double quotes and preserve the \n escape sequences.

Do not set FIREBASE_SERVICE_ACCOUNT_KEY; the current web code reads the split variables above.


step 7: deploy rules and indexes

Run these commands from the repository root so firebase.json can find firestore.rules, firestore.indexes.json, and storage.rules.

npm install -g firebase-tools
firebase login
firebase use --add
firebase deploy --only firestore:rules,firestore:indexes
firebase deploy --only storage

Choose the Firebase project created in step 1 when firebase use --add prompts for a project. The deploy uses:

filepurpose
firestore.rulesFirestore client access rules
firestore.indexes.jsonComposite indexes for chat, logs, audit logs, and webhook queries
storage.rulesFirebase Storage access rules

Indexes are required

Do not skip the firestore:indexes deploy. Features that query conversation history, autonomous events, logs, audit records, or webhooks can fail with a "requires an index" error until the composite indexes are live.

See Firestore Rules for rule architecture and testing guidance.


step 8: deploy the web app with firebase env vars

Add every variable from steps 5 and 6 to the web app's production environment, then deploy the web app. The Firebase setup is not complete until the running web deployment has both:

  • the NEXT_PUBLIC_FIREBASE_* client variables
  • the FIREBASE_PROJECT_ID, FIREBASE_CLIENT_EMAIL, and FIREBASE_PRIVATE_KEY server variables

See environment variables and web deployment for the full production checklist, including session, email, rate-limit, cron, Cortex, and R2 variables.


step 9: bootstrap the first superadmin

New users are created as member with an empty sites array. The first platform operator must be promoted manually after signing in once.

  1. Open the deployed dashboard.
  2. Register or sign in with the first operator account.
  3. In Firebase Console, open Firestore Database -> Data -> users -> {uid} for that account.
  4. Change role from "member" to "superadmin".
  5. Save the document, then sign out and sign back in to refresh the dashboard session.

After the first superadmin exists, use Admin Panel -> User Management to promote other users or assign site access.


access model summary

Owlette enforces site-based access through Firestore rules and server-side API authorization.

roleaccess
memberReads assigned sites listed in users/{uid}.sites[]
adminSite-scoped write access for assigned sites
superadminPlatform admin access and implicit access to every site
agentCustom-token access to one site and one machine

Client rules name the helpers isSuperadmin(), isSiteAdmin(siteId), canAccessSite(siteId), isServiceAccount(), and agent claim helpers. Trusted server APIs and the Admin SDK handle server-only collections and control-plane writes.


firestore paths used by owlette

This is the operational shape a fresh project should expect after users, sites, and agents start using the system:

sites/{siteId}
sites/{siteId}/machines/{machineId}
sites/{siteId}/machines/{machineId}/commands/{commandDoc}
sites/{siteId}/machines/{machineId}/screenshots/{screenshotId}
sites/{siteId}/machines/{machineId}/installed_software/{softwareId}
sites/{siteId}/machines/{machineId}/hardware/{docId}
sites/{siteId}/machines/{machineId}/metrics_history/{bucketId}
sites/{siteId}/roosts/{roostId}
sites/{siteId}/roosts/{roostId}/target_state/{machineId}
sites/{siteId}/roosts/{roostId}/versions/{versionId}
sites/{siteId}/deployments/{deploymentId}
sites/{siteId}/installer_templates/{templateId}
sites/{siteId}/project_templates/{templateId}
sites/{siteId}/webhooks/{webhookId}
sites/{siteId}/logs/{logId}
sites/{siteId}/audit_log/{entryId}
config/{siteId}/machines/{machineId}
config/{siteId}/schedule_presets/{presetId}
config/{siteId}/reboot_presets/{presetId}
config/{siteId}/project_distribution_presets/{presetId}
users/{uid}
users/{uid}/api_keys/{keyId}
users/{uid}/settings/{settingId}
users/{uid}/devicePrefs/{docId}
chats/{chatId}/messages/{messageId}
system_presets/{presetId}
installer_metadata/{document}
agent_tokens/{tokenId}
agent_refresh_tokens/{tokenHash}
device_codes/{phrase}
api_keys/{keyHash}

Server-only paths such as agent_tokens, agent_refresh_tokens, device_codes, top-level api_keys, and most installer upload state are intentionally denied to normal client reads and writes. They are managed through trusted Owlette server routes.


verification checklist

  • Email/password login works.
  • Google login works if the provider is enabled.
  • A signed-in user's users/{uid} document exists.
  • The first operator has role: "superadmin".
  • firebase deploy --only firestore:rules,firestore:indexes completes successfully.
  • firebase deploy --only storage completes successfully.
  • The web deployment has all NEXT_PUBLIC_FIREBASE_* and Firebase Admin variables.
  • The dashboard can create or open a site without Firestore permission errors.
  • Installer upload, screenshot capture, chat image upload, and profile photo upload can access Firebase Storage.

troubleshooting

cannot find the rules tab

Create the Firestore database first. The Firestore console shows Data, Rules, Indexes, and Usage only after the database exists.

permission denied in the dashboard

  1. Confirm the user is signed in.
  2. Confirm users/{uid} exists.
  3. Confirm the user's role and sites array are correct.
  4. Confirm Firestore rules were deployed from firestore.rules.
  5. Use the Firebase Rules Playground with the same path and auth claims.

admin features fail but the app loads

Check the server-side Firebase Admin variables: FIREBASE_PROJECT_ID, FIREBASE_CLIENT_EMAIL, and FIREBASE_PRIVATE_KEY. Admin routes can fail even when browser login works, because browser login only proves the NEXT_PUBLIC_FIREBASE_* client variables are present.

storage upload fails

  1. Confirm Firebase Storage is enabled.
  2. Confirm NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET matches the bucket in Firebase Console.
  3. Confirm storage.rules was deployed with firebase deploy --only storage.
  4. Confirm the caller has the expected role for the upload path.

on this page