Docker is the smoothest way to run Odoo, whether for development or production. The official Docker image works, but for a real setup you need to customize it.
docker-compose.yml
Two services: Odoo and PostgreSQL. The Odoo image is based on odoo:18. PostgreSQL 17 for the database. Volumes for data persistence: PostgreSQL data and Odoo filestore. Expose port 8069 (or put it behind Nginx).
Custom Dockerfile
Base on the official image. Install extra Python packages with pip (requests, beautifulsoup4, Pillow, etc). Copy in your odoo.conf. Mount your addons folder to /mnt/extra-addons. This gives you a reproducible environment that everyone on the team can run identically.
Configuration
odoo.conf: addons_path, db_host (the PostgreSQL service name in docker-compose), admin_passwd, workers (0 for development, 4+ for production). Limit_memory_hard and limit_memory_soft prevent a single process from eating all memory.
Production
Nginx in front of Odoo as reverse proxy. SSL with Let's Encrypt. Workers set to at least CPU count times 2 plus 1. Longpolling port (8072) behind a separate upstream in Nginx. Gzip enabled. Static files served directly by Nginx instead of through Odoo.
Backup
PostgreSQL dump via pg_dump in cron. Filestore copied separately (it's a plain file directory). Automate to external storage (S3, Backblaze B2). Test restore quarterly.
Upgrade
Change Docker tag in Dockerfile (odoo:17 to odoo:18). Run odoo --update all against the database. Test in staging. It's simpler with Docker than with a traditional installation.