Skip to main content

CLI-first Odoo-aware deployment platform for self-hosted Odoo projects

Project description

odooctl

CI License: AGPL v3 Python 3.11+ PRs Welcome

odooctl is a CLI-first, Odoo-aware control plane for self-hosted Odoo on Docker Compose — think open-source Odoo.sh for your own server. It handles the operational lifecycle generic deploy tools miss: verified backups, sanitized staging clones, module updates, rollback, environment promotion, upgrade rehearsal, and health checks, all Odoo- and PostgreSQL-aware. It runs against the compose stack you already have; you keep your server, your data, and your compose files.

Why odooctl

  • Safety by default. Deploys to protected environments take a database + filestore backup first; failed module updates and failed health checks stop the deployment with a non-zero exit.
  • Verify before destroy. Restores land in a temporary database and are only swapped into place after the restore succeeds — a bad backup never destroys a working environment.
  • Staging clones you can trust. odooctl clone production staging sanitizes by default: mail servers, crons, payment providers, queue jobs, OAuth secrets, IAP tokens, and webhook URLs are neutralized — including wiping Odoo 19 WebAuthn passkeys — so staging cannot email customers or charge cards.
  • Adopt what you already run. odooctl import detects an existing compose deployment read-only, previews the generated config, and only writes on --yes — then registers the project, runs preflight checks, and takes a safety backup.
  • Protected environments. Production-tier environments require elevated confirmation for destructive operations, in the CLI, API, and web UI alike.
  • Secrets stay secret. Config references secrets by env-var name only; logs, errors, and streamed operation events are redacted.
  • A local API and web UI, RBAC'd. odooctl serve runs a localhost-only REST API plus a no-build web UI with viewer/operator/admin/owner roles, HMAC bearer tokens, and a privileged runner kept in a separate process.
  • Upgrade rehearsal, not upgrade roulette. odooctl migrate rehearse clones production into a throwaway DB, runs the (OpenUpgrade-backed) upgrade there, health-checks, and writes a report. Production is never touched.

Quickstart

A. Adopt an existing Docker Compose deployment

# Read-only detection and preview — no containers touched, no secrets stored
odooctl import /srv/odoo/acme

# Adopt: write odooctl.yml, register the project, run doctor, take a safety backup
odooctl import /srv/odoo/acme --name acme --yes

# First verified backup, then a sanitized staging environment in one command
odooctl -p acme backup production --verify
odooctl -p acme env create staging --clone-from production

B. Start a fresh project

mkdir acme && cd acme
odooctl setup --name acme --stack odoo-19-community   # or run interactively: odooctl setup

setup scaffolds odooctl.yml from a pinned stack template (secrets referenced by env-var name, never inlined). Edit the domain, database names, and your docker-compose.yml, then:

export ODOO_DB_PASSWORD='a-strong-secret'
odooctl validate
odooctl doctor
odooctl deploy production --branch main

Either way, day-2 operations look like:

odooctl backup production --verify
odooctl clone production staging --sanitize
odooctl update-modules staging --modules sale,stock
odooctl restore staging --backup latest
odooctl rollback production --mode code
odooctl migrate rehearse --env production --to 19.0 --openupgrade
odooctl status

Features

Feature Command(s) Docs
Import / takeover of existing stacks odooctl import docs/getting-started.md
Deploy with pre-deploy backups odooctl deploy docs/deployment.md
Verified backups, safe restores odooctl backup --verify, odooctl restore docs/backup-restore.md
Sanitized staging clones odooctl clone, odooctl env create docs/staging-clone.md, docs/environments.md
Rollback (code or full) odooctl rollback docs/rollback.md
Environment promotion odooctl promote docs/environments.md
Preflight checks odooctl doctor docs/doctor.md
Upgrade rehearsal (17 → 18 → 19) odooctl migrate matrix / scan / rehearse docs/migration.md
Disaster-recovery drills odooctl dr drill docs/disaster-recovery.md
Domains / SSL via reverse proxy odooctl domain docs/domains-ssl.md
Local REST API + operation queue odooctl serve, odooctl runner, odooctl ops docs/api.md
RBAC, tokens, secret store odooctl security docs/rbac.md
Stack / addon catalog odooctl catalog, odooctl setup docs/catalog.md
Scheduled backups / checks odooctl schedule docs/getting-started.md

Web UI

The optional web UI is a no-build vanilla-JS SPA served by the local API:

pip install 'odooctl[api]'
export ODOOCTL_API_KEY="$(python -c 'import secrets; print(secrets.token_hex(32))')"
odooctl serve            # binds 127.0.0.1:8787 by default

Open http://localhost:8787/ and paste a token minted with:

odooctl security token mint --action api --env "*" --project "*" --role operator

The server is localhost-only by design and speaks plain HTTP — do not bind it to a public address; use an SSH tunnel for remote access. The API process never touches Docker or PostgreSQL directly: privileged work is delegated to odooctl runner through a durable queue with short-lived, single-use capability tokens. See docs/web-ui.md and docs/api.md.

How it compares

Compared to Odoo.sh, odooctl is self-hosted and free: your server, your data, no per-worker pricing — with the same core workflow of environments, backups, staging builds, and upgrade testing. Compared to doodba, odooctl is not a project scaffolding framework; it manages the operational lifecycle (backup, clone, restore, promote, rehearse) of whatever compose project you already have — including one built with doodba. Compared to hand-rolled compose scripts, every destructive path here ships with tested safety rails: pre-deploy backups, restore-into-temp-then-swap, sanitization that is on by default, protected-environment confirmation, and secret redaction, backed by 700+ unit tests plus a real-Odoo integration suite.

Supported Odoo versions

Odoo 17, 18, and 19 (Community) are integration-tested: a disposable-stack harness in tests/integration/ runs the full operator lifecycle against real odoo:17/odoo:18/odoo:19 images. See docs/odoo-versions.md for per-version notes.

Install

PyPI publication is coming soon — pipx install odooctl / uv tool install odooctl will work once released. Today, install from source:

git clone https://github.com/odooctl/odooctl && cd odooctl
pipx install .          # or: uv tool install .
odooctl --help

The host also needs Docker Engine with the Compose plugin and tar. With the recommended execution_mode: docker, PostgreSQL client tools run inside your DB container, so the host needs none. See docs/installation.md.

Development

uv venv
uv pip install -e '.[dev]'
pytest -q                              # unit suite
pytest -m integration tests/integration  # opt-in real-Odoo matrix (needs Docker)

Safety defaults

  • Deploys to protected environments create database and filestore backups first.
  • Module-update and health-check failures fail the deployment with a non-zero exit.
  • Restores go into a temporary database and are swapped in only after success.
  • Clone sanitization is on by default and disables mail, fetchmail, crons, payment providers, queue jobs, and automation rules; scrubs OAuth/IAP/webhook credentials; deletes Odoo 19 passkeys; and rewrites and freezes web.base.url.
  • Secrets are referenced via environment variables (password_env) and redacted from logs, errors, and operation events; never commit secret values.
  • The API/runner split is structurally enforced: odooctl security runner-check verifies the API layer imports no privileged adapters.

See docs/security.md for the trust model.

Contributing, security, license

Contributions are welcome — see CONTRIBUTING.md and the Code of Conduct. Good entry points are issues labeled good first issue and help wanted. Report vulnerabilities privately per SECURITY.md.

odooctl is free software, dual-licensed: AGPL-3.0-or-later for open use — including running it commercially for yourself or your clients — with a commercial license available for embedding or reselling it in proprietary products. See LICENSING.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

odooctl-0.2.0.tar.gz (310.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

odooctl-0.2.0-py3-none-any.whl (184.0 kB view details)

Uploaded Python 3

File details

Details for the file odooctl-0.2.0.tar.gz.

File metadata

  • Download URL: odooctl-0.2.0.tar.gz
  • Upload date:
  • Size: 310.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for odooctl-0.2.0.tar.gz
Algorithm Hash digest
SHA256 54fb15417b20d1a3371ac5bfaaaa499a930cdffa425cfc629622deb49638a477
MD5 0c98391264a3ac3391890a596024999c
BLAKE2b-256 366bfa8fd329be04770767e09943cb21386136e7056c3e15004dd327c61cdc38

See more details on using hashes here.

Provenance

The following attestation bundles were made for odooctl-0.2.0.tar.gz:

Publisher: release.yml on odooctl/odooctl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file odooctl-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: odooctl-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 184.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for odooctl-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 95da06676f5a590367b4fd5725b3034dc6792109729e129891554d61accb2e56
MD5 025272347fca1e8548d3edd8e09af69b
BLAKE2b-256 6f5e9a8ba80ecfc79756413e17e5d0b6e456c8c81e242b763698db87e593cdd5

See more details on using hashes here.

Provenance

The following attestation bundles were made for odooctl-0.2.0-py3-none-any.whl:

Publisher: release.yml on odooctl/odooctl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page