前阵子帮一个朋友在他的新笔记本上装 Odoo,他一上来就问:是不是要装 PostgreSQL、装 Python 3、再下载源码才能跑起来?我告诉他,现在最省事的路径是先用 Docker Desktop 拉一个odoo:19.0镜像,几分钟就能看到数据库创建页面;等这套东西要放到服务器上长期跑,再装一个 1Panel 面板做统一管理,备份、反向代理、证书都有地方看。这条“本地快速部署 + 服务器面板纳管”的组合我反复用过很多次,过程中踩过不少坑,也总结了一套能直接复用的流程。这篇就把完整过程写出来,既有能抄走的 Compose 配置,也有我真实操作时遇到的坑。
1. 两条路线为什么这么走:Docker Desktop 与 1Panel 的分工逻辑
1.1 本地开发用 Docker Desktop:低摩擦、高还原
在本地跑 Odoo,最传统的方式是装 Python、装 PostgreSQL、再拉源码手动安装依赖。这条路不是不能走,但很容易出问题:Odoo 依赖一大堆 Python 包,每个版本对依赖的版本要求还不一样;PostgreSQL 的版本和编译选项也很挑剔。更要命的是,你电脑上可能还跑着别的服务,全局装一个 PostgreSQL 后,端口、系统服务、环境变量会互相打架。我见过有人因为这个把系统 Python 环境改乱了,最后只能重装。
Docker Desktop 的核心价值就是把 Odoo 和它需要的数据库全部关进独立容器里,本机只需要一个 Docker 引擎。容器和宿主机之间只留端口和挂载目录两个出口,依赖冲突基本不可能发生。你把代码目录挂载进容器,改完保存刷新页面就能看到效果,不需要重装依赖。而且本地只要能docker compose up -d启动,服务器上也一样启动,环境差异几乎为零,不存在“我本机能跑,服务器上跑不起来”的问题。
我用 Docker Desktop 的另一个原因是可以随时丢弃重建。调试自定义模块时经常会把数据库搞乱,直接把这个目录删掉、重新docker compose up -d,一分钟内回到干净状态。这在原生环境里是不可想象的——卸载重装一次至少半小时起步。
注意:Docker Desktop 在 Windows 上默认基于 WSL2 或 Hyper-V 后端,首次启动会拉取较多镜像层,建议把 Docker 数据目录放到空间充足的磁盘,并保证至少有 4GB 内存可分配。
1.2 服务器选 1Panel 的原因
服务器上跑 Odoo,不是“能跑”就完事。你可能要面对这些问题:容器怎么启停、磁盘满了去哪看、数据库每天怎么自动备份、域名证书三个月到期了谁来提醒。这些需求用纯命令行也能做,但有了面板就有了一个统一入口,而且 1Panel 这类轻量级面板对 Docker 的原生支持做得很好。
我选择 1Panel 的具体理由有几个。第一,它自带容器管理界面,Odoo 的容器状态、日志、资源占用能在一个页面里看完;第二,它的计划任务功能可以直接备份 PostgreSQL 数据库,不用自己写复杂的定时脚本;第三,它内置了反向代理和免费证书申请功能,上线时不用再单独搭一套 Nginx。这几件事如果全部手工维护,每一件都要单独学习一套命令和配置,面板把这些收拢成了可视化操作。
很多服务器面板越做越重,装完以后光是自身组件就占掉大量内存。1Panel 相比同类方案更克制的点是它默认依赖 Docker 来运行应用,面板本身只做管理编排,不会侵入你的业务容器。对一台 2GB 内存的 Ubuntu 24 服务器来说,这个取舍很关键。
1.3 面板只是工具箱,不是牢笼
很多人一听到“用面板管容器”就担心被绑死,这其实是误解。1Panel 管理的容器目录结构仍然是标准 Docker 的,Compose 文件是普通文本,数据库数据也还是存放在你指定的挂载目录里。面板只是在上面套了一层可视化管理,你随时可以用命令行操作同一个编排文件。
正因为如此,我每次部署前都会先把目录规划清楚:哪些目录是面板统一管理的,哪些是我自己自定义的持久化位置。这样即便某天面板本身出问题,甚至整个面板重装,业务数据不会跟着丢。容器可以被随意删除重建,数据目录才是真正不能动的部分。后面第 5 章会详细展开目录怎么设计,这里先记下这个原则。
2. Odoo 19.0 本地部署前必须想清楚的五件事
2.1 镜像用官方 odoo:19.0 就够了
Docker 镜像仓库里能搜到很多 Odoo 相关镜像,有的自称集成了更多插件,有的声称已经配好了中文环境。我的建议是:本地开发和标准部署一律用官方odoo:19.0镜像,不要用第三方打包版。原因很简单,第三方镜像你无法确认里面改了哪些文件,也没法保证和你之后要安装的模块兼容。
如果确实需要额外的 Python 库,更推荐基于官方镜像写一个自己的 Dockerfile,把需要的包加进去。这样整个依赖链是可控的,出了问题也知道从哪查。
版本 tag 方面,建议写odoo:19.0,不要用latest。latest的坑在于它会跟着官方推送变化,某天你重启容器时可能不知不觉就升到了下一个小版本。固定 tag 意味着升级动作是主动选择的,而不是意外发生的。
2.2 PostgreSQL 版本要配套
Odoo 对 PostgreSQL 版本有明确要求,官方文档会在每个大版本里标注出来。以 19.0 为例,配套的 PostgreSQL 大版本用 16 或更高基本都能正常工作,具体还是以官方文档为准。我在 Compose 里固定用postgres:16,原因是我测过这个组合在 18.0 和 19.0 上都能稳定跑,而且 16 的镜像很成熟,资源占用也合理。
这里有个容易犯的错误:直接用宿主机上已经安装的 PostgreSQL,然后让容器连接宿主机数据库。不建议这么做,因为宿主机 PG 的版本、配置和容器内 Odoo 的适配不一定匹配,而且你会失去“整个环境一键重建”的能力。既然用了 Docker,就要让数据库也在容器里,两个容器通过网络互通。
2.3 目录规划三件套
我建任何一个 Odoo 项目都会提前规划三个挂载目录,缺一个后面都会后悔:
./addons:自定义模块目录,挂载到容器里的/mnt/extra-addons。./odoo-data:Odoo 的 filestore 和会话数据,挂载到/var/lib/odoo。./odoo.conf:配置文件,挂载到/etc/odoo/odoo.conf。
如果只挂载addons而不挂载odoo-data,容器一旦被删除重建,你上传的附件、自定义设置都会消失,代码还在但数据没了。这种情况我见过不止一次,有人辛辛苦苦配置了几天,容器重建后打开系统发现附件全裂了,只能翻备份。目录规划其实花不了几分钟,但能救命。
我用一个比较固定的目录结构:
odoo19-project/ ├── addons/ ├── odoo-data/ ├── odoo.conf └── docker-compose.yml这个结构简单清晰,后续无论是本地迁移到服务器,还是交给 1Panel 管理,路径都能直接沿用。
2.4 端口最容易打架
Odoo 默认 Web 端口是 8069,PostgreSQL 默认端口是 5432。这两个端口在本地电脑上非常容易被占用,尤其是你装过其他数据库管理工具或者开发环境时。
我习惯把开发用的 PostgreSQL 对外映射改成5433:5432,这样即使宿主机有 PG 实例在跑也不冲突。Odoo 的 8069 端口也不一定要保持默认,如果被占用,可以映射成8070:8069。
检查端口占用可以用netstat -ano | grep 5432这类命令,Windows 下也可以直接在“资源监视器”里看监听端口。确定端口冲突再动手启动容器,能省掉很多排查时间。
2.5 给 Docker Desktop 留足资源
Odoo 创建新数据库时,会执行大量初始化迁移脚本,这个过程对内存和 CPU 都比较敏感。我实测过,如果 Docker Desktop 只分配 2GB 内存,创建带演示数据的数据库时会非常慢,甚至报 OOM 错误。建议在 Docker Desktop 的设置里把内存调到 4GB 以上,CPU 给 2 核以上。
另外还有一个 Windows 下的细节:尽量不要把项目目录放在很深的位置,尤其是用户目录下的深层路径。Docker 在跨文件系统做 IO 时性能会打折扣,直接影响 Odoo 读写的响应速度。项目放在磁盘根目录下一个好找的位置,比如D:\workspace\odoo19-project,会比较舒服。
3. Docker Desktop 快速拉起 Odoo 19.0:能直接抄的 Compose 配置
3.1 docker-compose.yml 全文
下面这份配置是我在 Odoo 19.0 上实际用过的,包含 Odoo 应用容器和 PostgreSQL 数据库容器,本地开发可以直接用:
version: '3.8' services: db: image: postgres:16 container_name: odoo19_db restart: unless-stopped environment: - POSTGRES_DB=postgres - POSTGRES_USER=odoo - POSTGRES_PASSWORD=odoo - PGDATA=/var/lib/postgresql/data/pgdata volumes: - ./pgdata:/var/lib/postgresql/data/pgdata ports: - "5433:5432" odoo: image: odoo:19.0 container_name: odoo19_app restart: unless-stopped depends_on: - db environment: - HOST=db - USER=odoo - PASSWORD=odoo ports: - "8069:8069" volumes: - ./addons:/mnt/extra-addons - ./odoo-data:/var/lib/odoo - ./odoo.conf:/etc/odoo/odoo.conf几个字段的用意我解释一下。数据库容器里的配置项是标准的 PostgreSQL 初始化参数,POSTGRES_DB指定了初始数据库名,后面 Odoo 创建业务数据库时会基于这个实例来建。PGDATA定义了数据文件存放路径,同时通过卷挂载到宿主机./pgdata,这样数据库文件不会写在容器层里。
Odoo 容器里的HOST=db是关键,它告诉 Odoo 连接名为db的容器,这是 Compose 网络内的服务名解析。./addons挂载到/mnt/extra-addons后,自定义模块放进这个目录,Odoo 启动时会自动扫描。./odoo-data挂载保证 filestore 持久化。./odoo.conf挂载使容器内的配置和你本机文件保持一致,改配置不需要进入容器内部操作。
3.2 启动步骤与验证
在项目目录下执行:
docker compose up -d首次启动会拉取postgres:16和odoo:19.0两个镜像,耗时取决于网络情况。拉完后两个容器都会开始运行,用下面命令确认状态:
docker compose ps正常状态应该是两个容器都显示running。然后打开http://localhost:8069,如果能看到“创建数据库”的页面,就说明 Odoo 已经成功连上数据库了。这一步最容易出问题的是数据库连接失败,常见原因是POSTGRES_PASSWORD与 Odoo 容器里的PASSWORD不一致,或者数据库容器还没初始化完成 Odoo 就尝试连接了。depends_on只保证容器启动顺序,不保证数据库就绪,所以如果第一次打开报错,等几秒刷新一下通常就好了。
3.3 初始化数据库的两个选择
第一次打开 Odoo 页面时需要创建一个新的业务数据库。页面会让你填写数据库名称、管理员密码,还有一个选项是“是否安装演示数据”。
我的建议是:如果只是学习 Odoo 的界面流程,可以勾选演示数据,这样能看到各种预置产品、订单、报表,理解业务对象之间的关联会快很多。如果是自己准备写模块或者作为正式系统的起点,就不要勾选演示数据,否则后面要费劲清理一堆示例记录。生产环境更是绝对不要勾选,演示数据会污染正式业务数据。
创建过程一般需要一两分钟,大版本首次初始化的时间会更长一些。这时候不要反复刷新页面,用docker compose logs -f odoo看日志,能看到模块初始化进度。等到日志里出现HTTP service (production) started之类就说明服务已经就绪。
3.4 挂载自定义模块与热更新
把自定义模块放到./addons目录后,重启 Odoo 容器让模块被扫描到:
docker compose restart odoo模块扫描后还需要在应用列表里找到它并安装。安装完成后,每次修改模块代码,Odoo 都需要更新模块才能让改动生效,常见方式是在开发者模式下执行“升级模块”。不过本地开发阶段最简单的调试闭环是:改代码 →docker compose restart odoo→ 复现问题。重启一个容器只要几秒,比在原生环境里重启服务还要快。
在 Windows 或者 macOS 上,文件挂载一般没有权限问题;如果你用的是 Linux 桌面版 Docker,可能会出现容器内用户写不了挂载文件的权限问题,需要调整目录的拥有者或者给容器指定user。这个问题到了服务器上同样存在,我在第 5 章会再提一下怎么处理。
4. Ubuntu 24 上安装 1Panel 面板:从准备到初始化
4.1 装之前先检查系统
在 Ubuntu 24.04 LTS 上安装 1Panel 之前,我会先做一轮基础检查,避免装到一半才发现资源或网络层有问题。
第一是内存和磁盘。1Panel 自身占用不大,但如果你打算让它管理 Odoo 容器,你需要至少 2GB 可用内存和 20GB 可用磁盘。Odoo 的数据库和文件存储增长很快,磁盘给太少后面会很被动。
第二是系统时间。面板的证书申请、计划任务、日志时间都依赖系统时间正确,安装前检查一下时区是否设置成你的业务所在时区,用timedatectl可以查看。
第三是防火墙。如果服务器开启了 UFW,需要放行面板端口,以及后续要用的 80、443 端口。很多人装完面板发现访问不了,就是因为防火墙没放行。
4.2 执行官方安装脚本
1Panel 的安装脚本很长,不需要自己一条条执行,官方提供了一个 quick_start 脚本。具体命令以官网当前版本为准,基本形式是:
curl -sSL https://www.1panel.cn/quick_start.sh -o quick_start.sh sudo bash quick_start.sh执行过程中脚本会交互式问你几个问题:安装目录、面板端口、是否安装 Docker。如果你这台服务器之前没装 Docker,就让它顺手装好;如果已经装了 Docker,脚本会检测到并直接复用。
安装目录这一点很容易被忽略。有人直接把面板装到根目录或者系统盘,后面磁盘被日志塞满了才发现问题。我会单独用一个剩余空间较大的分区给面板和容器持久化数据,比如/opt下面划分一个固定目录。这样即使系统分区遇到问题,业务数据仍然在独立位置。
4.3 初始化面板安全配置
安装完成后终端会输出面板访问地址、用户名和随机生成的密码,先保存好再操作。
登录后的第一件事不是急着部署 Odoo,而是做安全初始化。我按这个顺序来:
- 修改管理员密码。安装时生成的随机密码强度够,但记不住,换成自己的强密码。
- 修改面板端口。默认端口很容易被扫描工具盯上,换成不常用的高位端口。
- 开启两步验证。面板是服务器管理的入口,这一步强烈建议做。
- 如果有域名且打算通过公网访问面板,可以给面板绑定域名并申请证书;如果只是内网使用,跳过也行。
面板里还能看到服务器的 CPU、内存、磁盘使用情况,也可以从这里管理 Docker 容器,后续部署 Odoo 的操作基本都会在这个界面里完成。
5. 用 1Panel 接管 Odoo 容器的两种姿势
5.1 方式一:把 Compose 整个导入
1Panel 里有个编排功能,直接用它可以导入标准的 docker-compose 内容。我的推荐做法是把第 3 章的 Compose 内容做一点适配改动,路径改成服务器上的实际路径,然后粘贴到面板的编排配置中。
适配时需要注意三个点。第一,./addons、./odoo-data、./pgdata这些相对路径要改成服务器上的绝对路径,比如/opt/odoo19/addons,否则面板执行编排时可能定位不到目录。第二,端口映射要考虑服务器上是否已有服务占用 8069 或 5432。第三,如果服务器上已经跑了别的容器网络,建议为这个项目指定独立网络,避免容器名冲突。
改完以后保存并启动编排,面板会按照 Compose 文件自动创建网络和容器,然后在容器列表里就能看到 Odoo 和 PostgreSQL 的状态。之后的启动、停止、重启、日志查看都能在面板里完成,不再需要敲命令行。
5.2 方式二:面板里手工创建容器
如果不想用编排文件,也可以在 1Panel 的容器页面手工创建。操作顺序是先创建数据库容器,再创建 Odoo 容器。
创建 PostgreSQL 容器时,在镜像栏输入postgres:16,设置好容器名称、端口映射、挂载目录和环境变量。环境变量里必须有POSTGRES_USER、POSTGRES_PASSWORD,这两个值要和后面 Odoo 容器里填的一致。
创建 Odoo 容器时,在镜像栏输入odoo:19.0,端口映射8069:8069,挂载目录指向你的addons、odoo-data,环境变量里写明HOST=刚才创建的数据库容器名、USER=odoo、PASSWORD=odoo。如果需要让 Odoo 等数据库就绪后再启动,可以在依赖关系里把 Odoo 容器设为依赖数据库容器。
这种方式的操作路径更直观,新手对每个配置项是什么会有更具体的概念,但步骤多,而且如果填错一项,日志排查又要从头捋一遍。我一般只在临时验证单个容器时才用这种方式。
5.3 两种方式怎么选
| 对比维度 | Compose 编排导入 | 界面手工创建 |
|---|---|---|
| 配置可读性 | 配置是文本文件,可进版本管理 | 依赖界面,历史记录不易追溯 |
| 创建速度 | 一次成型,适合整套服务 | 需要逐个创建,来回切换界面 |
| 升级维护 | 改镜像标签后重新编排即可 | 要逐项修改容器配置 |
| 适合场景 | 正式交付,标准部署 | 快速验证单个容器 |
| 路径管理 | 集中在 Compose 文件中控制 | 分散在各容器配置里 |
我个人推荐 Compose 方式,理由很实际:Odoo 升级时只需要改 Compose 里的镜像标签,然后重新执行编排,比在界面里逐个配置容器要高效得多。
6. 上线前绕不开的备份、反向代理与升级顺序
6.1 备份策略:数据库与业务文件分开备份
Odoo 系统的数据可以分成两部分:数据库和文件存储。数据库里是业务记录、配置、权限关系,文件存储里是附件和上传的文档。备份必须两部分都覆盖,只备份数据库不备份 filestore,恢复后附件全裂;只备份文件不备份数据库,业务记录全丢。
在 1Panel 里可以创建计划任务,选择数据库备份功能,指定 PostgreSQL 容器,它会定时导出 SQL 文件。频率上我建议生产环境每天一次。文件目录那一侧,只要把第 2 章的三个目录(addons、odoo-data、pgdata)一起打包压缩即可。1Panel 的计划任务也支持压缩指定目录,把三个目录统一放到一个母目录下,备份时就一条任务搞定。
开发环境另外还有一个更轻量的备份方式:直接打开 Odoo 的数据库管理页面/web/database/manager,用内置备份功能下载数据库文件。这个适合开发阶段快速打快照,不适合作为生产备份替代方案。
备份恢复这件事一定要演练一次,不要只配置了任务就以为万事大吉。我见过有人备份任务跑了三个月,恢复时才发现导出的 SQL 是空的,原因是他选错了数据库容器。收尾前做一次实际恢复测试,比出问题后再补救重要得多。
6.2 反向代理与 HTTPS 证书
Odoo 容器默认监听 8069,生产环境要做 HTTPS 访问时,不能直接把 8069 暴露到公网。合理做法是用 1Panel 的网站功能建一个反向代理,把域名流量转到127.0.0.1:8069。
在 1Panel 中创建网站,类型选择反向代理,域名填你的业务域名,目标地址填127.0.0.1:8069。创建完成后,申请免费证书并开启自动续期,HTTPS 就位了。
这里有个 Odoo 侧必须做的配置:开启反向代理模式。在odoo.conf中加入:
[options] proxy_mode = True不开启这个选项,经过反向代理访问时,Odoo 可能会生成错误的内部链接,造成附件打不开、路由异常等问题。odoo.conf通过 Compose 里挂载到/etc/odoo/odoo.conf,改完重启容器生效。
6.3 升级镜像的先后顺序
Odoo 大版本升级不是一件可以随便“拉新镜像重启”的事。很多人图省事,直接docker compose pull然后docker compose up -d,结果容器起来后数据库迁移跑到一半报错,数据就处于一个不稳定的中间状态。
正确的升级顺序我总结为六步:
- 记下当前正在运行的镜像版本,比如
odoo:19.0,升级后如果要回滚,需要这个信息。 - 做完整备份。数据库导出一份完整 SQL,同时把
odoo-data和pgdata目录压缩打包。 - 修改 Compose 文件中的镜像标签,比如从
odoo:19.0改到odoo:19.1或新的大版本。 - 执行拉取新镜像并重新创建容器。
- 查看日志,确认数据库迁移正常完成。
- 如果迁移中途报错,立即回滚:改回旧版本标签、恢复备份、重新启动容器,而不是继续在坏状态里调试。
升级前做备份这个步骤最容易被跳过,但只有它能保证你有后悔药。数据库迁移失败后的现场往往很惨淡,与其想着怎么修复,不如直接回滚到升级前,查清楚原因再升一次。
6.4 本地镜像搬到服务器的技巧
如果你的服务器带宽比较小,或者目标机器在迁移仓库时下载非常慢,本地和服务器之间可以走离线搬运。这一步也能保证两边跑的镜像完全一致,避免“本地是 19.0,服务器上不知道是什么版本”这类问题。
在本地执行:
docker save odoo:19.0 | gzip > odoo-19.tar.gz然后把压缩包传到服务器:
scp odoo-19.tar.gz user@<服务器地址>:/tmp/在服务器上执行:
docker load -i /tmp/odoo-19.tar.gz镜像导入后在 1Panel 里创建容器时就能直接看到这个镜像。这招在需要同时管理多台服务器时尤其有用,也是我每次上线新环境时的保底方案。
最后聊聊个人体会。我在 Docker Desktop 上调试自定义模块,在 1Panel 里管理线上容器,来回折腾过的次数不算少,最大的感受是:这套组合把“环境问题”从业务问题里剥离了出去。即使某天面板出问题,只要addons、odoo-data、pgdata三个目录都还在,容器重建也只是几分钟的事。建议你把这三个目录放在清晰好找的位置,命名固定下来,备份和迁移脚本直接按它们来写,后面会省掉非常多焦虑。