A reproducible, Dockerised Odoo 18 + PostgreSQL 16 development stack. Clone
it, run one command, and you have a working Odoo with French localization
(l10n_fr) ready to install and a sample custom addon already loaded.
Maintained by Roekish. It is the runnable companion to our Odoo Implementation Playbooks — see the Self-hosted Docker setup guide for the narrative walkthrough and the reasoning behind these choices.
Requires Docker with the Compose plugin (docker compose, v2).
git clone https://github.com/roekish-org/odoo-dev-stack.git
cd odoo-dev-stack
cp .env.example .env # local-only dev credentials; .env is git-ignored
docker compose up -d # or: make upThen open http://localhost:8069. On first run, create a database from the
database manager at /web/database/manager (master password: admin, the
dev-only default in config/odoo.conf).
Prefer a database pre-loaded with French localization? Use the Makefile:
make init-db # creates DB "odoo" with base + l10n_fr (fr_FR)
make up # then browse to http://localhost:8069odoo-dev-stack/
├── docker-compose.yml # Odoo 18 + PostgreSQL 16 services (pinned images)
├── config/odoo.conf # Odoo server config — dev defaults, no secrets
├── .env.example # copy to .env; ports + local DB credentials
├── addons/
│ └── sample_addon/ # minimal installable module (use as a template)
├── scripts/ci_smoke.sh # install + test every addon against the stack
├── Makefile # one-command lifecycle (see `make help`)
└── .github/workflows/ci.yml # lint + install/upgrade smoke on every push
- Credentials never live in tracked files.
config/odoo.confdeliberately omits the DB connection; the Docker entrypoint injectsdb_host/user/passwordfrom theHOST/USER/PASSWORDenv vars indocker-compose.yml, which are sourced from your local.env. The only password in the repo is the documented dev-onlyadmin_passwd = adminfor the database manager. - Pinned images (
odoo:18.0,postgres:16) for reproducible builds. - Named volumes keep the database (
db-data) and filestore (odoo-web-data) across restarts.make destroywipes them.
Run make help for the full list. The essentials:
| Command | What it does |
|---|---|
make up |
Start the stack in the background |
make down |
Stop the stack (keeps data volumes) |
make destroy |
Stop and delete all data (db + filestore volumes) |
make logs |
Follow the Odoo logs |
make init-db |
Create dev DB with base + l10n_fr (French, fr_FR) |
make verify |
Install l10n_fr into a throwaway DB, then drop it |
make ci-smoke |
Install + test every addon (what CI runs) |
make shell |
Bash shell in the running Odoo container |
make psql |
psql against the dev database |
Anything under addons/ is mounted into the container at
/mnt/extra-addons (already on Odoo's addons_path). To start a module, copy
the sample and rename it:
cp -r addons/sample_addon addons/my_module
# rename the model, view ids, manifest "name", etc.
docker compose run --rm odoo odoo -d odoo -i my_module --stop-after-init
make restartCI (scripts/ci_smoke.sh) auto-discovers any directory under addons/ with a
__manifest__.py and verifies it installs and its tests pass — so a fresh clone
is continuously proven to reach a working Odoo.
All tunables live in .env (copy from .env.example):
| Variable | Default | Purpose |
|---|---|---|
COMPOSE_PROJECT_NAME |
odoo-dev |
Prefixes containers/volumes (run many) |
POSTGRES_USER |
odoo |
Local-only dev DB user |
POSTGRES_PASSWORD |
odoo |
Local-only dev DB password |
ODOO_PORT |
8069 |
Host port for the Odoo web/RPC interface |
ODOO_GEVENT_PORT |
8072 |
Host port for websockets / longpolling |
Going to production? These are development defaults. Change
admin_passwd, setlist_db = False, use real secrets, and follow the Playbooks' production hardening guidance. This stack targets local dev.
MIT — the stack tooling. The bundled sample_addon is LGPL-3 (Odoo
module convention; see its __manifest__.py).