Odoo 20 配置参数详解
Odoo 20 社区版 odoo.conf 逐节详解:参数加载与覆盖优先级、全参数默认值(config.py my_default 取证)、admin_passwd/list_db/dbfilter 实测语义(403/AccessDenied/锁库路由/CSRF 强制)、多进程 workers 与 limit_* 系列官方计算公式、日志与 SMTP 参数、环境变量对照与生产配置模板。
Odoo 20 配置参数详解
目标:把 Odoo 20 社区版服务端的
odoo.conf配置体系逐项讲透——参数如何加载与覆盖、每个核心参数的真实默认值与实测行为、多进程模型与资源限制的计算依据、多数据库与dbfilter路由语义、环境变量对照与生产配置模板。全部参数默认值取自 Odoo 20 服务端源码odoo/tools/config.py,全部行为结论来自 2026-10-27 在 Ubuntu 22.04 上的真实实测。部署过程见 《Odoo 20 Docker Compose 部署实战》,命令行操作见 《Odoo 20 常用命令与运维实战》。
一、环境信息
- 操作系统:Ubuntu 22.04(x86_64,真实服务器视角)
- Odoo:社区版 Odoo Server 20.0-20261015(
odoo --version实测回显),以 deb 包形态安装、systemd 服务odoo.service托管 - 数据库:PostgreSQL 17(与 Odoo 同机部署,监听 5432)
- 配置文件:
/etc/odoo/odoo.conf(deb 包安装的默认配置路径) - 服务端口:HTTP 8069(默认)、WebSocket/长轮询 8072(默认)
- 实测账号:PostgreSQL 角色
odoo/odoo20pg;Odoo 应用管理员admin/q1w2e3r4(演示口令);数据库管理器主控口令实测值q1w2e3r4 - 实测数据库:
odoo20main(空库)、odoo20demo(演示数据库,已安装 CRM/库存)、odoo20restore(备份恢复库)、odoo20clirestore(CLI 恢复库)
二、前置条件
-
服务器上已有一套可运行的 Odoo 20(deb 包安装或源码运行均可),且
odoo --version能正常回显版本:odoo --version实测回显:
Odoo Server 20.0-20261015 -
已知配置文件位置。Odoo 按以下顺序确定配置文件(找到即用,找不到则以内置默认值运行):
- 命令行
--config=/path/to/odoo.conf(优先级最高); - 环境变量
ODOO_RC指定的路径; ~/.odoorc(用户级默认,老版本兼容~/.openerp_serverrc)。
- 命令行
-
服务重启方式(deb 安装形态):
sudo systemctl restart odoo配置文件修改后必须重启服务才生效;验证服务状态:
systemctl is-active odoo预期回显(正常运行时):
active -
数据库管理器的验证走 HTTP 接口(本篇所有接口验证均以服务监听 8069 为前提):
curl -sI http://127.0.0.1:8069/web/database/selector | head -1实测回显:
HTTP/1.1 200 OK
三、参数查看与修改方式
配置参数的「查看—修改—验证」闭环是配置运维的基本功。Odoo 20 的参数有四个来源层次:源码内置默认值 → 配置文件 odoo.conf → 命令行参数 → 环境变量(仅部分数据库参数)。本节先建立这个认知,再逐层展开。
3.1 查看全部参数与默认值
odoo --help 只输出子命令清单,服务端参数要通过 odoo server --help 查看:
odoo server --help | head -20
实测回显(节选,实测首尾):
Usage: odoo [options]
Odoo Server version 20.0-20261015
Options:
--version show program's version number and exit
-h, --help show this help message and exit
Common options:
-c PATH, --config=PATH
specify alternate config file
--save save configuration to ~/.odoorc (or to
~/.openerp_serverrc if it exists)
-i MODULE,..., --init=MODULE,...
install one or more modules (comma-separated list, use
"all" for all modules), requires -d
-u MODULE,..., --update=MODULE,...
帮助文本不显示默认值。Odoo 20 的权威默认值在源码 odoo/tools/config.py 中,每个选项的 my_default 即真实默认值。检索方式(服务器上按 deb 包路径):
grep -n 'my_default' /usr/lib/python3/dist-packages/odoo/tools/config.py | head -20
实测回显(节选,实测首尾):
230: parser.add_option(FileOnlyOption(dest='admin_passwd', my_default='admin'))
289: group.add_option("--http-interface", dest="http_interface", my_default='127.0.0.1',
291: group.add_option("-p", "--http-port", dest="http_port", my_default=8069,
293: group.add_option("--gevent-port", dest="gevent_port", my_default=8072,
297: group.add_option("--proxy-mode", dest="proxy_mode", action="store_true", my_default=False,
425: group.add_option("--db_maxconn", dest="db_maxconn", type='int', my_default=64,
477: group.add_option("--max-cron-threads", dest="max_cron_threads", my_default=2,
495: "--workers", dest="workers", my_default=0,
💡 技术拓展:服务端配置的四种载体对比——
载体 生效范围 优先级 适用场景 源码默认值 全局 最低 兜底行为 配置文件 odoo.conf 全局持久 中 生产标准做法 命令行参数 当次进程 高 一次性实验/调试 环境变量 当次进程 低于配置文件 编排注入(仅 PG* 等少数项) 本文生产实践以配置文件为唯一事实源:配置文件可版本化管理、可审计,命令行参数仅用于临时验证,避免「改了配置不生效」或「命令行覆盖遗忘」两类排查陷阱。
3.2 配置文件格式与修改生效
odoo.conf 是 INI 格式,所有服务端参数都放在 [options] 节内,键名用下划线风格(与命令行 --db-host 对应为 db_host)。实测当前生效的配置:
cat /etc/odoo/odoo.conf
实测回显:
[options]
addons_path = /mnt/extra-addons
data_dir = /var/lib/odoo
http_interface = 0.0.0.0
db_host = db
db_port = 5432
db_user = odoo
db_password = odoo20pg
workers = 2
limit_time_cpu = 30
limit_time_real = 60
limit_memory_soft = 1073741824
limit_memory_hard = 1610612736
limit_request = 8192
max_cron_threads = 1
admin_passwd = q1w2e3r4
逐项说明:数据库连接四项(db_host/db_port/db_user/db_password)指向 PostgreSQL 实例;http_interface = 0.0.0.0 放开对外监听(Odoo 20 默认只听 127.0.0.1,这是本专栏部署篇实测确认过的 Odoo 20 关键变化);workers = 2 开启多进程模式(见 5.6 节);limit_* 系列限制单请求资源;admin_passwd 是数据库管理器主控口令(见 5.2 节)。
修改后重启服务生效,服务启动日志会回显加载的配置文件与解析出的关键值:
sudo systemctl restart odoo && sudo journalctl -u odoo -n 8 --no-pager
实测回显(日志关键行):
2026-10-27 15:25:12,448 1 INFO ? odoo: Using configuration file at /etc/odoo/odoo.conf
2026-10-27 15:25:12,448 1 INFO ? odoo: addons paths: _NamespacePath(['/usr/lib/python3/dist-packages/odoo/addons', '/var/lib/odoo/addons/20.0', '/mnt/extra-addons'])
2026-10-27 15:25:12,448 1 INFO ? odoo: database: odoo@db:5432
2026-10-27 15:25:12,671 1 INFO ? odoo.service.server: HTTP service running on 0.0.0.0:8069
这四行是配置生效的快速核对点:第一行确认加载的就是目标文件,第二行确认 addons_path 解析结果,第三行确认数据库连接(格式 用户@主机:端口),第四行确认监听地址端口。
3.3 命令行覆盖与 --save 回写
命令行参数优先于配置文件。例如配置文件已设 db_host = db,命令行临时改连另一实例:
odoo -c /etc/odoo/odoo.conf --db-host=192.168.1.50 --stop-after-init --no-http
--save 参数可把当前生效的全部参数(含命令行覆盖后的值)写回 ~/.odoorc,适合把调好的命令行组合固化成配置底稿再手工合并。
四、参数总览
Odoo 20 服务端参数按 server --help 的分组可归纳为九组,下表给出各组核心参数、真实默认值(源码 my_default 取证)与一句话作用。默认值列的布尔值以源码为准:
| 分组 | 参数 | 默认值 | 作用 |
|---|---|---|---|
| 数据库连接 | db_host | 空(本机 socket) | PostgreSQL 地址 |
db_port | 空(5432) | PostgreSQL 端口 | |
db_user / db_password | 空 / 空 | 连接角色与口令 | |
db_maxconn | 64 | 单进程连接池上限 | |
db_sslmode | prefer | 与 PostgreSQL 的 SSL 模式 | |
db_template | template0 | 建库模板 | |
| 数据库管理器 | admin_passwd | admin | 管理器主控口令(只能配置文件设置) |
list_db | True | 是否允许列出数据库 | |
dbfilter | 空(不过滤) | 数据库路由正则 | |
| HTTP 服务 | http_interface | 127.0.0.1 | 监听网卡(Odoo 20 关键变化) |
http_port | 8069 | HTTP 端口 | |
gevent_port | 8072 | WebSocket/长轮询端口 | |
proxy_mode | False | 反向代理模式 | |
x_sendfile | False | X-Sendfile 静态加速 | |
| 多进程 | workers | 0(多线程模式) | HTTP worker 进程数 |
max_cron_threads | 2 | cron 线程数 | |
limit_memory_hard | 2684354560(2560MiB) | worker 内存硬限(字节) | |
limit_memory_soft | 2147483648(2048MiB) | worker 内存软限(字节) | |
limit_time_cpu | 60 | 单请求 CPU 时间上限(秒) | |
limit_time_real | 120 | 单请求真实时间上限(秒) | |
limit_time_real_cron | -1(随 limit_time_real) | cron 任务真实时间上限 | |
limit_request | 65536 | worker 处理请求数后重生 | |
| 模块加载 | addons_path | 内置路径 | 模块搜索路径(逗号分隔) |
server_wide_modules | base,web | 常驻加载模块(--load) | |
data_dir | 系统 XDG 数据目录 | filestore/session 根目录 | |
| 日志 | logfile | 空(stdout) | 日志文件路径 |
log_level | info | 日志级别 | |
log_handler | :INFO | 按模块定制级别 | |
syslog | False | 输出到 syslog | |
log_db / log_db_level | 空 / warning | 写入数据库的日志 | |
| 邮件 | smtp_server / smtp_port | localhost / 25 | SMTP 服务器 |
smtp_user / smtp_password | 空 / 空 | SMTP 认证 | |
smtp_ssl | False | SMTPS | |
email_from / from_filter | 空 / 空 | 发件地址与过滤 | |
| 翻译与导入 | overwrite_existing_translations | False | 覆盖既有翻译(--i18n-overwrite) |
import_file_maxbytes | 10485760(10MiB) | CSV 导入文件上限 | |
import_partial | 空 | 大导入断点文件路径 | |
| 开发与杂项 | dev_mode | 空 | 开发模式(--dev) |
osv_memory_count_limit | 0(不限制) | 瞬态记录数上限 | |
transient_age_limit | 1.0(小时) | 瞬态记录存活期 | |
websocket_keep_alive_timeout | 3600 | WebSocket 保活(秒) | |
publisher_warranty_url | http://services.odoo.com/publisher-warranty/ | 版本校验上报地址 |
表格解读:日常生产调参集中在「数据库连接、数据库管理器、HTTP 服务、多进程、日志」五组;邮件组在配置出站邮件时必碰;翻译与杂项组多数场景保持默认。下文按组逐项展开实测行为。
五、核心参数分类详解
5.1 数据库连接参数
Odoo 绑定 PostgreSQL(不支持 MySQL/MariaDB),连接参数六件套是所有部署的第一组必配项:
| 参数 | 实测取值 | 说明 |
|---|---|---|
db_host | db | 空 = 本机 UNIX socket(deb 同机部署默认);远程/容器网络填主机名或 IP |
db_port | 5432 | 空 = 5432 |
db_user | odoo | deb 包安装时安装脚本自动创建的数据库角色同名 |
db_password | odoo20pg | 该角色的口令 |
db_sslmode | 未设置(默认 prefer) | 可选 disable/allow/prefer/require/verify-ca/verify-full(Odoo 11.0 起支持) |
db_maxconn | 未设置(默认 64) | 单进程 PostgreSQL 连接池上限 |
两个实测佐证:其一,连接池行为可见于 DEBUG 日志(log_handler = odoo.sql_db:DEBUG 时),连接池的 max=64 即 db_maxconn 默认值,连接串里的 sslmode=prefer 即 db_sslmode 默认值:
2026-10-27 15:24:08,781 331 DEBUG odoo20restore odoo.sql_db.connection: ConnectionPool(read/write;used=2/count=2/max=64) Give back connection to 'user=odoo password=xxx dbname=odoo20restore host=db port=5432 application_name=odoo-331 sslmode=prefer'
其二,application_name=odoo-{pid} 是 db_app_name 参数的默认格式(odoo-{pid}),PostgreSQL 侧 pg_stat_activity 可据此区分连接来自哪个 Odoo 进程——多进程模式下排查连接归属时非常实用。
容量关系:db_maxconn 是单进程上限,总连接数 ≈ db_maxconn × (workers + cron 线程 + 1 个 gevent)。PostgreSQL 默认 max_connections = 100,官方部署文档的同机示例将 PostgreSQL max_connections 调到 80 并以此约束 worker 数量——调大 workers 时务必同步核算连接总数,避免 PostgreSQL 拒连。
5.2 数据库管理器与 admin_passwd
/web/database/manager 提供建库、删库、备份、恢复、复制等全部破坏性操作,其防护就是 admin_passwd(主控口令)。官方文档明确:该参数只能通过配置文件设置("This setting can only be set using configuration files"),命令行参数无效,这是它与其他参数的重要差异。
默认值 admin 意味着「装完即裸奔」:任何能访问 8069 端口的人都能用默认口令建库删库。实测把主控口令改为 q1w2e3r4 后,旧口令的建库请求被拒绝:
curl -s -X POST http://127.0.0.1:8069/web/database/create \
-d 'master_pwd=admin&name=badtest&login=admin&password=q1w2e3r4&phone=&lang=zh_CN&country_code=CN&demo=false' \
-o /dev/null -w 'HTTP %{http_code}\n'
实测回显:
HTTP 403
403 页面为建库表单重新渲染并提示 Master Password 错误;改用正确口令 master_pwd=q1w2e3r4 则返回 303 建库成功(本专栏部署篇已实测)。生产环境的第一动作就是设置强 admin_passwd。
与 admin_passwd 配套的是 list_db(默认 True)。设为 False 后(等价命令行 --no-database-list)数据库列表接口被整体禁用,实测 JSON-RPC 调用返回明确的拒绝消息:
curl -s -X POST http://127.0.0.1:8069/web/database/list \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"call","params":{"master_pwd":"q1w2e3r4"}}'
实测回显:
{"jsonrpc": "2.0", "id": null, "error": {"code": 0, "message": "Odoo Server Error", "data": {"name": "odoo.exceptions.AccessDenied", "message": "Database management functions blocked, admin disabled database listing.", "arguments": ["Database management functions blocked, admin disabled database listing."], "timestamp": 1793114793, "context": {}, "debug": "odoo.exceptions.AccessDenied: Database management functions blocked, admin disabled database listing.\n"}}
同时 /web/database/selector 页面返回 200 但选择器已被禁用(页面表单标记 disabled)。多库生产服务器官方推荐组合就是:dbfilter 锁库 + list_db = False 禁列库 + 屏蔽数据库管理界面(官方原话:"it is strongly recommended to block access to the database manager screens, and to use the --no-database-list startup parameter")。
顺带一个 Odoo 20 的接口形态实测发现:用表单方式(Content-Type: application/x-www-form-urlencoded)调 JSON-RPC 端点会命中新的类型路由检查:
curl -s -X POST http://127.0.0.1:8069/web/database/list -d 'master_pwd=q1w2e3r4' -w '\nHTTP %{http_code}\n' | head -5
实测回显:
<!doctype html>
<html lang=en>
<title>415 Unsupported Media Type</title>
<h1>Unsupported Media Type</h1>
<p>Request inferred type is compatible with ['http'] but '/web/database/list' is type='jsonrpc'.<br><br>Please verify the Content-Type request header and try again.</p>
写脚本对接数据库管理器时必须带 Content-Type: application/json,否则收到 415 而非业务结果。
5.3 多数据库与 dbfilter
一个 Odoo 服务可同时管理多个数据库(每个库是独立租户:独立应用清单、用户与业务数据),dbfilter 决定「当前请求路由到哪个库」。它支持两个动态占位符:%h = 请求域名(去端口、去 www.),%d = 域名第一段子域。
官方配置示例(照录自官方部署文档):
# 只显示 mycompany 开头的库
dbfilter = ^mycompany.*$
# 按第一段子域路由(如 www2.mycompany.com → www2 库)
dbfilter = ^%d$
官方还强调:使用 website 模块的多库生产服务器 必须 设置 dbfilter,否则未登录访客(门户/网站页)无法确定库,相关功能将不能正常工作。
实测语义验证(这是本篇最重要的实测结论):服务器上已有 4 个库(odoo20main/odoo20demo/odoo20restore/odoo20clirestore),设置 dbfilter = ^odoo20demo 并重启后——
-
匹配库登录正常(先 GET
/web/login建立会话并获取 CSRF token,再带 token POST):curl -s -c /tmp/odoo-cj.txt http://127.0.0.1:8069/web/login > /dev/null CSRF=$(grep -oE 'csrf_token: "[^"]+"' /tmp/odoo-cj.txt | head -1) curl -s -b /tmp/odoo-cj.txt -o /dev/null -D - -X POST http://127.0.0.1:8069/web/login \ --data-urlencode "csrf_token=$(echo $CSRF | sed 's/.*"\(.*\)"/\1/')" \ -d 'db=odoo20demo&login=admin&password=q1w2e3r4' | grep -iE '^HTTP|^location'实测回显:
HTTP/1.1 303 SEE OTHER location: /odoo -
dbfilter 之外显式指定的库也会被路由进匹配库。用
db=odoo20main(不匹配^odoo20demo)重复上述登录,响应同为 303 →/odoo,而服务日志显示两次请求实际都落在odoo20demo:2026-10-27 15:28:48,484 16 INFO odoo20demo odoo.http.server: 10.89.64.1 I3KgXUIM - [27/Oct/2026 15:28:48] "POST /web/login HTTP/1.1" 303 197 23 0.043 0.269 rw 2026-10-27 15:29:06,328 16 INFO odoo20demo odoo.http.server: 10.89.64.1 oPb6qkoX - [27/Oct/2026 15:29:06] "POST /web/login HTTP/1.1" 303 197 14 0.006 0.253 rw日志第三列的库名均为
odoo20demo——dbfilter的本质是请求级数据库路由器:源码odoo/http/router.py的db_filter()先按正则(含%h/%d展开)过滤可用库集合,路由取过滤结果的第一个;会话中已存的库若不匹配过滤也会被登出重选。它不是安全边界——库级访问控制要靠 PostgreSQL 角色权限与网络层。 -
锁库后登录 POST 强制要求 CSRF token。不带 token 直接 POST(部署篇部署时可行的写法)此时报 400:
400 Bad Request Session expired (invalid CSRF token)原因:filter 锁定唯一库后,GET 登录页即绑定库并颁发 CSRF token,POST 必须携带。多库无 filter 时首跳 POST 可免 token(部署篇实测 303),锁库后该捷径失效——脚本对接多租户环境要先 GET 建 session。
💡 技术拓展:多租户库路由的常见模式对比——
模式 dbfilter 写法 适用 单库直连 不设置(默认) 服务器只有一个业务库 前缀匹配 ^customer.*$一台服务器多客户库、按名分流 子域路由 ^%d$SaaS 化:a.example.com → a 库 整域路由 ^%h$库名与完整域名一致的场景 本文实测采用前缀匹配
^odoo20demo,因为它能最直观地暴露「过滤集合 + 取首个」的路由语义;生产 SaaS 场景选子域路由%d,与域名规划天然对齐。
5.4 addons_path 与 data_dir
addons_path 是模块搜索路径(逗号分隔多个目录),data_dir 是 filestore(附件/图片二进制)、session、自动下载模块的根目录。二者是自定义模块开发与数据备份定位的基础。
实测要点:
-
内置路径自动存在。即使
addons_path只写一个自定义目录,服务日志显示最终搜索路径是内置路径与自定义路径的合集:2026-10-27 15:25:12,448 1 INFO ? odoo: addons paths: _NamespacePath(['/usr/lib/python3/dist-packages/odoo/addons', '/var/lib/odoo/addons/20.0', '/mnt/extra-addons'])三段含义:核心框架模块(deb 包随 Python 库安装)、
data_dir/addons/<版本>(网页端「应用」里下载的第三方模块落点)、自定义模块目录。 -
无效目录告警不阻断。目录存在但没有有效模块(缺
__manifest__.py)时,启动日志出现两行告警:2026-10-27 15:25:12,936 17 WARNING ? odoo.tools.config: option addons_path, invalid addons directory '/mnt/extra-addons', skipped服务照常启动运行;放入有效模块后告警消失。排查「自定义模块不出现」问题时先看这两行。
-
filestore 与数据库必须成对备份。
data_dir下的filestore/<库名>/存放该库全部附件二进制,只备份数据库 dump 不带 filestore 会丢附件(数据库管理器/CLI 的 zip 备份格式之所以「filestore-aware」正为此,见命令篇实测)。
5.5 HTTP 服务参数
| 参数 | 默认值 | 实测说明 |
|---|---|---|
http_interface | 127.0.0.1 | Odoo 20 关键变化:旧版本默认 0.0.0.0,20 改为仅本机回环;对外提供服务必须显式 0.0.0.0(源码 config.py 289 行 my_default='127.0.0.1',且配置留空时代码兜底强制回环,本专栏部署篇实测定位) |
http_port | 8069 | 改端口时注意 --http-port 同名覆盖 |
gevent_port | 8072 | 多进程模式下 LiveChat/WebSocket 专用 worker 的监听端口,启动日志实测:GeventServer: Evented/WebSocket service running on 0.0.0.0:8072 |
proxy_mode | False | 只应在反向代理之后启用:开启后 Odoo 信任 X-Forwarded-Host/X-Forwarded-Proto 等头,还原真实客户端 IP 与协议。无反代直开会导致 IP/协议失真 |
x_sendfile | False | 反代支持 X-Sendfile/X-Accel-Redirect 时静态文件交给代理直传,减轻应用进程 IO |
http_enable | True | --no-http 关闭 HTTP(CLI 管理命令场景,命令篇实测) |
多进程模式下反代的分工(官方部署文档):HTTP 请求全部走 8069 常规 worker,路径以 /websocket/ 开头的请求需由反代单独转发到 8072 的 gevent worker,同时开启 proxy_mode。这套组合是 Odoo 生产 HTTPS 架构的标准形态。
5.6 多进程 workers 与 limit_* 系列
Odoo 服务端有两种运行模型,workers 参数是开关:
| 模型 | 触发条件 | 特征 | 适用 |
|---|---|---|---|
| 多线程 | workers = 0(默认) | 单进程,每请求一线程,受 Python GIL 限制 | 开发/演示/极小规模 |
| 多进程 | workers > 0 | prefork 模型:HTTP worker 进程池 + 独立 gevent 进程(8072)+ cron 进程,配有进程收割器(process reaper)监控资源、杀掉并重启失控 worker | 生产(Windows 不可用) |
实测 workers = 2、max_cron_threads = 1 的多进程启动形态(日志 + 进程两个视角):
2026-10-27 15:25:12,671 1 INFO ? odoo.service.server: HTTP service running on 0.0.0.0:8069
2026-10-27 15:25:12,673 14 INFO ? odoo.service.server.WorkerHTTP: Alive
2026-10-27 15:25:12,675 16 INFO ? odoo.service.server.WorkerHTTP: Alive
2026-10-27 15:25:12,677 19 INFO ? odoo.service.server.WorkerCron: Alive
2026-10-27 15:25:13,183 17 INFO ? odoo.service.server.GeventServer: Evented/WebSocket service running on 0.0.0.0:8072
UID PID COMMAND
odoo 1 /usr/bin/python3 /usr/bin/odoo
odoo 14 /usr/bin/python3 /usr/bin/odoo
odoo 16 /usr/bin/python3 /usr/bin/odoo
odoo 17 /usr/bin/python3 /usr/bin/odoo gevent
进程清单与日志一一对应:PID 1 主进程(prefork 管理者),14/16 两个 HTTP worker(workers = 2),17 是 gevent 专用进程(gevent_workers 默认 1),19 为 cron 进程(内部跑 max_cron_threads = 1 个线程)。workers = 0 时这组 WorkerHTTP/WorkerCron 日志不会出现,全部请求在同一进程内——这是判断当前运行模型最直接的证据。
worker 数量计算(官方部署文档经验公式,照录):
- 经验法则:
workers = (CPU 核数 × 2) + 1; - cron worker 也要占 CPU(
max_cron_threads计入资源预算); 1 worker ≈ 6 个并发用户。
内存计算(官方文档模型):按 20% 重请求/80% 轻请求假设,重 worker 峰值约 1GB、轻 worker 约 150MB:
Needed RAM = #worker × (light_worker_ratio × light_worker_ram_estimation
+ heavy_worker_ratio × heavy_worker_ram_estimation)
官方给的标准算例(4 CPU / 8 线程服务器,60 并发用户):60 / 6 = 10 个 worker(并发需求)、(4 × 2) + 1 = 9 个 worker(CPU 上限),取 8 worker + 1 cron;内存 9 × (0.8 × 150 + 0.2 × 1024) ≈ 3GB。
limit_* 系列逐项(默认值取自源码,行为取自源码 help 文本与实测日志):
| 参数 | 默认值 | 行为 |
|---|---|---|
limit_memory_soft | 2147483648(2048MiB) | worker 虚拟内存软限:超限后当前请求完成后 worker 自杀重生 |
limit_memory_hard | 2684354560(2560MiB) | worker 虚拟内存硬限:超限后任何内存分配立即失败 |
limit_time_cpu | 60 | 单请求 CPU 时间上限(秒),超时 worker 被收割器终止 |
limit_time_real | 120 | 单请求墙钟时间上限(秒) |
limit_time_real_cron | -1(随 limit_time_real) | cron 任务墙钟上限;0 = 不限时 |
limit_request | 65536 | worker 累计处理请求数达到后主动重生(防内存碎片累积) |
实测佐证:把 limit_time_real = 60 后,一个长跑 cron 任务被收割器按 60 秒上限终止,日志留下明确的超时记录(真实回显):
2026-10-27 15:26:16,306 1 ERROR ? odoo.service.server.PreforkServer: WorkerCron (19) timeout after 60s
PreforkServer: WorkerXXX timeout 就是 limit 系列生效的标志行;HTTP worker 的对应形态是 WorkerHTTP (NN) timeout after NNs。生产上若日志频繁出现该行,说明 limit 配置低于业务真实耗时,应调参或优化慢请求,而不是一味加大。
5.7 日志体系
| 参数 | 默认值 | 说明 |
|---|---|---|
logfile | 空(输出到 stdout/stderr) | 指定文件后日志落盘,控制台输出停止(实测:配置后 journalctl 无新增行、文件持续增长,二者互斥) |
log_level | info | 预设级别:debug/info/warn/error/critical,其中 debug_rpc/debug_sql 等是组合预设 |
log_handler | :INFO | 精细化控制,格式 模块前缀:级别,可多行(如 odoo.sql_db:DEBUG 只把 SQL 连接池日志调到 DEBUG) |
log_db | 空 | 指定库名后日志写入该库 ir_logging 表 |
syslog | False | 输出到系统 syslog |
实测组合 logfile = /var/lib/odoo/odoo.log + log_handler = odoo.sql_db:DEBUG 的落盘内容(真实回显):
2026-10-27 15:24:08,781 331 DEBUG odoo20restore odoo.sql_db.connection: ConnectionPool(read/write;used=2/count=2/max=64) Put connection to 'user=odoo password=xxx dbname=odoo20restore host=db port=5432 application_name=odoo-331 sslmode=prefer' in pool
2026-10-27 15:24:08,781 331 INFO ? odoo.sql_db: ConnectionPool(read/write;used=1/count=1/max=64): Closed 1 connections to 'user=odoo password=xxx dbname=odoo20restore host=db port=5432 application_name=odoo-331 sslmode=prefer'
逐段解读:时间戳 进程号 级别 库名 模块:子模块 消息——第 2 列进程号在多进程模式下可定位具体 worker(331 是新 fork 的 HTTP worker),库名列为空表示与库无关的系统日志;password=xxx 表明连接口令在日志中自动脱敏。排障时最实用的两级组合就是:全局 info + odoo.sql_db:DEBUG 看连接池,或临时 log_level = debug_rpc_answer 看请求级 RPC 报文。
注意运行模型的日志入口差异:多线程模式日志从主进程输出;多进程模式各 worker 独立写同一文件(logfile)或各自输出 stdout,journalctl 聚合时按进程号区分。
5.8 SMTP 邮件参数
这组参数定义服务端级默认发件通道(数据库内还可按公司覆盖):
| 参数 | 默认值 | 说明 |
|---|---|---|
smtp_server | localhost | SMTP 主机;配内网中继或公网 SMTP 服务地址 |
smtp_port | 25 | 587(STARTTLS)/465(SMTPS)按服务商调整 |
smtp_user / smtp_password | 空 | 服务端认证凭据 |
smtp_ssl | False | True = 全程 TLS(465) |
email_from | 空 | 全局发件地址兜底 |
from_filter | 空 | 限定哪些发件地址走此通道(逗号匹配规则) |
验证方式:配置后重启服务,在应用内「设置 → 技术 → 邮件」触发测试邮件;若 SMTP 凭据错误,日志会出现 odoo.addons.mail 前缀的 SMTP 连接错误(smtplib.SMTPAuthenticationError 等),按报错对号入座。演示环境未接外网 SMTP,本篇以参数语义与默认值为准。
5.9 多进程之外的资源参数
| 参数 | 默认值 | 说明 |
|---|---|---|
max_cron_threads | 2 | 多线程模式下的 cron 线程数;多进程模式归入 cron 进程。定时任务重的实例适当调大,纯接口型实例可设 0 停用定时调度 |
osv_memory_count_limit | 0(不限) | 瞬态模型(向导类)单表记录上限 |
transient_age_limit | 1.0 | 瞬态记录存活小时数,过期由 vacuum 清理 |
websocket_keep_alive_timeout | 3600 | WebSocket 空闲保活秒数 |
publisher_warranty_url | http://services.odoo.com/publisher-warranty/ | 版本/订阅校验上报地址。企业版数据库每周向 services.odoo.com 校验订阅;内网隔离环境官方给出两个选项:放行 80 端口出口,或改走 443 并配置 publisher_warranty_url = https://services.odoo.com/publisher-warranty/。社区版无订阅校验,该地址仅承载匿名版本遥测 |
5.10 环境变量对照
Odoo 服务端原生识别 PostgreSQL 客户端标准环境变量(源码 config.py 各选项的 env_name 实证),在配置文件缺省时生效:
| 环境变量 | 对应配置项 | 说明 |
|---|---|---|
PGHOST | db_host | PostgreSQL 地址 |
PGPORT | db_port | 端口 |
PGUSER | db_user | 角色 |
PGPASSWORD | db_password | 口令 |
PGDATABASE | db_name | 默认连接库(-d) |
PGDATABASE_TEMPLATE | db_template | 建库模板 |
PGSSLMODE | db_sslmode | SSL 模式 |
PGAPPNAME | db_app_name | application_name 标识 |
ODOO_DEV | dev_mode | 开发模式特性开关 |
ODOO_RC | --config | 配置文件路径(deb 安装脚本已写入 systemd 单元) |
优先级实测结论(命令篇 §命令形态将继续验证):配置文件已有值时,环境变量不再生效;两者都缺时回落源码默认。另有一组官方容器镜像专属变量(HOST/PORT/USER/PASSWORD/PASSWORD_FILE,由镜像 entrypoint 转换为命令行参数),仅存在于容器部署形态,其行为与优先级在 《Odoo 20 Docker Compose 部署实战》第六章已实测——裸机/包管理器部署不涉及。
六、生产配置模板
以下模板按官方部署文档的算例与本文实测参数组装,适用场景:8GB 内存、4 核 CPU、NVMe SSD,60 并发用户以内,CRM/销售/库存业务,Odoo 20 与 PostgreSQL 17 同机:
[options]
; ---- 数据库连接(同机 UNIX socket 可省 db_host/db_port)----
db_host = 127.0.0.1
db_port = 5432
db_user = odoo
db_password = odoo20pg
db_maxconn = 64
db_sslmode = prefer
; ---- 多进程与资源限制(官方 4C/8G 算例)----
workers = 8
max_cron_threads = 1
limit_memory_soft = 629145600
limit_memory_hard = 1677721600
limit_time_cpu = 600
limit_time_real = 1200
limit_request = 8192
; ---- HTTP 服务 ----
http_interface = 0.0.0.0
http_port = 8069
gevent_port = 8072
proxy_mode = True
; ---- 数据库管理器安全 ----
admin_passwd = q1w2e3r4
list_db = False
dbfilter = ^%d$
; ---- 模块与数据 ----
addons_path = /opt/odoo/extra-addons
data_dir = /var/lib/odoo
; ---- 日志 ----
logfile = /var/log/odoo/odoo.log
log_level = info
log_handler = odoo.sql_db:WARNING
逐项解读与调整指引:
workers = 8:(4 × 2) + 1 = 9上限下留 1 核余量给 cron 与系统;并发用户增长按「每 worker ≈ 6 并发」扩容并同步核算 PostgreSQLmax_connections(≈db_maxconn × (workers + 2))。limit_memory_soft/hard:官方算例的 600MB/1.6GB 组合,较源码默认(2GB/2.5GB)更适合小内存多 worker;内存充裕(16GB+)可放宽 soft 到 1GB 减少重生频率。limit_time_cpu/real = 600/1200:官方示例值,比默认(60/120)宽松,适配报表导出等长请求;接口型业务可回调收紧。proxy_mode = True+dbfilter = ^%d$+list_db = False:三者是多租户 HTTPS 生产的配套组合——反代终结 TLS 并转发/websocket/到 8072,按子域路由库,禁列库。admin_passwd:上生产前必须改为强随机值(本文q1w2e3r4仅为演示环境的固定测试口令)。- 日志:
log_handler = odoo.sql_db:WARNING把连接池 INFO 降噪;排障期临时改为odoo.sql_db:DEBUG,完毕改回。
轻量对照模板(2 核 4GB、20 并发以内):workers = 4、limit_memory_soft = 1073741824(1GB)、limit_memory_hard = 1610612736(1.5GB)、其余同上——本文实测环境即采用该档参数(workers = 2 为实测机保守值),多进程行为验证见 5.6 节。
七、常见问题
Q1:改了 odoo.conf 重启后行为没变化?
三步排查:确认服务加载的就是目标文件(启动日志 Using configuration file at ... 的路径);确认参数名是下划线风格且在 [options] 节内(写成 db-host 或放错节会被静默忽略);确认没有命令行参数(systemd 单元 ExecStart)覆盖配置文件。
Q2:admin_passwd 改完用 Web 界面验证报 403?
admin_passwd 只能配置文件设置且重启生效;确认提交的 master_pwd 与配置值完全一致。403 页面是「口令错误后表单重渲染」的正常表现,不是服务故障。
Q3:开启 workers 后服务起不来或 Windows 上不可用?
多进程模型仅支持 Linux(官方明确 not available on Windows);Linux 下起不来看日志是否出现 PosixOnlyOption 相关参数冲突(workers 组参数在 Windows 被禁用)与端口占用(8069/8072)。
Q4:日志频繁出现 WorkerHTTP (NN) timeout after NNs?
limit 时间上限低于真实业务耗时。先定位慢请求(log_level = debug_rpc 或数据库侧 pg_stat_activity),常见根因是未加索引的大表操作或报表聚合;确属业务常态再调大 limit_time_cpu/limit_time_real。
Q5:worker 频繁重生(Exiting cleanly. request_count: ... 高频出现)?
两种可能:limit_request 到数(默认 65536,属设计内正常重生);limit_memory_soft 频繁触发(调大 soft 或排查内存泄漏模块)。若为 limit_memory_hard 触发则伴随内存分配失败报错,需立即处理。
Q6:多库服务器未登录页面(网站/门户)报错?
dbfilter 未设置时未登录请求无法定位库。按域名规划设置 %h/%d 过滤;确认后按 5.3 节实测语义验证路由结果(看日志第三列库名)。
Q7:list_db = False 后数据库管理器还能用吗?
管理器各操作端点与列表端点是分开的:list_db = False 禁掉库列表与选择器,备份/恢复/复制等操作仍可用正确 master_pwd 走对应端点(JSON-RPC 形态,注意 415 一节所述的 Content-Type 要求)。要彻底禁用管理器,官方建议在网络层屏蔽 /web/database/ 路径。
Q8:dbfilter 设置后脚本登录报 Session expired (invalid CSRF token)?
锁库后登录必须先 GET /web/login 建 session 拿 CSRF token 再 POST(5.3 节实测流程),或在脚本中复用带 cookie 的会话对象。
八、参考链接
- 官方文档站 20.0(部署与配置):https://www.odoo.com/documentation/20.0/
- 官方部署指南(System configuration,workers/内存计算与配置示例):https://www.odoo.com/documentation/20.0/administration/deploy.html
- 官方 on-premise 管理文档(数据库管理器/订阅校验):https://www.odoo.com/documentation/20.0/administration/on_premise.html
- 官方命令行参考(CLI 与配置文件):https://www.odoo.com/documentation/20.0/developer/reference/cli.html
- 服务端源码配置定义(默认值权威来源):https://github.com/odoo/odoo/blob/20.0/odoo/tools/config.py
- 本专栏部署实测:《Odoo 20 Docker Compose 部署实战》
- 本专栏命令实测:《Odoo 20 常用命令与运维实战》
- 本专栏选型认知:《Odoo 介绍与选型指南》