Skip to content

Multi tenancy

quentin edited this page May 5, 2025 · 1 revision

Multi-Tenancy Overview for Administrators

This document explains how the multi-tenancy module lets you run multiple domains (tenants) from a single application instance, each with its own settings and feature controls—no deep development knowledge required.


1. Active Domains Registry

  • Source: domains table in the database storing all registered domains with an active flag.
  • Loading: At startup, the system reads all active domains (via loadTenants()), builds an in-memory map of domain IDs and names, and caches their per-tenant configuration.

2. Configuration Hierarchy

  1. Global Defaults

    • Defined in code (defaultConfig) and local configuration file (config/local.json).
  2. Local Overrides

    • Project-wide settings in config/local.json that differ from defaults (e.g., host, port, global feature flags).
  3. Tenant Overrides

    • Stored per-domain in the tenantconfig table. Loaded at runtime and merged on top of the global settings via deepMerge().

When you call getConfig(domain, keyPath), the module merges global and tenant values, returning tenant-specific settings when available.

3. Domain Context Resolution

  • By Hostname: Incoming requests use req.hostname to determine which domain’s settings apply (if multiTenancy is enabled).
  • Admin UI Override: In the Settings page, administrators can switch domains with a ?domain= parameter to view or edit that tenant’s configuration.
  • Fallback: If no matching tenant is found or multi-tenancy is disabled, the system uses the global configuration exclusively.

4. Feature & Module Toggles

Every domain can enable or disable entire service modules independently:

Module Config Section Description
frontend server.availableModules.frontend Frontend pages (login, dashboard, profile)
register register User registration rules (invite, payment, username rules)
media media File upload/download limits and policies
payments payments Lightning payments, invoices, balance management
relay relay Nostr relay settings, WebSocket/API limitations
nostraddress server.availableModules.nostraddress Lookup pubkey by nostr address
lightning server.availableModules.lightning Lightning address redirection and management
verify server.availableModules.verify Event verification endpoint
plugins server.availableModules.plugins Plugin management API

Administrators simply toggle a module’s enabled flag under a domain to activate or deactivate it.

Note: The security, admin, and domains modules are global-only and cannot be customized per tenant to ensure consistent core functionality across all domains.

5. Per-Domain Settings Examples

  • Registration: Set register.requireinvite to require an invitation code only for some domains.
  • Upload Limits: Adjust media.maxMBfilesize differently per domain to control maximum file sizes.
  • Pricing: Define payments.satoshi.registerMaxSatoshi to charge different user registration fees.
  • Appearance: Customize appearance.serverName, theme colors, and background per domain.
  • Relay: Configure relay.limitation.auth_required to require authenticated WS connections; adjust relay.limitation.max_message_length and relay.limitation.max_filters for domain‑specific rate limits, or disable the entire relay module by toggling its enabled flag. 

6. Admin Settings UI

The Settings interface displays two panels:

  • Global Configuration: Current defaults and local overrides.
  • Domain Configuration: Merged settings for the selected domain.

Making a change in the domain panel writes directly to the tenant’s config in the database (via setConfig()), without affecting other tenants.

7. Enforcement in APIs & Services

  • Module Checks: Each API route calls isModuleEnabled(moduleName, req.hostname) to block inactive modules per domain.
  • Dynamic Behavior: Controllers use getConfig(req.hostname, keyPath) to retrieve domain-specific values for things like rate limits, file size, feature flags, and pricing.

8. Benefits

  • Operational Efficiency: One deployment serves many tenants—no need for separate instances.
  • Flexibility: Tailor business rules, pricing, and features to each community or project.
  • Isolation: Each tenant’s data, settings, and modules remain separate and secure.

With this multi-tenancy setup, administrators can onboard new domains, adjust features, and set custom policies—all from a unified interface, without touching the codebase.

Clone this wiki locally