--- id: ahmed-lakosha/odoo-plugins/odoo-docker version: "2e26bd82" license: MIT install: manual updated: 2026-03-28 --- # odoo-docker — odoo-docker manages Docker infrastructure for Odoo 14-19 Enterprise deployments, automating production setups with nginx, PostgreSQL, and SSL termination. It generates optimized compose files, handles container troubleshooting, and provides performance tuning recommendations via natural language commands. Publisher: ahmed-lakosha · Stars: 71 · Updated: 2026-03-28 Install (manual): `git clone https://github.com/ahmed-lakosha/odoo-plugins` ## SKILL.md # Odoo Docker Infrastructure Skill ## 1. Overview Docker infrastructure and deployment expert for multi-version Odoo Enterprise environments. Handles production deployment, nginx configuration, CI/CD pipelines, performance tuning, security hardening, and container troubleshooting. > **v2.1**: Nginx config, debugging, and performance tuning are handled via natural language. > For project init, compose generation, deployment, and builds, use `/odoo-docker` sub-commands. ### What This Skill Does - **Production Deployment**: docker-compose with nginx, SSL, PostgreSQL tuning, resource limits, warm-up - **CI/CD Pipelines**: Build and push multi-version Docker images via GitHub Actions - **Performance Tuning**: Data-driven recommendations from real stress tests - **Nginx Configuration**: Optimized configs with gzip (90% CSS reduction), WebSocket, asset caching - **Container Debugging**: Systematic troubleshooting using known issue patterns - **Project Setup**: Auto-detect Odoo version, scan modules, generate all configs + IDE integration - **Compose Generation**: Smart compose for dev/staging/production scenarios - **Image Management**: Build, tag, push images for Odoo 14-19 (amd64 + arm64) ### When to Use This Skill vs `odoo-service` | Use `odoo-service` for... | Use `odoo-docker` for... | |---|---| | Starting/stopping servers | Deploying to production | | Basic `docker up/down/logs` | Configuring nginx reverse proxy | | Database backup/restore | CI/CD pipeline setup | | IDE configuration | Performance analysis & tuning | | Environment initialization | Container debugging & troubleshooting | | Module install/update | Building & pushing Docker images | ### Natural Language Triggers - "deploy to production", "production docker setup", "deploy odoo with nginx" - "configure nginx for odoo", "add reverse proxy", "enable gzip" - "optimize docker performance", "slow containers", "tune workers" - "build docker image", "push to docker hub", "ci/cd pipeline" - "container won't start", "500 errors in docker", "debug container" - "set up docker for this project", "initialize docker environment" - "generate docker-compose", "create compose file" --- ## 2. User Configuration Users can customize this plugin by creating `~/.claude/odoo-docker.local.md` with YAML frontmatter. See `odoo-docker.local.md.example` in the plugin root for the full template. Key settings: - `image_prefix`: Docker Hub org/image prefix (default: `myorg/odoo`) - `default_version`: Default Odoo version when not auto-detected (default: `17`) - `git_org`: GitHub organization for source clone suggestions When generating configs, check for user overrides in `.local.md` first. If not found, use template defaults and prompt the user for their image prefix on first use. --- ## 3. Architecture ### Core Principle: Source Mounted, Not Baked ``` Docker Hub: {image_prefix}:19.0-enterprise (pre-built base image) Workspace: sources/odoo-19/ <-- Odoo Enterprise source (git clone, mounted read-only) projects/relief_center/ <-- Custom modules (git clone, mounted) compose/relief_center.yml <-- Per-project Docker Compose conf/relief_center.conf <-- Per-project Odoo config One image --> Many containers. No rebuilding per project. ``` ### Key Design Decisions 1. **Source code is NOT baked into the image** — mounted at runtime via Docker volumes (read-only) 2. **Two deployment models**: Standalone workspaces (per-version Dockerfile) and centralized workspace (pre-built images from Docker Hub) 3. **Container isolation**: Each project gets its own Docker network, named volumes, port mappings ### Container Directory Structure ``` /opt/odoo/source/ <-- Odoo source (mounted, read-only) /opt/odoo/custom-addons/ <-- Custom modules (mounted) /etc/odoo/odoo.conf <-- Configuration (mounted, read-only) /var/log/odoo/ <-- Log files (mounted) /var/lib/odoo/ <-- Filestore + compiled assets (named volume) ``` ### Exposed Ports | Port | Purpose | |------|---------| | **8069** | HTTP — Odoo web interface | | **8072** | Gevent/Longpolling — WebSocket, live chat, bus | | **5678** | Remote debugger (debugpy, optional) | --- ## 4. Template Files All templates are in `${CLAUDE_PLUGIN_ROOT}/templates/`. Read them with the Read tool when generating configs. | Template | Use For | Key Placeholders | |----------|---------|-----------------| | `docker-compose.dev.yml` | Development compose | `{postgres_image}`, `{version}`, `{project_name}` | | `docker-compose.prod.yml` | Production compose with nginx | + `{odoo_image}` | | `Dockerfile.template` | Building base images | `PYTHON_VERSION`, `ODOO_VERSION` (build args) | | `nginx.conf` | Reverse proxy | `{server_name}` | | `entrypoint.sh` | Container startup script | Environment variables (see section 7) | | `odoo.conf.template` | Odoo configuration | `{project_name}`, `{addons_paths}`, `{gevent_or_longpolling_key}`, `{admin_password}` | | `.env.template` | Environment variables | Copy and customize | ### Placeholder Convention - `{placeholder}` — Must be replaced by the user/skill before use - `${ENV_VAR:-default}` — Resolved automatically by Docker Compose at runtime --- ## 5. Version Matrix Full version matrix is in `${CLAUDE_PLUGIN_ROOT}/reference/version-matrix.md`. Key lookup table: | Version | PostgreSQL | Gevent Key | Entry Point | Python | |---------|-----------|------------|-------------|--------| | 14-16 | postgres:12 | `longpolling_port` | `odoo-bin` | 3.8-3.10 | | 17 | postgres:15 | `gevent_port` | `odoo-bin` | 3.10 | | 18 | postgres:15 | `gevent_port` | `odoo-bin` | 3.11 | | 19 | postgres:15 | `gevent_port` | `setup/odoo` | 3.12 | ### Build Workarounds (Applied Automatically) | Version | Issue | Fix | |---------|-------|-----| | 14 | Buster EOL | archive.debian.org mirrors | | 14-15 | gevent compilation | Cython<3, no-build-isolation | | 16-17 | gevent compilation | Cython<3, no-build-isolation | | 18 | cbor2 build | PIP_CONSTRAINT="setuptools<81" | | 19 | No `__init__.py` | PYTHONPATH=/opt/odoo/source | | All | setuptools 80+ | PIP_CONSTRAINT="setuptools<81" | --- ## 6. Critical Configuration Notes These are the most important settings. Getting any of them wrong causes hard-to-diagnose failures. | Setting | Why It Matters | |---------|---------------| | `data_dir = /var/lib/odoo` | **CRITICAL.** Without this, filestore defaults to `~/.local/share/Odoo/` (ephemeral). JS assets return HTTP 500. | | `workers = 0` | Single-threaded. OK for dev. At 50 users: P50 = 10s, 10% errors. Minimum production: `workers=2`. | | `proxy_mode = True` | Required behind nginx. Without it, IP logging and URL generation are wrong. | | `list_db = False` | Production security. Prevents database name enumeration. | | `gevent_port` vs `longpolling_port` | v14-16: `longpolling_port`. v17+: `gevent_port`. Wrong key = WebSocket broken. | | `db_maxconn = 16` | Without limit, 51+ idle connections accumulate under stress. Pool exhaustion risk. | --- ## 7. Environment Variables ### Entrypoint Variables | Variable | Default | Values | Purpose | |----------|---------|--------|---------| | `DEV_MODE` | `0` | `0`, `1` | Enables `--dev=all` for auto-reload | | `ENABLE_DEBUGGER` | `0` | `0`, `1` | Starts debugpy on port 5678, waits for IDE | | `WAIT_FOR_DB` | `0` | `0`, `1` | Waits up to 30s for PostgreSQL before starting | | `LOG_LEVEL` | (none) | `debug`, `info`, `warn`, `error`, `critical` | Overrides odoo.conf log level | | `ODOO_EXTRA_ARGS` | (none) | Any CLI args | Passed directly to Odoo CLI | ### Port Allocation Convention | Port | Calculation | Project 1 | Project 2 | |------|-------------|-----------|-----------| | HTTP | `HTTP_PORT` | 8069 | 8169 | | Gevent | `HTTP_PORT + 3` | 8072 | 8172 | | Debug | `HTTP_PORT + 609` | 8678 | 8778 | --- ## 8. Performance Tuning ### Workers Configuration | Setting | Response at 50 Users | Use Case | |---------|---------------------|----------| | `workers=0` | P50 = 9,068ms, 10% errors | **Dev only** | | `workers=2` | P50 ~ 800ms | Minimum production | | `workers=4` | P50 ~ 400ms | Heavy load | **Formula:** `workers = (CPU cores * 2) + 1` (capped at available RAM / 512MB per worker) ### PostgreSQL Tuning | Setting | Default | 4 GB RAM | 16 GB RAM | |---------|---------|----------|-----------| | `shared_buffers` | 128 MB | 1 GB | 4 GB | | `work_mem` | 4 MB | 16 MB | 32 MB | | `effective_cache_size` | 4 GB | 3 GB | 12 GB | | `maintenance_work_mem` | 64 MB | 128 MB | 512 MB | | `random_page_cost` | 4.0 | 1.1 | 1.1 | ### Gzip Compression (Nginx) | Configuration | CSS Size | Reduction | |---------------|----------|-----------| | Dev (Werkzeug, no gzip) | 894 KB | — | | Prod (nginx, gzip level 6) | 89 KB | **90%** | ### Asset Warm-Up First request after restart compiles all assets (25-120s). The production compose template includes a warm-up service that pre-loads `/web/login` and `/shop`. --- ## 9. Security Hardening ### High-Risk Issues (Fix Before Production) | Issue | Default | Fix | |-------|---------|-----| | Database enumeration | `list_db = True` | `list_db = False` | | Weak master password | `admin_passwd = 123` | Strong 32+ character password | | No SSL/TLS | Plaintext HTTP | Nginx + Let's Encrypt | | Default DB credentials | `odoo` / `odoo` | Custom credentials per environment | | Proxy mode disabled | `proxy_mode = False` | `proxy_mode = True` behind nginx | ### Volume Security - Odoo source: Always mount `:ro` (read-only) - Config files: Always mount `:ro` - Filestore and logs: Read-write (necessary for operation) ### Network Isolation - Each project gets its own Docker network - Database containers are NOT exposed to host in production - Only nginx exposes ports to the outside --- ## 10. SSL/TLS Configuration For production HTTPS, the nginx template (`${CLAUDE_PLUGIN_ROOT}/templates/nginx.conf`) has commented SSL blocks. Uncomment and configure: ```nginx server { listen 80; server_name yourdomain.com; return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name yourdomain.com; ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; # ... (same location blocks as HTTP config) } ``` Add Let's Encrypt volume to production compose: ```yaml nginx: volumes: - /etc/letsencrypt:/etc/letsencrypt:ro ports: - "443:443" ``` --- ## 11. CI/CD Pipeline ### GitHub Actions Overview - **Triggers:** Push to `main` (Dockerfile/entrypoint/requirements changes) or manual dispatch - **Matrix:** Builds all 6 versions in parallel - **Multi-platform:** `linux/amd64` + `linux/arm64` - **Cache:** GitHub Actions layer cache per version - **Tags:** `{image_prefix}:{version}.0-enterprise` + SHA suffix ### Required Secrets | Secret | Purpose | |--------|---------| | `DOCKERHUB_USERNAME` | Docker Hub login | | `DOCKERHUB_TOKEN` | Docker Hub access token | The full GitHub Actions workflow template is generated by `/odoo-docker build --generate-ci`. --- ## 12. Centralized Multi-Project Workspace ### Layout ``` ~/odoo-docker/ ├── sources/ <-- Git clones of Odoo Enterprise (per version) ├── projects/ <-- Git clones of custom modules (per project) ├── conf/ <-- Generated Odoo configs ├── compose/ <-- Generated Docker Compose files ├── logs/ <-- Runtime logs ├── scripts/ <-- start.sh, stop.sh, logs.sh, shell.sh ├── .env <-- Global config └── .env.local <-- Machine-specific overrides ``` ### Daily Commands ```bash ./scripts/start.sh # Start containers ./scripts/start.sh --dev # Start with auto-reload ./scripts/stop.sh # Stop containers ./scripts/logs.sh # Odoo logs ./scripts/shell.sh 19 # Bash into container ``` ### Running Multiple Projects Assign unique ports per project in `.env`: ```env RELIEF_CENTER_HTTP_PORT=8069 SOQYA_HTTP_PORT=8169 TAQAT_HTTP_PORT=8269 ``` --- ## 13. Database Management in Docker ### Create Database via API ```bash curl -s -X POST http://localhost:8069/web/database/create \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"call","params":{"master_pwd":"changeme","name":"my_db","lang":"en_US","password":"admin","login":"admin"}}' ``` ### Access from Host ```bash psql -h localhost -p 5433 -U odoo -d my_database ``` ### Backup and Restore ```bash docker exec {db_container} pg_dump -U odoo my_database > backup.sql docker exec -i {db_container} psql -U odoo -d my_database < backup.sql ``` --- ## 14. Debugging & Development ### Dev Mode ```bash DEV_MODE=1 docker compose up -d ``` ### Remote Debugger (debugpy) 1. Set `ENABLE_DEBUGGER=1` in `.env` 2. Expose port `5678:5678` in docker-compose 3. Container waits for IDE attach 4. VS Code config: ```json { "name": "Attach to Odoo Docker", "type": "debugpy", "request": "attach", "connect": { "host": "localhost", "port": 5678 }, "pathMappings": [ { "localRoot": "${workspaceFolder}", "remoteRoot": "/opt/odoo/source" } ] } ``` ### Module Management Inside Container ```bash python -m odoo -c /etc/odoo/odoo.conf -d {db} -u {module} --stop-after-init python -m odoo -c /etc/odoo/odoo.conf -d {db} -i {module} --stop-after-init ``` --- ## 15. Troubleshooting For the full troubleshooting reference with all known issue patterns and diagnostic commands, read `${CLAUDE_PLUGIN_ROOT}/reference/troubleshooting.md`. For performance-related patterns and lessons learned from stress tests, read `${CLAUDE_PLUGIN_ROOT}/reference/docker-patterns.md`. For the production deployment checklist, read `${CLAUDE_PLUGIN_ROOT}/reference/production-checklist.md`. --- ## 16. Quick Command Reference ```bash # Build local image docker compose build # Pull pre-built image docker pull {image_prefix}:19.0-enterprise # Start / Stop docker compose up -d docker compose down # Logs / Shell docker compose logs -f odoo docker compose exec odoo bash # Module update inside container python -m odoo -c /etc/odoo/odoo.conf -d {db} -u {module} --stop-after-init ``` [View on SkillFed](https://skillfed.io/ahmed-lakosha/odoo-plugins/odoo-docker) · [View on GitHub](https://github.com/ahmed-lakosha/odoo-plugins)