I kept seeing the same question here — “what’s the best way to run n8n for multiple
clients?” — so I wanted to share the setup that’s been working for me, in case it
saves someone the trial and error.
The short answer: one isolated n8n instance per client, managed from a shared stack.
After trying the single-instance-with-projects route, I went with a container-per-client
approach. Here’s the reasoning and the architecture:
Why instance-per-client
- Real isolation. Each client’s credentials (Salesforce, HubSpot, Gmail tokens) live in
their own container and their own database schema. No risk of cross-tenant leaks. - Process isolation. If one client’s n8n misbehaves, it doesn’t take down the others.
- Cleaner offboarding. Parting ways with a client = tear down one container, done.
The architecture
- Docker Compose stack: Caddy (reverse proxy + automatic HTTPS), Postgres, Qdrant
(for RAG use cases), and a base n8n. - Postgres with schema-per-tenant: one database, but each client gets an isolated schema.
Good balance between isolation and not running 20 separate databases. - Caddy with wildcard subdomains: each client gets client.yourdomain.com with HTTPS
handled automatically. Adding a client doesn’t mean touching DNS each time. - A CLI that provisions a new client in one command: creates the schema, spins up the
container, wires the subdomain, reloads the proxy. ~30 seconds instead of the usual
half-day of manual setup.
Two things that bit me (so they don’t bite you)
- The N8N_ENCRYPTION_KEY must be consistent and backed up. If it changes, every client’s
stored credentials become unrecoverable. Generate it once, keep it safe, never regenerate. - Pin your n8n version. Running :latest means clients created at different times can end
up on different versions, and an update can break workflows with no warning.
Updates across all clients
Because every client runs the same pinned image from a shared compose, rolling an update
is one operation, not one-per-client. That was the part I worried about most and it
turned out to be the easiest.
I ended up packaging all of this (the stack, the provisioning CLI, backup/restore per
client, a few ready-made workflow templates) into a project called Siennabase, since I
was tired of rebuilding it. If anyone wants to skip the setup, it’s at siennabase.dev
Happy to answer questions about any of the architecture decisions.