Docker vs DBFilter
When you create a subscription, you choose a deployment strategy: Docker or DBFilter. This is the most consequential decision in your SaaS setup — it determines how customer instances are isolated, how they scale, and how they are managed. The right choice depends on your isolation requirements, expected customer count, available server resources, and the technical profile of your customer base. You cannot change strategy after a subscription is created, so it is worth understanding the trade-offs before you start provisioning.
How Each Strategy Works
Docker
Each subscription runs as an isolated Docker stack managed through Portainer. The stack contains:
- An Odoo container (the customer's Odoo instance)
- A named Docker volume for filestore data
- Optionally a bundled PostgreSQL container, or a connection to an external PostgreSQL server
- Its own assigned HTTP port (and WebSocket port if workers > 1)
Nginx Proxy Manager receives a proxy host entry that routes the customer's domain to that port on the host machine.
Every subscription is completely independent — its own process, its own filesystem, its own database. One subscription crashing or consuming resources has no effect on others.
customer1.sadeem.cloud → NPM → host:8100 → Docker stack (Odoo + PG)
customer2.sadeem.cloud → NPM → host:8103 → Docker stack (Odoo + PG)
customer3.sadeem.cloud → NPM → host:8106 → Docker stack (Odoo + PG)
DBFilter
All subscriptions share a single running Odoo instance on a server. Each customer has their own database on that instance, and Odoo's --db-filter startup flag routes each incoming request to the correct database based on the domain name.
Nginx Proxy Manager routes all customer domains to the same Odoo port on the shared server.
customer1.sadeem.cloud → NPM → shared-odoo:8069 (db: customer1)
customer2.sadeem.cloud → NPM → shared-odoo:8069 (db: customer2)
customer3.sadeem.cloud → NPM → shared-odoo:8069 (db: customer3)
Side-by-Side Comparison
| Docker | DBFilter | |
|---|---|---|
| Isolation | Full — separate process, volume, ports per subscription | Shared — one Odoo process serves all customers |
| Resource usage | Higher — each subscription uses its own RAM and CPU | Lower — customers share the Odoo worker pool |
| Resource cost per customer | High — minimum ~256–512 MB RAM per idle container | Low — incremental cost per additional database is near zero |
| Odoo version per customer | Any — each stack uses its own Docker image | Same for all — all customers run the same Odoo instance |
| Custom addons per customer | Yes — mounted into each container independently | Limited — addons are installed at the instance level |
| Startup time | Slower — stack must be created and started | Fast — database already accessible on the running instance |
| Provisioning speed | 60–120 seconds (stack pull + container start) | 10–30 seconds (database create or template restore) |
| Ideal customer count per server | 10–50 (depends on RAM; each stack is a separate process) | 50–500+ (CPU/memory shared; scales well for small tenants) |
| Stop/Start | Stack is paused/resumed in Portainer | Database access is revoked; Odoo keeps running |
| Failure blast radius | One stack crashes → only that customer affected | One error in shared Odoo process can affect all customers |
| Scaling | Scale by adding more servers/environments | Scale by adding more shared Odoo instances |
| Backup granularity | Per-subscription — each stack has its own database and filestore volume, backed up independently | Per-database — database dump per customer; filestore backup may be shared or per-database depending on setup |
| PostgreSQL | Bundled in stack, or external server | External — the shared Odoo server's database host |
| Portainer required | Yes | No |
| Root server | Auto-assigned from Portainer environment | Not used unless Git integration is enabled |
| Migration path between strategies | No automated tool — requires exporting the database and filestore from the source subscription and importing under a new subscription with the target strategy | Same — no automated migration; manual export and re-import required |
When to Choose Docker
- You want strong isolation between customers
- Customers may need different Odoo versions or custom addons
- You are comfortable managing Docker and Portainer
- You have enough server resources to run multiple containers
- You need per-subscription start/stop without affecting others
- You need granular per-subscription backups with independent restore capability
- You serve customers who may have compliance or data residency requirements that benefit from process-level isolation
When to Choose DBFilter
- You are managing a large number of small customers on limited hardware
- All customers run the same Odoo version and addon set
- You want fast provisioning (database creation vs. stack launch)
- You have an existing shared Odoo instance to reuse
- You are running a trial or freemium tier where resource efficiency is critical
- You expect high subscription churn and want provisioning to be fast and lightweight
Can You Mix Both?
Yes. You can have Docker subscriptions and DBFilter subscriptions on the same Odoo master instance. Install both sadeem_saas_docker and sadeem_saas_dbfilter and choose the type per subscription at creation time.
Once a subscription is created, its SAAS Type field is fixed and cannot be changed. There is no automated migration path between strategies. If you need to move a customer from Docker to DBFilter (or vice versa), you must export the customer's database and filestore from the existing subscription, create a new subscription with the target strategy, and import the data into it. Plan your strategy choice carefully before provisioning.
Warning
Attempting to change saas_subscription_type on an existing subscription after it has been confirmed is not supported. Always set the correct type before clicking Confirm.