PRODUCTION COMPOSE

Build an Odoo Compose stack that can survive the first failure.

A production design is more than docker compose up -d. Keep PostgreSQL private, persist both data stores, pin tested images, terminate HTTPS at a reverse proxy, restrict database selection, tune Odoo’s production server, monitor the host, and prove that remote backups restore.

Production Odoo Compose stack with proxy application database volumes and remote backups

The direct answer: use at least three roles: an HTTPS reverse proxy exposed on 80/443, Odoo on a private application network, and PostgreSQL on a private database network with no published host port. Persist /var/lib/odoo and PostgreSQL separately. Compose describes that topology; production readiness comes from configuration, secret handling, resource policy, monitoring, patching, and tested off-host recovery.

Prerequisites

Prepare operations before YAML

  • A supported, patched Linux host with restricted key-based administration and a firewall.
  • DNS controlled by your organization and a valid certificate renewal path.
  • A chosen Odoo 19 build, PostgreSQL version, tested custom addon set, and documented owner for updates.
  • Remote encrypted backup storage with separate credentials, retention policy, alerts, and restore exercises.
  • Monitoring for application health, logs, certificate expiry, CPU, memory, disk, database growth, cron work, and backup status.

Do not copy a VPS size from a generic blog. Odoo workload depends on concurrent requests, workers, imports, reports, cron jobs, integrations, website traffic, attachments, and custom code. Measure and adjust with headroom.

Architecture

Separate public traffic, application, database, and recovery

LayerPublic exposurePersistent stateControl
Reverse proxy80/443 onlyCertificates/configurationTLS, headers, request limits, timeouts
Odoo 19Private proxy network/var/lib/odoo filestoreWorkers, limits, dbfilter, addons
PostgreSQLPrivate database network onlyPostgreSQL data directoryNon-superuser Odoo role, access policy
Backup targetOutbound or isolated backup pathDatabase + matching filestoreEncryption, retention, immutability, restore tests

Only the proxy should accept internet requests. Do not publish PostgreSQL. Ideally do not publish Odoo’s 8069 port to all host interfaces either; connect the proxy through the internal network or bind Odoo to loopback if the proxy runs on the host. Avoid mounting the Docker socket into the web-facing proxy or application.

Compose baseline

Start from official image behavior, then add controls

Docker Hub’s official Odoo example documents a web service, a separate PostgreSQL service, named volumes, custom configuration at /etc/odoo, custom addons at /mnt/extra-addons, and file-based PostgreSQL password support. The following fragment illustrates the private application/database core, not a complete production file:

services:
  web:
    image: odoo:19.0
    depends_on:
      - db
    volumes:
      - odoo-web-data:/var/lib/odoo
      - ./config:/etc/odoo:ro
      - ./addons:/mnt/extra-addons:ro
    environment:
      HOST: db
      USER: odoo
      PASSWORD_FILE: /run/secrets/postgresql_password
    secrets:
      - postgresql_password
  db:
    image: postgres:15
    environment:
      POSTGRES_DB: postgres
      POSTGRES_USER: odoo
      POSTGRES_PASSWORD_FILE: /run/secrets/postgresql_password
      PGDATA: /var/lib/postgresql/data/pgdata
    volumes:
      - odoo-db-data:/var/lib/postgresql/data/pgdata
    secrets:
      - postgresql_password
volumes:
  odoo-web-data:
  odoo-db-data:
secrets:
  postgresql_password:
    file: ./secrets/odoo_pg_pass

Keep the secret file outside version control with restrictive permissions. Compose file-based secrets improve accidental exposure but are not an automatic hardware-backed vault. Add explicit internal networks, a reverse proxy, health checks, restart behavior, log rotation, and resource controls appropriate to your Compose/runtime version and tested deployment.

odoo:19.0 avoids an unintended major upgrade, but it can move as new 19.0 builds are published. For reproducible production rollout, record and deploy a tested dated tag or immutable digest, then deliberately test and promote newer current builds. Never advise latest for production.

Odoo configuration

Harden database routing and server behavior

Set proxy_mode = True only because requests arrive through a trusted reverse proxy. Enabling it on a directly exposed server can make client-address and scheme information trust attacker-controlled forwarding headers.

For a single production database, configure db_name and/or a precise dbfilter that matches only the intended hostname/database. Confirm routing first, then set list_db = False (equivalent startup option: --no-database-list) and block /web/database management routes at the proxy. Odoo strongly recommends disabling Database Manager for internet-facing systems.

Docker’s default Odoo server is multi-threaded, which Odoo describes primarily for development and demonstrations. Production uses a nonzero worker count and configured memory, request, CPU, real-time, and cron limits. Odoo publishes rules of thumb, but custom modules and reports vary dramatically; load-test, monitor, and tune rather than treating a formula as a promise.

Reverse proxy

Make HTTPS the only public path

Odoo’s deployment guide states that authentication information is transmitted in cleartext without HTTPS. Redirect HTTP to HTTPS, maintain a valid certificate, forward the documented host, scheme, address, and realtime/websocket traffic, and set proxy request-size and timeout limits based on legitimate imports and reports. Test long-running requests without opening unlimited timeouts.

Add HSTS only after HTTPS and renewal are proven; a long HSTS policy can lock users out if certificates fail. Restrict direct access to Odoo, verify generated links use the public HTTPS URL, and test websocket-dependent features. Protect metrics and administrative proxy endpoints from public access.

Security and backups

Assume the host and a backup job can fail

Use a non-superuser PostgreSQL application role and keep port 5432 private. Patch the host, Docker runtime, proxy, PostgreSQL image, and Odoo build. Scan and review custom addons, remove unused services, deny demo data, secure the Odoo master password, rotate credentials deliberately, and keep production separate from developer environments.

A named volume is not a backup. Schedule a PostgreSQL-aware dump or snapshot coordinated with the matching Odoo filestore. Copy encrypted backups to remote storage that compromised application credentials cannot delete. Preserve configuration, custom addon revisions, image digests, and a secrets inventory. Define retention and recovery objectives based on business needs.

Restore tests are mandatory: build an isolated stack, restore both data components, and verify attachment downloads, logins, reports, integrations, cron jobs, and representative transactions. Record time to recovery and fix undocumented steps.

Updates

Promote builds; do not mutate blindly

  1. Record the running image digests, Odoo configuration, database version, and addon revisions.
  2. Read release/build changes and dependency advisories.
  3. Create and verify a recoverable backup before maintenance.
  4. Restore or clone representative data to staging with personal-data controls.
  5. Deploy the candidate Odoo 19 and PostgreSQL patch images; test install/update paths and workflows.
  6. Roll production during a communicated window, monitor errors and queues, and retain a tested recovery path.

A major Odoo change requires a database and addon migration; changing 19.0 to a later major tag is not an upgrade plan. PostgreSQL major upgrades also need their own documented method.

Troubleshooting

Use the failing boundary to choose the next check

  • 502/504: inspect proxy and Odoo logs, container health, worker exhaustion, timeouts, and network membership before increasing limits.
  • Redirect loop or HTTP links: verify proxy headers and Odoo proxy mode; do not enable proxy mode without the proxy.
  • Database unavailable: check PostgreSQL health, private DNS, credentials file permissions, storage space, and role access.
  • Attachments missing after restore: the database and filestore are mismatched or the volume is mounted at the wrong path.
  • Database selector visible: validate db routing, disable listing, and block management routes after confirming the target database resolves.
Go-live checklist

Evidence required before launch

  • Only 80/443 public; PostgreSQL and 8069 are not directly internet-accessible.
  • Valid HTTPS, renewal alert, correct proxy headers, realtime traffic, and safe request limits tested.
  • Pinned tested Odoo 19 and PostgreSQL image references recorded; no production latest.
  • Database routing restricted, listing disabled, management routes blocked, demo data absent.
  • Workers and limits tested under representative load; host and container metrics alert.
  • Remote database-plus-filestore backup restored successfully in isolation.
  • Owner, maintenance window, incident contacts, update runbook, and recovery runbook documented.
Questions

FAQ

Is Docker Compose itself production-ready for Odoo?

Compose can describe a production topology, but a short Compose file is not production readiness. You still need HTTPS, isolation, secrets, database restrictions, workers and limits, monitoring, updates, remote backups, and tested recovery.

Should Odoo proxy mode always be enabled in Docker?

No. Enable proxy_mode only when Odoo is behind a trusted reverse proxy that sets the required forwarding headers. Do not enable it merely because Odoo runs in a container.

What must an Odoo Compose backup contain?

It must contain a recoverable PostgreSQL database and the matching Odoo filestore, plus the configuration, custom addon revisions, image references, and protected secrets information needed to rebuild the stack.

Want a managed stack, not a mystery YAML file?

Odin offers transparent one-click and managed Odoo deployment. We document image policy, data location, proxy, backups, updates, monitoring, and responsibility boundaries before go-live.