Skip to Content

Final production checklist (Odoo + PgBouncer + PostgreSQL)

December 27, 2025 by
Final production checklist (Odoo + PgBouncer + PostgreSQL)
John Wolf
| No comments yet

This is the checklist you want to havebeforeopening Odoo to the world. It's not theory: it's what prevents 80% of startup incidents (auth, pools, websocket, queues, locks, logs, backups).


1) Network and exposure (layer "don't get hacked")

  • Odoo is NOT exposeddirectly to the Internet

    • http_interface = 127.0.0.1 (or private network)

  • Only thereverse proxy (Nginx/HAProxy)listens on 443 (TLS)

  • Firewall:

    • 443 open to the world

    • 8069/8072 closed to the world (only localhost or internal network)

    • 6432 (PgBouncer) only accessible from Odoo/internal network

    • 5432 (Postgres) only accessible from PgBouncer/bastion


2) Reverse proxy and WebSocket (the "classic ghost bug")

  • / → Odoo HTTP (8069)

  • /websocket/ → Odoo gevent (8072)

  • Correct headers:

    • X-Forwarded-For

    • X-Forwarded-Proto

    • Host

  • proxy_mode = True in Odoo

  • Reasonable proxy timeouts (PDF reports are not 5s)


3) Odoo: minimum secure configuration

  • strong admin_passwd and outside the repo

  • list_db = False

  • defined dbfilter (if multi-DB / multi-tenant applies)

  • separate addons_path (core vs custom)

  • defined logfile with rotation (logrotate/journald)


4) Odoo: concurrency and limits (so it doesn't "eat" the host)

  • workers sized by CPU/RAM (not by faith)

  • conservative max_cron_threads (1–2) if you haven't measured yet

  • Configured limits:

    • limit_time_cpu

    • limit_time_real

    • limit_memory_soft

    • limit_memory_hard

  • If there are spikes due to crons: batching + avoid long transactions (mitigation plan)


5) PgBouncer: correct pool (and no surprises)

  • pool_mode = transaction for Odoo web

  • calculated default_pool_size (and not 'random')

  • reserve_pool_size for short spikes

  • sufficient max_client_conn for workers + spikes

  • If there are multiple DBs: consider max_db_connections and limits per pool


6) Auth: users, userlist, and reloads

  • defined auth_type (ideally scram-sha-256)

  • auth_file (userlist.txt) with correct format and permissions 0600

  • If you use auth_user/auth_query: technical role and well-structured query/fn

  • Rotation procedure:

    • edit userlist

    • RELOAD (or SIGHUP) without downtime


7) TLS 'if applicable' (not always, but when it applies, do it right)

  • If Odoo↔PgBouncer cross untrusted networks: TLS enabled

  • db_sslmode in Odoo (ideally verify-full if you have CA/hostname correct)

  • Certificates with correct SAN (hostname)

  • Certificate rotation plan (expiration monitored)


8) PostgreSQL: limits, timeouts, and DB health

  • max_connections consistent with actual pools (PgBouncer)

  • Timeouts:

    • statement_timeout (according to your policy)

    • lock_timeout

    • idle_in_transaction_session_timeout

  • Useful logs:

    • log_lock_waits (if you need visibility of locks)

  • Monitored autovacuum (so performance doesn't degrade over time)


9) Minimum observability (without this, you fly blind)

PgBouncer

  • SHOW POOLS; monitored (cl_waiting, maxwait)

  • SHOW STATS; collected (TPS/aggregated latency)

  • Logs:

    • log_connections=1

    • log_disconnections=1

    • log_pooler_errors=1

Odoo

  • p95/p99 of key endpoints (login, listings, write, reports)

  • errors (timeouts, pool full, deadlocks) as metrics/alerts

  • duration of crons and overlap (backlog)

Postgres

  • long transactions (xact_start)

  • sessions waiting for locks

  • top queries (if you use pg_stat_statements)

Infra

  • CPU, RAM, swap

  • I/O wait and disk latency

  • network (drops/retransmits)

  • file descriptors (especially PgBouncer)


10) Backups, restore, and 'day 2' (what defines if you survive)

  • Verified automatic backups (not just 'exist')

  • Tested restore in staging (real RTO, not theoretical)

  • Maintenance plan:

    • Odoo upgrade

    • Postgres upgrade

    • PgBouncer upgrade

  • Internal documentation:

    • how to view queue (SHOW POOLS)

    • how to reload auth_file

    • what to do in case of locks/long transactions


Closure (the golden rule)

If you only do 3 things to be at ease:

  1. Well-routed Proxy + WebSocket

  2. PgBouncer sized with metrics (cl_waiting, maxwait)

  3. Crons without long transactions (batching)


Next chapter ->

Final production checklist (Odoo + PgBouncer + PostgreSQL)
John Wolf December 27, 2025
Share this post
Tags
Archive
Sign in to leave a comment