Multi-tenancy
Multi-tenancy is built-into Uwazi and allows for multiple databases/tenants to be served with a single node process.
The tenant object defines all specific configurations. Tenants should be created on a separated db ‘uwazi_shared_db’ in a ‘tenants’ collections with the following structure:
This is from app/api/tenants/tenantContext.ts
export type Tenant = {
name: string; //must be unique
dbName: string; //should be unique
indexName: string; //should be unique
uploadedDocuments: string; //defaults to [rootPath]/uploaded_documents/
attachments: string; //defaults to [rootPath]/uploaded_documents/
customUploads: string; //defaults to [rootPath]/custom_uploads/
temporalFiles: string; //defaults to [rootPath]/temporal_files/
activityLogs: string; //defaults to [rootPath]/log/
};
Uwazi will use this config for requests that provide a tenant header corresponding with the tenant name, for requests that do not provide one Uwazi will use the defaultTenant from app/api/config.ts.
The most basic working example
//setup tenants, no paths specified for simplicity, but they can be specified instead of defaults
mongo localhost/uwazi_shared_db --eval 'db.tenants.insert({ name : "tenant1", dbName : "tenant1", indexName: "tenant1" });'
mongo localhost/uwazi_shared_db --eval 'db.tenants.insert({ name : "tenant2", dbName : "tenant2", indexName: "tenant2" });'
//setup dbs for tenants
yarn blank-state tenant1
yarn blank-state tenant2
//add entity for tenant1 and reindex
mongo localhost/tenant1 --eval 'db.entities.insert({ title : "Test entity", template : "5bfbb1a0471dd0fc16ada146", published: true, language: "en" });'
INDEX_NAME=tenant1 DATABASE_NAME=tenant1 yarn reindex
//start uwazi server
MULTI_TENANT=true node server
//requests for specific tenant, tenant1 should return "Test entity" and tenant2 should return an empty result :)
curl -H "tenant: tenant1" localhost:3000/api/search
curl -H "tenant: tenant2" localhost:3000/api/search
As you can see a MULTI_TENANT env variable is set to true, Uwazi is multi-tenant by default but we need to set this variable to deactivate certain features that do not work with a multi-tenant approach for now. These are the features not supported for now:
evidence vault
sync
semantic search
topic classification
Serving the web app
In order for this to work not only for the api but the web app, a proxy mapping the different tenants needs to be set up. We use nginx.
Here is a basic nginx config that maps different ports to the same Uwazi process, but with different tenant header:
server {
server_name tenant1.localhost;
listen 3001;
location / {
proxy_set_header tenant tenant1;
proxy_set_header host $host;
proxy_set_header x-forwarded-server $host;
proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
proxy_pass http://localhost:3000;
client_max_body_size 500M;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
}
}
server {
server_name tenant2.localhost;
listen 3002;
location / {
proxy_set_header tenant tenant2;
proxy_set_header host $host;
proxy_set_header x-forwarded-server $host;
proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
proxy_pass http://localhost:3000;
client_max_body_size 500M;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
}
}
Opening the browser on localhost:3001 will serve an app that will work with tenant1, localhost:3002 will work with tenant2.
Maintenance scripts
Scripts such as yarn migrate, and yarn reindex use the defaultTenant to perform the task, defaultTenant is configured by setting appropiate environment variables, a full list of this variables is on the install documentation.
Example:
DATABASE_NAME=tenant1_db INDEX_NAME=tenant1_index yarn migrate
DATABASE_NAME=tenant2_db INDEX_NAME=tenant2_index yarn reindex