Why Docker for Odoo?
Docker simplifies Odoo deployment: consistent environments, easy version upgrades, isolated services, and reproducible setups. Docker Compose orchestrates Odoo + PostgreSQL + nginx as a single stack.
Production docker-compose.yml
version: '3.8'
services:
odoo:
image: odoo:19
container_name: odoo
depends_on:
db:
condition: service_healthy
ports:
- "127.0.0.1:8069:8069"
- "127.0.0.1:8072:8072"
volumes:
- odoo-data:/var/lib/odoo
- ./config/odoo.conf:/etc/odoo/odoo.conf:ro
- ./custom-addons:/mnt/extra-addons
- ./logs/odoo:/var/log/odoo
environment:
- HOST=db
- USER=odoo
- PASSWORD=odoo_db_password
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8069/web/health"]
interval: 30s
timeout: 10s
retries: 3
db:
image: postgres:16-alpine
container_name: postgres
volumes:
- pg-data:/var/lib/postgresql/data
- ./config/postgresql.conf:/etc/postgresql/postgresql.conf:ro
environment:
- POSTGRES_DB=odoo
- POSTGRES_USER=odoo
- POSTGRES_PASSWORD=odoo_db_password
command: postgres -c config_file=/etc/postgresql/postgresql.conf
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U odoo"]
interval: 10s
timeout: 5s
retries: 5
nginx:
image: nginx:alpine
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./config/nginx.conf:/etc/nginx/conf.d/default.conf:ro
- ./certbot/conf:/etc/letsencrypt:ro
- ./certbot/www:/var/www/certbot:ro
depends_on:
- odoo
restart: unless-stopped
certbot:
image: certbot/certbot
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h; done'"
volumes:
odoo-data:
pg-data:Directory Structure
odoo-production/
├── docker-compose.yml
├── config/
│ ├── odoo.conf
│ ├── postgresql.conf
│ └── nginx.conf
├── custom-addons/
│ └── my_module/
├── logs/
│ └── odoo/
├── certbot/
│ ├── conf/
│ └── www/
└── backups/odoo.conf for Docker
[options]
addons_path = /mnt/extra-addons,/usr/lib/python3/dist-packages/odoo/addons
data_dir = /var/lib/odoo
db_host = db
db_port = 5432
db_user = odoo
db_password = odoo_db_password
db_name = odoo
list_db = False
proxy_mode = True
workers = 5
limit_memory_hard = 2684354560
limit_memory_soft = 2147483648
limit_time_real = 120
limit_time_cpu = 60
logfile = /var/log/odoo/odoo.log
log_level = infoDeployment Commands
# Start all services
docker compose up -d
# View logs
docker compose logs -f odoo
# Install/update a module
docker compose exec odoo odoo -d odoo -i my_module --stop-after-init
docker compose exec odoo odoo -d odoo -u my_module --stop-after-init
# Backup database
docker compose exec db pg_dump -U odoo odoo | gzip > backups/odoo_$(date +%Y%m%d).sql.gz
# Restore database
gunzip -c backups/odoo_20260322.sql.gz | docker compose exec -T db psql -U odoo odoo
# Upgrade Odoo version
docker compose pull odoo
docker compose up -d odooSSL with Let's Encrypt
# Initial certificate
docker compose run --rm certbot certonly \
--webroot --webroot-path=/var/www/certbot \
-d your-domain.com \
--email [email protected] \
--agree-tos --no-eff-email
# Reload nginx after certificate
docker compose exec nginx nginx -s reloadCommon Issues
| Issue | Cause | Fix |
|---|---|---|
| Odoo can't connect to DB | PostgreSQL not ready yet | Use depends_on with health check condition |
| Permission denied on volumes | UID mismatch | Match container user to volume ownership |
| Slow file operations | Volume driver overhead | Use named volumes, not bind mounts for data |
| Can't reach Odoo externally | Bound to 127.0.0.1 | Access via nginx on ports 80/443, not 8069 directly |
DeployMonkey
DeployMonkey deploys Odoo using Docker Compose with all of the above configured automatically — optimized PostgreSQL, nginx with SSL, health checks, log rotation, and automated backups. One click, production-ready.