Odoo best practices

Tune Odoo for performance and stability on TurboStack - worker sizing, PostgreSQL, the Nginx reverse proxy, filestore offloading, and safe scaling.

Odoo is a Python ERP that runs as its own long-lived service behind an Nginx reverse proxy. Getting good, stable performance is mostly about right-sizing the worker pool, keeping PostgreSQL healthy, and letting Nginx serve static and filestore content. This page covers what TurboStack already configures for you and the optimizations worth applying on top.

What TurboStack configures for you

When you set app_type: odoo, the platform provisions a complete, tuned Odoo stack:

  • A dedicated systemd service that launches odoo-bin from your pyenv-managed Python and restarts automatically on failure (Restart=on-failure).
  • An Nginx reverse proxy with proxy_mode = True set in Odoo, forwarding X-Forwarded-* and X-Real-IP headers so Odoo sees the correct client address and scheme.
  • Multiprocess workers, auto-calculated from the server's CPUs, plus max_cron_threads = 2 for scheduled jobs.
  • A separate websocket/longpolling endpoint - Nginx routes /websocket (Odoo 16+) and /longpolling (Odoo 15 and earlier) to the gevent port (8072 by default). Normal traffic goes to the main port (8069).
  • Per-worker resource limits: limit_memory_soft (2 GB), limit_memory_hard (4 GB), limit_time_cpu (3600 s), limit_time_real (7200 s) and limit_request (8192).
  • Direct filestore delivery: x_sendfile = True plus an Nginx internal /web/filestore location, so attachments are streamed by Nginx instead of through Python workers.
  • A PostgreSQL connection with a dedicated role and database, plus a generated admin_passwd for the database manager.
  • A ready-made odoo.conf.sample in your conf/ directory with all of the above as a starting point.
  • Tune the worker count to your workload. The default scales with CPUs. Odoo's guideline is roughly (2 x CPU) + 1 HTTP workers, or about one worker per 6 concurrent users - use the lower of the two. More workers serve more concurrent users but cost RAM - see Sizing and scaling.
  • Keep filestore on disk, not in the database. The platform already serves it via Nginx; avoid storing attachments in PostgreSQL, which bloats the database and backups.
  • Run Odoo in production mode. Do not enable dev_mode or demo data on a live site; the defaults already disable them (without_demo = True).
  • Pre-compile and cache assets. Let Odoo bundle and minify JS/CSS (the default), and serve them through Nginx with long cache headers.
  • Right-size cron threads. Heavy scheduled actions (mailings, accounting, inventory valuation) run under max_cron_threads; keep them modest so cron jobs do not starve HTTP workers.
  • Tighten timeouts for long operations. Imports and reports may need higher limit_time_real/limit_time_cpu; raise them deliberately rather than disabling them.
  • Front it with HTTP caching/Content Delivery Network (CDN) where safe. Static assets and public application pages cache well; never cache authenticated /web session traffic.
  • Install Python dependencies in the virtual environment. Use the project's pip, never system-wide: pip install -r odoo/requirements.txt for core, and pip install -r custom-addons/<addon>/requirements.txt per add-on.
  • Leave db_maxconn at its default (64). The platform's PostgreSQL is tuned for high concurrency; raising it rarely helps and can exhaust connections.

Manage the Odoo and PostgreSQL services from the host Services tab.

Sizing and scaling

The worker pool and memory limits are auto-tuned from the server's resources, and PostgreSQL is sized by the platform. Override defaults only with measured evidence:

Variable Tune when
workers CPUs are consistently busy and requests queue - but ensure RAM covers workers × limit_memory_soft.
limit_memory_soft / limit_memory_hard Workers are recycled too aggressively under legitimate load.
PostgreSQL memory and connections The database becomes the bottleneck rather than the app.

See Performance tuning for the general approach to changing auto-tuned values.

Stability

  • Back up regularly. Ensure both PostgreSQL and the filestore are covered - see Backups. A database backup without the matching filestore loses attachments.
  • Watch the Health tab for CPU, memory, and service status; rising memory or worker restarts are early warnings.
  • Keep Odoo and modules current. Apply security and point releases, and review third-party modules before upgrading major versions.
  • Test on a staging clone. Validate module installs/upgrades (-u) and configuration changes on a copy before touching production.