-
Notifications
You must be signed in to change notification settings - Fork 23
Multi tenancy
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.
-
Source:
domainstable in the database storing all registered domains with anactiveflag. -
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.
-
Global Defaults
- Defined in code (
defaultConfig) and local configuration file (config/local.json).
- Defined in code (
-
Local Overrides
- Project-wide settings in
config/local.jsonthat differ from defaults (e.g., host, port, global feature flags).
- Project-wide settings in
-
Tenant Overrides
- Stored per-domain in the
tenantconfigtable. Loaded at runtime and merged on top of the global settings viadeepMerge().
- Stored per-domain in the
When you call getConfig(domain, keyPath), the module merges global and tenant values, returning tenant-specific settings when available.
-
By Hostname: Incoming requests use
req.hostnameto determine which domain’s settings apply (ifmultiTenancyis 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.
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.
-
Registration: Set
register.requireinviteto require an invitation code only for some domains. -
Upload Limits: Adjust
media.maxMBfilesizedifferently per domain to control maximum file sizes. -
Pricing: Define
payments.satoshi.registerMaxSatoshito charge different user registration fees. -
Appearance: Customize
appearance.serverName, theme colors, and background per domain. - Relay: Configure
relay.limitation.auth_requiredto require authenticated WS connections; adjustrelay.limitation.max_message_lengthandrelay.limitation.max_filtersfor domain‑specific rate limits, or disable the entire relay module by toggling itsenabledflag.
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.
-
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.
- 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.