Configuration files
Where they live
/root/.local/share/odoocli/
├── conf/
│ ├── odoo.json the server configuration
│ └── appsettings.json which master-database provider to use
├── data/ container data trees, secrets, the SQLite master database
├── logs/ CLI logs and the audit trail
└── license/ *.lic files, install-id, checkin.receipt, checkin-state.json
Editing it while the API is running changes nothing until you restart odoo-api. Worse, nginx and
Fail2Ban configuration regenerated in the meantime uses the values the API still holds, so the file
on disk and the behaviour on the wire disagree with no error anywhere.
Change it with odoocli server config edit and re-run odoocli server install, or restart
odoo-api afterwards.
odoo.json
Written by odoocli server config create and edited by odoocli server config edit. Hand-editing
is possible and occasionally necessary, but the wizard is the supported path.
{
"id": "6f1c2b90-6a1e-4a5f-9c1a-7a0f2b3c4d5e",
"hostname": "odoo.example.com",
"description": "Primary production host, Frankfurt",
"autoEnrollmentFqdn": "*.odoo.example.com",
"trustedProxies": ["203.0.113.8", "198.51.100.0/24"],
"instanceConfigSource": "Database",
"directoryRoot": "/var/lib/odoo",
"directoryInstanceRoot": "/var/lib/odoo/instances",
"directoryBackup": "/var/backups/odoo",
"directoryArchive": "/var/lib/odoo/archive",
"directoryHostTemp": null,
"management": {
"apiPort": 5210,
"apiBindAddress": "0.0.0.0",
"webPort": 5220,
"webBindAddress": "0.0.0.0",
"webHttps": true
},
"docker": {
"registry": "registry.antelao.io",
"username": null,
"password": null
},
"maxConcurrentJobs": 1,
"keepImageVersions": 3,
"postgresMajorVersion": "17",
"licenseExpiryWarningDays": 30,
"apiKey": "<40-character key, generated by server install>",
"smtpProfile": {
"host": "smtp.example.com",
"port": 587,
"username": "odoo@example.com",
"password": "<secret>",
"from": "odoo@example.com"
},
"fail2BanOptions": {
"whitelist": ["203.0.113.8"],
"blacklist": [],
"banTimeMinutes": 60,
"findTimeMinutes": 10,
"maxRetry": 5,
"notify": ["ops@example.com"]
}
}
The members worth understanding
| Member | Notes |
|---|---|
hostname | Must resolve to this server. Used for the console's own certificate |
autoEnrollmentFqdn | A wildcard such as *.odoo.example.com. Instances under it need no DNS work of their own |
trustedProxies | Addresses or CIDR ranges of a reverse proxy in front of nginx. Leave empty when nginx is the public edge. Getting this wrong makes Fail2Ban ban the wrong address, silently. See Fail2Ban |
instanceConfigSource | Database (default) or Json. Where instance configuration is stored |
directoryBackup | Put this on separate storage if you can. The default keeps backups on the same disk as the data they protect |
maxConcurrentJobs | Default 1, meaning serial. Raising it helps a server with many instances doing independent work; it does not speed up one instance. See Jobs |
keepImageVersions | How many built images per instance to keep before cleanup removes older ones |
licenseExpiryWarningDays | Default 30. 0 turns the warning off, including the daily e-mail |
apiKey | The management API key. server install generates it; server apikey rotate replaces it |
Secrets in this file are real secrets. It lives under a root-only directory; keep it that way, and remember that a copy of it is a copy of your API key and SMTP password.
appsettings.json
Selects the master-database provider. The CLI and the API both read it.
{
"Connection": {
"Default": "SQLite"
}
}
Default is SQLite, PostgreSQL or SqlServer.
# odoocli system database provider# odoocli system database migrate --from SQLite --to PostgreSQLMigrate first, then switch, then restart odoo-api so it picks up the new file. Switching without
migrating points the product at an empty database.
SQL Server is always an external server, and its connection string must be complete. It must never
target the engine's own master database: the application database merely happens to share that
name on the PostgreSQL container.
.env, for the compose deployment
Only relevant if you run the API and Web UI from docker-compose.yml rather than through
server install, which is the development and build-your-own-images path.
# Copy from .env.example. Never commit this file.
# The same value is the API's key (Api:Keys:ui) and the UI's client key (OdooApi:ApiKey).
ODOO_API_KEY=change-me-to-a-long-random-string
Generate a strong value:
openssl rand -base64 48Compose refuses to start if ODOO_API_KEY is unset. Both services use host networking and
bind-mount the host's Docker socket and data trees at identical paths, because the domain layer
writes host paths into the configurations it generates. Changing the mount paths breaks that.
Environment variables
| Variable | Used by | Purpose |
|---|---|---|
ODOO_API_URL | odoocli | Default management API endpoint for remote mode |
ODOO_API_KEY | odoocli, compose | The management API key |
Api__Keys__ui | odoo-api | The API's accepted key, injected by the installer |
OdooApi__ApiKey | odoo-web | The key the console presents |
Global CLI options
Available on every command:
| Option | Meaning |
|---|---|
-v, --verbosity <level> | Log verbosity for this invocation |
-f, --force | Recreate or overwrite instead of reusing what exists |
-y, --yes | Answer confirmations with yes, for unattended use |
--show-secrets | Print credentials unmasked instead of **** |
--server <name|url> | Run against a stored connection or a management API URL |
--token <key> | The API key for remote mode |
--local | Force local execution even when an endpoint is configured |
--error-action <action> | How errors are handled |