| name | odoo-deploy |
| description | Running and deploying Odoo — odoo.conf options, odoo-bin flags, multi-worker + reverse-proxy (nginx websockets), Docker/compose, CI test runs, and DB+filestore backup/restore. Use whenever writing or debugging odoo.conf (addons_path, workers, gevent_port, proxy_mode, limits, dbfilter), choosing odoo-bin flags (-c/-d/-i/-u/--stop-after-init/--dev), setting up dev/staging/prod, wiring nginx for longpolling/websockets, dockerizing Odoo + Postgres, running tests in CI, or backing up/restoring. Verify the config the server actually loaded — don't guess which file or flags are in effect. |
Odoo deployment
A wrong odoo.conf fails quietly: live chat hangs (no websocket route), the wrong DB loads (dbfilter), a worker OOM-kills mid-request, or -u silently reverts prod data. The defaults are fine for --dev, never for production.
The rule: deploy multi-worker behind a proxy with explicit limits, and verify the config the server actually loaded — don't assume a file or flag is in effect.
Targets Odoo 17/18, through Odoo 19 (current LTS). Cross-version option renames: skills/odoo-introspect/references/version-matrix.md.
Task → command/flag
| Task | Command / flag |
|---|
| Run with a config file | odoo-bin -c /etc/odoo/odoo.conf |
| Install a module | odoo-bin -d DB -i my_module --stop-after-init |
| Update a module (runs migrations) | odoo-bin -d DB -u my_module --stop-after-init |
| Update all modules | odoo-bin -d DB -u all --stop-after-init |
| Dev mode: auto-reload + readable assets | odoo-bin -d DB --dev=all (or reload,qweb,xml) |
| One-off shell (introspection) | odoo-bin shell -d DB --no-http |
| Run tests then exit (CI) | odoo-bin -d DB -i my_module --test-enable --test-tags '/my_module' --stop-after-init |
| Don't auto-create/list DBs | --no-database-list + list_db = False |
--stop-after-init makes install/update/test runs exit with a status code instead of serving — essential for CI and scripted upgrades.
odoo.conf — the options that matter
[options]
addons_path = /opt/odoo/addons,/opt/odoo/custom
data_dir = /var/lib/odoo
db_host = 127.0.0.1
db_port = 5432
db_user = odoo
db_password = ****
dbfilter = ^%d$
list_db = False
admin_passwd = ****
workers = 5
max_cron_threads = 1
limit_time_cpu = 60
limit_time_real = 120
limit_memory_soft = ...
limit_memory_hard = ...
limit_request = 8192
proxy_mode = True
gevent_port = 8072
workers = 0 runs the threaded server — fine for dev, never prod (no websocket worker, no memory recycling).
workers > 0 starts a dedicated gevent worker on gevent_port for /websocket/ (live chat, bus, mail).
Reverse proxy — websockets are the trap
Multi-worker Odoo needs the proxy to route normal traffic to 8069 and /websocket/ to the gevent port 8072 — miss the second route and live chat / longpolling / bus hang with no page error.
location /websocket/ { # the route everyone forgets
proxy_pass http://127.0.0.1:8072;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location / { proxy_pass http://127.0.0.1:8069; } # + Host / X-Forwarded-* headers
Pair with proxy_mode = True so Odoo reads the forwarded scheme/host/IP. Full TLS vhost + compose in references/deployment.md.
Environments & CI
| Env | Shape |
|---|
| dev | workers=0, --dev=all, demo data OK, SQLite-free (Postgres always) |
| staging | prod-like config on a restored copy of prod — where you rehearse -u and migrations |
| prod | multi-worker, list_db=False, proxy, backups, no demo data |
CI: install/upgrade + run tests, exit code gates the pipeline (see odoo-testing for tags and the -i clean / -u data matrix):
odoo-bin -d ci_$BUILD -i my_module --test-enable --test-tags '/my_module' \
--stop-after-init --without-demo=False ; echo "exit=$?"
Backup / restore — DB and filestore
Attachments live in data_dir/filestore/<db>, not in Postgres. A pg_dump alone loses every uploaded file.
pg_dump -Fc -U odoo mydb > mydb.dump
tar czf mydb_fs.tgz -C /var/lib/odoo/filestore mydb
The web /web/database/backup (needs admin_passwd) bundles both into one zip — convenient, but memory-heavy on large DBs; prefer pg_dump + filestore tar for big instances.
Hosting model changes the rules — self-hosted vs odoo.sh vs Odoo Online
Everything above is self-hosted (you own odoo.conf, the proxy, the OS). The
two managed platforms remove most of that control — and most of the levers this
skill describes:
| Self-hosted | odoo.sh (PaaS) | Odoo Online (SaaS) |
|---|
| Custom modules | yes | yes (git-deployed) | no (Studio only) |
Shell / odoo-bin | yes | yes (per-branch web shell) | no |
odoo.conf / workers / proxy | you own it | managed | managed |
| How you deploy | -u + restart | git push to a branch | n/a |
| How AI introspects | odoo-bin shell | branch shell or RPC | RPC only |
- odoo.sh: deployment is git push, not
-u. Push to a staging branch
first — odoo.sh builds it on a copy of production and runs your tests; promote
to production only after it's green. You still get a shell per branch, so the
full introspection engine works. The migration rehearsal (odoo-migration)
happens automatically on the staging build — read its log before merging.
- Odoo Online: no custom code, no shell. Introspection falls back to RPC
(→
odoo-introspect references/introspection.md); customization is limited to
Studio + automations. If the task needs a real module, the instance must move
to odoo.sh or self-hosted first — flag that early rather than writing a module
that can't be installed.
See references/odoo-sh.md for the odoo.sh branch model, the git-push deploy
flow, staging rehearsal, and what to check in a build log.
Gotchas that fail silently
workers > 0 but no /websocket/ proxy route → live chat/bus hang with no error in the page.
limit_time_real ≤ limit_time_cpu → requests killed before the CPU budget matters.
proxy_mode = True with no proxy → clients spoof their IP/host.
list_db = True + reachable admin_passwd default → anyone can drop/dump databases.
- Restored DB without its filestore → records exist, every attachment/image 404s.
-u on prod without rehearsing on staging → an unguarded migration reshapes live data irreversibly (see odoo-migration).
- Custom addon not on
addons_path → -i/-u reports "module not found" though the folder is right there.
References & scripts
references/deployment.md — annotated full odoo.conf, complete nginx vhost, docker-compose.yml (odoo + postgres), --dev sub-options, CI script, and the backup/restore runbook.
references/odoo-sh.md — odoo.sh branch model (dev/staging/production), git-push deploy, staging rehearsal of -u/migrations, build-log triage, and the Odoo Online (SaaS) limits.
- Running tests / exit codes / tags:
odoo-testing. What -u will touch before you deploy it: odoo-migration, odoo-data.
- Per-version config option renames (e.g.
longpolling_port → gevent_port): skills/odoo-introspect/references/version-matrix.md.
- Pre-deploy gates:
odoo-ai env-fingerprint + odoo-ai env-diff <dev.json> <prod.json> catch dev-vs-prod drift before you claim production safety; odoo-ai deploy-gate <bundle_dir> aggregates the evidence (native-check / env-diff / scenarios / validate / security / trace / upgrade) into approve / needs-human / block, requiring human sign-off for high-risk models (accounting, stock valuation, payroll, payments, access rules, public controllers).
- CI integration (
references/ci-integration.md): the GitHub Action (.github/workflows/odoo-ai-gate.yml), odoo.sh recipe, Docker + MCP wrappers, and an honest RPC-degraded capability table. odoo-ai evidence <bundle_dir> renders the gate verdict into a PR-comment Markdown — the procurement-friendly "agent-written, tool-verified, human-approved" artifact.