Why Docker for Odoo?
Docker provides consistent, reproducible Odoo deployments. The same configuration runs identically on development, staging, and production. Updates are clean: pull the new image, restart, done. Rollbacks are instant: revert to the previous image. Multiple Odoo instances (different versions, different databases) coexist cleanly on the same server.
Docker Compose Setup
# docker-compose.yml
version: '3.8'
services:
odoo:
image: odoo:19
container_name: odoo
restart: unless-stopped
depends_on:
- db
ports:
- "8069:8069"
- "8072:8072"
volumes:
- odoo-data:/var/lib/odoo
- ./custom-addons:/mnt/extra-addons
- ./config/odoo.conf:/etc/odoo/odoo.conf
environment:
- HOST=db
- PORT=5432
- USER=odoo
- PASSWORD=odoo_password
db:
image: postgres:16
container_name: odoo-db
restart: unless-stopped
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=odoo
- POSTGRES_PASSWORD=odoo_password
- PGDATA=/var/lib/postgresql/data/pgdata
volumes:
odoo-data:
postgres-data:Production odoo.conf
[options]
addons_path = /mnt/extra-addons,/usr/lib/python3/dist-packages/odoo/addons
db_host = db
db_port = 5432
db_user = odoo
db_password = odoo_password
db_name = production
# Workers
workers = 5
limit_memory_hard = 2684354560
limit_memory_soft = 2147483648
limit_time_real = 120
limit_time_cpu = 60
# Security
list_db = False
admin_passwd = change_this_to_a_strong_password
dbfilter = ^production$
# Proxy
proxy_mode = True
# Longpolling
gevent_port = 8072
# Logging
log_level = info
logfile = /var/log/odoo/odoo.logNginx Reverse Proxy
# /etc/nginx/sites-available/odoo
upstream odoo {
server 127.0.0.1:8069;
}
upstream odoo-longpolling {
server 127.0.0.1:8072;
}
server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
# Security headers
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header Strict-Transport-Security "max-age=31536000";
# Proxy settings
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Longpolling
location /longpolling {
proxy_pass http://odoo-longpolling;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Block database manager
location /web/database {
deny all;
return 404;
}
# Main application
location / {
proxy_pass http://odoo;
proxy_read_timeout 720s;
proxy_connect_timeout 720s;
proxy_send_timeout 720s;
client_max_body_size 200m;
}
# Static files caching
location ~* /web/static/ {
proxy_pass http://odoo;
expires 7d;
add_header Cache-Control "public, immutable";
}
}Custom Module Deployment
# Directory structure:
./custom-addons/
├── my_module/
│ ├── __manifest__.py
│ ├── __init__.py
│ ├── models/
│ ├── views/
│ └── security/
└── another_module/
# Deploy custom modules:
# 1. Copy modules to custom-addons/
# 2. Restart Odoo
docker compose restart odoo
# 3. Update modules
docker compose exec odoo odoo -d production -u my_module --stop-after-initBackup Automation
#!/bin/bash
# backup.sh — run via cron daily
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR=/opt/backups
# Database backup
docker compose exec -T db pg_dump -U odoo production | gzip > $BACKUP_DIR/db_$DATE.sql.gz
# Filestore backup
docker compose exec -T odoo tar czf - /var/lib/odoo/filestore/production > $BACKUP_DIR/filestore_$DATE.tar.gz
# Upload to S3 (optional)
aws s3 cp $BACKUP_DIR/db_$DATE.sql.gz s3://your-bucket/backups/
aws s3 cp $BACKUP_DIR/filestore_$DATE.tar.gz s3://your-bucket/backups/
# Retention: keep 30 days
find $BACKUP_DIR -mtime +30 -deleteUpdates
# Update Odoo to latest patch
docker compose pull odoo
docker compose up -d odoo
# Update to new version (e.g., 18 → 19)
# 1. Backup
# 2. Change image tag in docker-compose.yml
# 3. docker compose pull
# 4. docker compose up -d
# 5. Run module updatesMulti-Instance Setup
# Run multiple Odoo instances on one server:
# Instance 1: production (port 8069)
# Instance 2: staging (port 8169)
# Use separate docker-compose files or multiple servicesOr Just Use DeployMonkey
All of the above — Docker setup, nginx, SSL, backups, updates, monitoring — is handled automatically by DeployMonkey. Deploy Odoo in 5 minutes without configuring any of this yourself. Free plan available.