Multi-customer architecture for MSPs

What changed

Every content update is versioned. Select a version to compare it with the one before.

Version 1 → 2

Small fix
3 lessons updated

Small corrections such as typos or translation fixes. Learners are not notified.

Isolation between customers starts with one question: which tenant does this request belong to? ### Monopam From v2026.09 Monopam derives the tenant **from the request host and port only**. Each tenant has its host names; an address that is no host of any tenant reaches no tenant. A tenant header sent by a client is not honoured. A signed-in session is bound to the tenant it was issued for. Used against another tenant's address it is rejected (HTTP 401) and the person is sent to sign-out. One session cannot act in several tenants. ### Monosign Monosign keeps all tenants in one database and filters every tenant-scoped table by tenant. It resolves the tenant in this order: a tenant header named by an API caller, then the host name and port, then the active default tenant. Browsers are resolved by host. ::diagram msp-tenant-resolution ### What this means for your design - Give every customer its own host name, in both products. Host and port must be unique across all tenants. - In front of Monopam, your proxy must pass the original `Host` header and `X-Forwarded-Proto`. An installation answers 404 on every page for a host it does not know. - Do not plan on a shared address with a customer selector. In Monopam there is no such thing. > Note: After the upgrade to Monopam v2026.09 every user signs in once more, because cookie keys moved into the database.
One Monopam installation means one installation database, one Redis and one vault key. It can run on several app servers. Two environment settings on each server decide its part: - `MONOPAM_SERVED_TENANTS`: the tenants this server answers for. Other tenants' addresses get the tenant-not-found page. - `MONOPAM_JOB_TENANTS`: the tenants this server runs background jobs for (rotation, discovery, user synchronisation, certificate jobs, alerts). ``` # main server: answers for every tenant, runs jobs only for its own MONOPAM_SERVED_TENANTS=* MONOPAM_JOB_TENANTS=default # customer server: answers and runs jobs for one tenant MONOPAM_SERVED_TENANTS=tenant-a MONOPAM_JOB_TENANTS=tenant-a ``` With both settings left out, a single server serves every tenant and runs every job. ::diagram msp-app-servers ### Rules for the plan - **Every tenant name appears in exactly one server's job list.** A tenant listed on two servers gets its rotations, alerts and synchronisations twice. - The main server starts first on a fresh database; it creates the default tenant. - A server that serves a tenant with a dedicated database needs network access to that database and to the installation database. - A dedicated tenant is best served by its own app server. ### What one server does not isolate Within one job loop, a tenant that fails stops that loop for the round; shared tenants run first, dedicated ones after. A dedicated database that is down therefore does not hold up the tenants of the installation database.
Some customers will not place their privileged data in a provider's environment. A **remote tenant** lets them run Monopam themselves and still be your managed customer. ### How the link works 1. You create the remote tenant and get a one-time enrollment code, valid for 24 hours and shown once. 2. The customer enrolls its installation with your address and the code. It creates its own keys; the private keys never leave it. 3. The customer's installation keeps **one outward WebSocket** to you. You never connect to the customer, and the customer needs no inbound rule. Every message is signed and single-use. You can hand the customer ready deployment files (Docker Compose, Kubernetes or OpenShift). Its secrets are made up on its own machines; nothing about its database is stored with you. ### Who decides what - You **propose** which of your people may enter, with a role. - The customer **approves each person** and picks the policies that decide what the person sees. Any change you make asks for approval again. - **Disconnect Provider** is the customer's switch: your sessions end within seconds and nobody of yours can enter until the customer reconnects. - **Offline tolerance** (1 hour, 4 hours, 24 hours by default, or 7 days) sets how long your access keeps working without a new synchronisation. ::diagram msp-remote-tenant-link ### What you cannot do - Manage the remote tenant's hosts, users, seed or settings, or see its policies. - Use group accesses or choose policies yourself. - Reach the customer's web address through the link. Your staff use the path the customer gives them, such as a VPN. > Warning: Issuing a new enrollment code cuts the linked installation off for good; it must enroll again.