Stackvora.tech

Deploying Odoo in production: PostgreSQL, workers and reverse proxy

A hardened Odoo deployment: sizing workers, tuning PostgreSQL, nginx reverse proxy with websockets, backups and the security settings most installs miss.

Odoo is easy to install and easy to deploy badly. A production install needs four things right: worker sizing, PostgreSQL tuning, a correct reverse proxy, and locked-down database management.

Worker sizing

Odoo in multi-processing mode forks worker processes. A workable starting formula is workers = (CPU cores * 2) + 1, plus dedicated cron workers.

; /etc/odoo/odoo.conf
[options]
admin_passwd = <long-random-string>
db_host = 127.0.0.1
db_user = odoo
db_password = <secret>
dbfilter = ^mycompany$
list_db = False
proxy_mode = True
workers = 9
max_cron_threads = 2
limit_memory_soft = 2147483648
limit_memory_hard = 2684354560
limit_time_cpu = 600
limit_time_real = 1200

limit_time_real must exceed your longest legitimate request (large invoicing or MRP runs), or users will see random 504s.

PostgreSQL

  • Put the database on its own volume with fast storage; Odoo is chatty.
  • shared_buffers ≈ 25% RAM, effective_cache_size ≈ 60–70% RAM, work_mem 32–64MB for reporting-heavy installs.
  • Enable pg_stat_statements — nearly every Odoo performance ticket ends there.
  • Schedule VACUUM/autovacuum tuning for high-churn tables such as mail_message and ir_attachment.

nginx reverse proxy

upstream odoo      { server 127.0.0.1:8069; }
upstream odoochat  { server 127.0.0.1:8072; }

server {
  listen 443 ssl http2;
  server_name erp.example.com;

  proxy_set_header Host $host;
  proxy_set_header X-Forwarded-Host $host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_read_timeout 720s;
  client_max_body_size 100m;

  location /websocket { proxy_pass http://odoochat; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
  location /          { proxy_pass http://odoo; }
  location ~* /web/static/ { proxy_cache_valid 200 60m; proxy_pass http://odoo; expires 864000; }
}

Without the websocket block, live chat, discuss notifications and the barcode app silently stop updating.

Security musts

  • list_db = False and a strong admin_passwd — the database manager is the number one Odoo breach vector.
  • dbfilter so one hostname maps to exactly one database.
  • Run Odoo as a non-root system user with the filestore on a dedicated path.
  • Block /web/database/* at the proxy for public installs.

Backups

A backup is both the PostgreSQL dump and the filestore directory (~/.local/share/Odoo/filestore/<db>). Restoring one without the other gives you an ERP with no attachments. Test a full restore quarterly and record the elapsed time — that is your real RTO.

Upgrades

Odoo releases annually and Community upgrades are your responsibility. Use the official upgrade service or odoo-bin --upgrade path on a clone first, and budget most of the effort for custom modules and OCA dependencies rather than for core data.

Back to the knowledge base · Ask the AI assistant