Skip to content

Subdomains & Access Management

Guide for creating new subdomains, managing Cloudflare Access policies, and maintaining security.


Table of Contents

  1. Domain Structure
  2. Protection Strategy
  3. Creating New Subdomains
  4. Access Policies
  5. Testing Workflows
  6. Troubleshooting

Domain Structure

Naming Convention

Every subdomain must have a dev. counterpart following this pattern:

ProductionDevelopment
ourlantern.appdev.ourlantern.app
{subdomain}.ourlantern.app{subdomain}.dev.ourlantern.app

Full Domain Tree

ourlantern.app (production root)
├── dev.ourlantern.app              (development staging)

├── admin.ourlantern.app            (admin portal - prod)
│   ├── /docs/                      (internal documentation)
│   └── /storybook/                 (component library)

├── admin.dev.ourlantern.app        (admin portal - dev)
│   ├── /docs/                      (internal documentation)
│   └── /storybook/                 (component library)

├── docs.ourlantern.app             (public documentation - planned)

├── api.ourlantern.app              (future: backend/API - prod)
├── api.dev.ourlantern.app          (future: backend/API - dev)

├── *.ourlantern.app                (wildcard catch-all - prod)
└── *.dev.ourlantern.app            (wildcard catch-all - dev)

Deprecated subdomains: docs.dev.ourlantern.app, storybook.dev.ourlantern.app, storybook.ourlantern.app These are replaced by paths within the admin portal.

Current Domains

DomainEnvironmentPurposeProtection
dev.ourlantern.appDevelopmentMain app stagingIn-app Firebase Auth
admin.dev.ourlantern.appDevelopmentAdmin portal (includes docs & storybook)In-app Firebase Auth + Admin role
*.dev.ourlantern.appDevelopmentWildcard catch-allCloudflare Access PIN
ourlantern.appProductionMain app (live)In-app Firebase Auth (planned)
admin.ourlantern.appProductionAdmin portal (includes docs & storybook)In-app Firebase Auth + Admin role (planned)
docs.ourlantern.appProductionPublic documentationPublic (planned - curated subset)
*.ourlantern.appProductionWildcard catch-allCloudflare Access PIN

Note: Docs and Storybook are bundled into the admin portal at /docs/ and /storybook/ paths. Separate docs.dev.ourlantern.app and storybook.dev.ourlantern.app subdomains are deprecated. See Issue #255 for implementation details.


Protection Strategy

We use a hybrid protection model to avoid Cloudflare Access cache issues on the main app while keeping static sites protected.

In-App Firebase Auth (No Cloudflare Access)

These domains use Firebase Authentication at the app level:

DomainAuth Requirement
dev.ourlantern.appFirebase login + admin role (pilot phase)
admin.dev.ourlantern.appFirebase login + admin role
ourlantern.app (planned)Firebase login + admin role (pilot phase)
admin.ourlantern.app (planned)Firebase login + admin role

Why? Cloudflare Access redirects cause persistent cache issues, blocking real-time app updates.

Pilot → Public transition: When ready to open to the public, set PILOT_MODE = false in src/App.jsx.

Implementation details:

  • src/App.jsx - Contains PILOT_MODE flag and access gate logic
  • src/components/AccessGate.jsx - UI components for loading, login prompt, and access denied
  • src/lib/auth.js - checkAdminRole() function checks Custom Claims then falls back to Firestore

See Issue #254 for implementation details.

Docs & Storybook (Bundled in Admin Portal)

Docs and Storybook are served as static assets within the admin portal:

URLContent
admin.dev.ourlantern.app/docs/VitePress documentation (all internal docs)
admin.dev.ourlantern.app/storybook/Storybook component library
admin.ourlantern.app/docs/ (planned)VitePress documentation (all internal docs)
admin.ourlantern.app/storybook/ (planned)Storybook component library

Why bundled? Single auth system (Firebase), no Cloudflare Access cache issues, simpler infrastructure.

Future public docs: When ready, curated user-facing docs will be deployed to docs.ourlantern.app (public, no auth).

See Issue #255 for implementation details.

Cloudflare Access PIN (Wildcard Safety Net)

The *.ourlantern.app and *.dev.ourlantern.app wildcards ensure:

  • Any new/forgotten subdomain is protected by default
  • Preview deployments are automatically locked down
  • Zero-effort security for future subdomains

Creating New Subdomains

Scenario: Adding a New Subdomain (e.g., api.ourlantern.app)

Step 1: Code Your Feature

Create a feature branch and develop your subdomain code:

bash
git checkout -b feature/api-endpoint dev
# ... implement API functionality ...
git push origin feature/api-endpoint

Step 2: Test on Preview URL

Cloudflare auto-generates a preview URL:

  • https://feature-api-endpoint.lantern-app-dev.pages.dev
  • Already protected by dev Access app
  • Test thoroughly before proceeding

Step 3: Merge to Dev

bash
git checkout dev
git merge feature/api-endpoint
git push origin dev

Result: Deploys to dev.ourlantern.app for staging.

Step 4: Add DNS Record in Cloudflare

  1. Go to Cloudflare DashboardDNS
  2. Click Add record
  3. Configure:
    • Type: CNAME
    • Name: api
    • Content: lantern-app.pages.dev (or your prod project)
    • Proxy status: Proxied (orange cloud)
    • TTL: Auto
  4. Save

Step 5: Create/Update Access App

Option A: Use Wildcard App (Recommended)

  • The existing lantern-app-wildcard app already protects *.ourlantern.app
  • No new Access app needed
  • New subdomain automatically inherits PIN policy

Option B: Create Specific Access App

  1. Go to Cloudflare Zero TrustAccessApplications
  2. Click Add an applicationSelf-hosted
  3. Configure:
    • Application name: lantern-app-api
    • Domain: api.ourlantern.app
  4. Add same PIN policy as other apps
  5. Save

Step 6: Deploy to Production

Once tested in dev:

bash
git checkout main
git merge dev
git push origin main

Result: Lives at https://api.ourlantern.app (protected by Access)


Access Policies

Current Access Setup

Cloudflare Access applications protect static sites and act as wildcard safety nets:

  1. lantern-docs-dev (Development Docs)

    • Domain: docs.dev.ourlantern.app
    • Policy: One-time PIN
    • Purpose: Dev documentation site
  2. lantern-storybook-dev (Development Storybook)

    • Domain: storybook.dev.ourlantern.app
    • Policy: One-time PIN
    • Purpose: Dev component library
  3. lantern-wildcard-dev (Development Catch-all)

    • Domain: *.dev.ourlantern.app
    • Policy: One-time PIN
    • Purpose: Protect any unknown dev subdomains
  4. lantern-docs (Production Docs)

    • Domain: docs.ourlantern.app
    • Policy: One-time PIN
    • Purpose: Production documentation site
  5. lantern-storybook (Production Storybook)

    • Domain: storybook.ourlantern.app
    • Policy: One-time PIN
    • Purpose: Production component library
  6. lantern-wildcard (Production Catch-all)

    • Domain: *.ourlantern.app
    • Policy: One-time PIN
    • Purpose: Protect any unknown prod subdomains

Domains WITHOUT Cloudflare Access

These domains rely on in-app Firebase Auth instead:

DomainWhy No Cloudflare Access
dev.ourlantern.appMain app - Firebase auth avoids cache issues
admin.dev.ourlantern.appAdmin portal - Firebase auth + admin role
ourlantern.app (planned)Main app - Firebase auth avoids cache issues
admin.ourlantern.app (planned)Admin portal - Firebase auth + admin role

Modifying Access Policies

Change Authentication Method

For example, switch from "One-time PIN" to "Email Domain":

  1. Go to Cloudflare Zero TrustAccessApplications
  2. Click the app name (e.g., lantern-app-dev)
  3. Click Edit
  4. Go to Policies tab
  5. Click your existing policy
  6. Change Require from "One-time PIN" to "Email addresses":
    • Add allowed email addresses (e.g., team members)
  7. Save policy

Add a New Policy

Example: Allow GitHub organization members:

  1. Go to Applications → Click app → EditPolicies
  2. Click Add a policy
  3. Configure:
    • Action: Allow
    • Include rule:
      • Selector: GitHub Organization
      • Value: Your org name
    • Session duration: 24 hours
  4. Save

Remove/Disable a Policy

  1. Go to Applications → Click app → EditPolicies
  2. Click the X button on the policy to delete
  3. Save

Session Management

Adjust how long users stay logged in:

  1. Click app → Edit → Click policy
  2. Under Session duration, choose:
    • 15 minutes (most secure)
    • 1 hour
    • 24 hours (current default)
    • Custom duration
  3. Save

Testing Workflows

Testing New Subdomains Locally

Since new subdomains require Cloudflare DNS, test locally first:

bash
# In your dev server, you can test by mocking the subdomain
# For example, test API logic without hitting Cloudflare DNS
npm run dev

# Visit http://localhost:5173 and test your code

Testing on Preview URL

Feature branches auto-deploy to preview URLs:

https://feature-api-endpoint.lantern-app-dev.pages.dev

Access PIN: Same as dev environment (request from team)

Testing in Dev Environment

After merging to dev:

https://dev.ourlantern.app

Full staging environment with dev Firebase, staging data, etc.

Testing in Production

After merging to main:

https://ourlantern.app

Live environment — use real Firebase, real data, and careful QA!


Common Tasks

Add a New Team Member to Access

  1. Go to AccessApplications
  2. Click the app (e.g., lantern-app-dev)
  3. Click EditPolicies
  4. Edit the PIN or email policy
  5. Add their email address
  6. Save

Disable Access Temporarily

⚠️ Warning: This makes your site public. Use with caution.

  1. Go to AccessApplications
  2. Click app → Edit
  3. Click the Delete button at the bottom
  4. Confirm deletion
  5. The domain becomes public (no more Access protection)

To re-enable: Create a new Access app with the same domain and policy.

Monitor Access Logs

  1. Go to AccessLogs
  2. View recent authentication attempts
  3. Filter by domain, date range, or user
  4. Useful for debugging access issues

Set Different PIN for Different Environments

Currently all use the same PIN. To differentiate:

  1. Edit dev Access app → Click policy
  2. Change PIN code
  3. Save

Now dev has a different PIN than prod (useful for separating access).


Security Best Practices

✅ Do

  • ✅ Always create both prod and dev subdomains (e.g., api.ourlantern.app AND api.dev.ourlantern.app)
  • ✅ Keep Cloudflare Access enabled on static sites (docs, storybook)
  • ✅ Use in-app Firebase auth for main app and admin portal
  • ✅ Use strong, random PIN codes for Cloudflare Access
  • ✅ Limit who has access to production
  • ✅ Review Access logs regularly
  • ✅ Test new subdomains on preview before production
  • ✅ Rely on wildcard apps as a safety net for unknown subdomains

❌ Don't

  • ❌ Create a subdomain without its dev. counterpart
  • ❌ Use Cloudflare Access on main app (causes cache issues)
  • ❌ Share PIN codes publicly or in code
  • ❌ Use weak PIN codes (like "1234")
  • ❌ Forget to add DNS records for new subdomains
  • ❌ Commit environment secrets to Git

Troubleshooting

New Subdomain Not Working

Error: 404 or "Not Found"

Checks:

  1. Is the DNS record created? Go to DNS tab and verify CNAME exists
  2. Is it proxied (orange cloud)? If not, enable proxying
  3. Did you wait for DNS propagation? (Usually instant, but can take 5 mins)
  4. Is the code actually deployed to the right Pages project?

Fix:

bash
# Verify DNS record
nslookup api.ourlantern.app

# Should resolve to lantern-app.pages.dev or lantern-app-dev.pages.dev

Access Redirecting to Wrong Domain

Error: dev.ourlantern.app redirects to ourlantern.app

Cause: Multiple Access apps covering the same domain

Fix:

  1. Go to AccessApplications
  2. Check for duplicate entries
  3. Ensure each domain has only ONE app
  4. Delete duplicates if found

PIN Not Working

Error: "Invalid PIN" even though you entered it correctly

Cause: PIN sent to your email may have expired (usually 15 mins)

Fix:

  1. Go back and request a new PIN
  2. Check spam/junk folder
  3. If still issues, contact admin to reset

Built with VitePress