☰
从零搭建 ERPNext V15:Docker 部署完整步骤及常见问题解决(适用于生产环境)|TaoToken 统一 Key 通道实践
2026/10/10 15:26:44 网站建设 项目流程

1. ERPNext V15 生产环境 Docker 部署到底难在哪

ERPNext V15 是一套开源的企业资源计划系统,涵盖财务、库存、生产、HR、CRM 等模块,适合中小制造、贸易、服务类企业自建数字化底座。它基于 Frappe 框架,天然支持多应用扩展,但正因为模块多、依赖重,生产环境部署时踩坑概率远高于普通 Web 应用。很多人第一次用 Docker 跑 ERPNext,卡在镜像构建、数据库健康检查、站点创建、反向代理这几步上,反复重来。

我试过在一台 4 核 8G 的 Ubuntu 24.04 上从零走完整流程,最深的感受是:官方pwd.yml那种一键演示部署确实五分钟能跑起来,但它用的是内置 MariaDB 和 Redis,端口直接暴露 8080,没有 HTTPS,没有备份策略,绝对不能拿去生产。生产环境要的是可复现的镜像、独立的数据卷、可控的数据库连接、反向代理加证书,以及出问题能回滚。

这篇文章面向的是已经决定自建 ERPNext、需要一套能直接复制粘贴落地的部署方案的人。我会给出完整的docker-compose.yml生成方式、环境变量模板、站点创建命令、健康检查脚本,以及端口冲突、权限报错、备份恢复这些高频问题的排查路径。同时,部署过程中如果涉及调用外部模型服务(比如智能客服、单据 OCR、报表问答),凭据管理容易散落各处,我会用 TaoToken 的统一 Key 通道把这类模型服务的 Base URL、Key、Model ID 收敛到一处,避免每个应用各配一份。

先说清楚整体架构:ERPNext 生产部署通常包含四层——MariaDB 数据库、Redis 缓存与队列、Frappe 后端(含 worker 和 scheduler)、前端与反向代理。Docker Compose 负责编排这四层,数据卷负责持久化,反向代理负责 HTTPS 和域名。下面按这个顺序展开。

2. TaoToken 统一 Key 通道在部署中的前置准备

ERPNext 本身不依赖大模型,但生产环境里往往要接一些智能能力:比如用模型做采购单摘要、客户邮件自动分类、库存异常问答。这些调用如果每个应用单独配 Key,运维会非常痛苦——Key 轮换要改多处,额度分散看不清,日志里还容易泄露。TaoToken 提供的是统一 Key/API 通道,把模型服务的接入点收敛成一个 Base URL 加一个 Key,模型用 Model ID 区分。

前置准备分三步。第一步,拿到统一 Key。访问 https://taotoken.net/api-keys 创建 API Key,建议按环境命名,比如erpnext-prod,方便后续审计。第二步,确认接入文档里的 Base URL 和可用 Model ID,文档地址 https://taotoken.net/doc 。第三步,在 ERPNext 侧决定凭据存放方式——不要硬编码进代码,用环境变量或.env文件,Compose 启动时注入。

这里要强调一个原则:模型服务的 Base URL、Key、Model ID 三件套必须成组出现,缺一个都调不通。Base URL 统一填https://taotoken.net/api,Key 填你创建的那串,Model ID 按文档里列出的填。如果你用的是 Claude Code 这类编码工具做部署脚本辅助,它的配置也是同样的三件套逻辑,Base URL 指向统一通道,Key 用同一个,Model ID 选对应模型。

为什么要在部署阶段就规划好这个?因为 ERPNext 的自定义应用(custom app)里如果写了模型调用,凭据来源必须和 Compose 的环境变量对齐。否则容器重启后环境变量丢失,应用报 401,你还得进容器排查。提前把.env里的变量名定好,比如TAOTOKEN_BASE_URL、TAOTOKEN_API_KEY、TAOTOKEN_MODEL_ID,后面写自定义应用时直接读这三个变量即可。

另外提醒一点:TaoToken 是模型服务的统一接入通道,不是数据库或 Redis 的替代品,别把它和 ERPNext 的核心依赖混在一起理解。它的作用域是“部署过程中及部署后调用的模型服务凭据管理”,核心业务数据仍然走 MariaDB 和 Redis。

3. 可复制的 Compose 配置与环境变量模板

这一节是全文最核心的可操作部分。我按官方frappe_docker仓库的 layered 镜像方案来写,因为 layered 基于预构建基础镜像,构建速度快,适合生产。先克隆仓库:

cd ~/ git clone -b v2.0.1 https://github.com/frappe/frappe_docker cd frappe_docker

然后准备apps.json,决定要装哪些应用。ERPNext 核心必装,HRMS 和 Payments 按需:

[ { "url": "https://github.com/frappe/erpnext.git", "branch": "version-15" }, { "url": "https://github.com/frappe/hrms.git", "branch": "version-15" }, { "url": "https://github.com/frappe/payments.git", "branch": "version-15" } ]

设置 base64 环境变量并构建镜像:

export APPS_JSON_BASE64=$(base64 -w 0 ~/frappe_docker/apps.json) docker build \ --build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \ --build-arg=FRAPPE_BRANCH=version-15 \ --build-arg=APPS_JSON_BASE64=$APPS_JSON_BASE64 \ --tag=myimages/custom:1.0.0 \ --file=images/layered/Containerfile .

构建完成后,复制环境变量模板并修改:

cp example.env custom.env

custom.env关键字段如下,这是生产环境的最小可用模板:

DB_PASSWORD=ChangeMe_StrongPass_2024 DB_HOST= DB_PORT= REDIS_CACHE= REDIS_QUEUE= FRAPPE_SITE_NAME_HEADER=frontend CUSTOM_IMAGE=myimages/custom CUSTOM_TAG=1.0.0 PULL_POLICY=missing TAOTOKEN_BASE_URL=https://taotoken.net/api TAOTOKEN_API_KEY=sk-你的统一Key TAOTOKEN_MODEL_ID=按文档填写

注意FRAPPE_SITE_NAME_HEADER必须填frontend,这是 Frappe 内部站点名匹配用的,填错会导致访问 404。DB_HOST和DB_PORT留空表示用 Compose 内置的 MariaDB;如果接外部数据库,填 IP 和端口。REDIS_CACHE和REDIS_QUEUE同理。

生成最终 Compose 文件,这里用 HTTPS 反向代理方案:

docker compose --env-file custom.env \ -f compose.yaml \ -f overrides/compose.mariadb.yaml \ -f overrides/compose.redis.yaml \ -f overrides/compose.https.yaml \ config > compose.custom.yaml

如果你暂时不接 HTTPS,把compose.https.yaml换成compose.noproxy.yaml,端口走 8080。生产环境强烈建议 HTTPS,证书可以用 Let's Encrypt,Traefik 会自动申请。

启动容器:

docker compose -p frappe -f compose.custom.yaml up -d

低配服务器上 MariaDB 健康检查可能超时,先等它变 Healthy:

docker ps --filter "name=frappe-db" --format "{{.Status}}"

看到healthy后再重启一次:

docker compose -p frappe -f compose.custom.yaml restart

创建站点并安装应用:

docker compose -p frappe exec backend bench new-site \ --mariadb-user-host-login-scope='%' \ --admin-password=Admin_Strong_2024 \ --db-root-username=root \ --db-root-password=ChangeMe_StrongPass_2024 \ --install-app erpnext \ --set-default frontend docker compose -p frappe exec backend bench --site frontend install-app hrms docker compose -p frappe exec backend bench --site frontend install-app payments

到这里,核心部署完成。模型服务的凭据已经通过custom.env注入到容器环境,自定义应用里用os.environ.get('TAOTOKEN_API_KEY')读取即可,不需要在代码里写死。

4. 验证请求与成功结果确认

部署完不能只看容器起来了就完事,要逐层验证。第一层,容器状态:

docker compose -p frappe ps

正常应该看到backend、db、redis-cache、redis-queue、frontend、websocket、scheduler、worker等容器都是Up或healthy。如果某个 worker 反复重启,先看日志:

docker compose -p frappe logs --tail=100 worker

第二层,站点健康检查。Frappe 自带bench doctor:

docker compose -p frappe exec backend bench doctor

输出里Scheduler is enabled和Workers online是正常标志。如果 scheduler 没启用,执行:

docker compose -p frappe exec backend bench --site frontend enable-scheduler

第三层,HTTP 验证。用 curl 打站点首页:

curl -I https://erp.yourdomain.com

返回HTTP/2 200且content-type: text/html说明反向代理和前端都通。如果返回 502,多半是 backend 没起来或 Traefik 配置没生效。

第四层,模型服务通道验证。这一步很多人忽略,但生产环境里自定义应用调模型失败,往往就是这里没验。在 backend 容器里执行:

docker compose -p frappe exec backend bash -c ' curl -s -o /dev/null -w "%{http_code}" \ -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d "{\"model\":\"$TAOTOKEN_MODEL_ID\",\"messages\":[{\"role\":\"user\",\"content\":\"ping\"}]}" '

返回200说明统一 Key 通道在容器内可用。如果返回401,检查 Key 是否复制完整、有没有多余空格;返回404,检查 Base URL 是否写成了带路径的完整地址。

第五层,登录界面确认。浏览器打开域名,用administrator和你设置的 admin 密码登录,能看到中文设置向导和左侧 ERPNext 菜单,说明站点创建成功。到这一步,部署验证闭环完成。

5. 常见报错排查:401、端口冲突、权限与备份恢复

生产部署最耗时的不是顺利路径,而是报错排查。下面按真实遇到的频率排序。

401 Unauthorized(模型通道):容器内 curl 返回 401,先确认TAOTOKEN_API_KEY是否真的注入到容器:

docker compose -p frappe exec backend printenv | grep TAOTOKEN

如果变量为空,说明custom.env没被 Compose 读取,检查启动命令有没有带--env-file custom.env。如果变量有值但仍 401,去 https://taotoken.net/api-keys 确认 Key 状态是否正常、额度是否耗尽。

local proxy failed / 502 Bad Gateway:反向代理到 backend 失败。先确认 backend 容器在运行,再看 Traefik 日志:

docker compose -p frappe logs --tail=50 frontend

常见原因是FRAPPE_SITE_NAME_HEADER没设成frontend,或者域名解析没指向服务器。另外检查compose.https.yaml里的域名变量是否和实际域名一致。

端口冲突:启动时报bind: address already in use。查占用:

ss -tlnp | grep -E '80|443|8080|3306|6379'

如果是本机已有 Nginx 占了 80/443,要么停掉它,要么改 Compose 映射端口。MariaDB 默认 3306、Redis 6379,如果宿主机已装同款服务,也会冲突,建议生产环境用独立端口映射,比如3307:3306。

权限报错(Permission denied):数据卷挂载后容器内用户无写权限。Frappe 容器内用户 UID 通常是 1000,宿主机目录属主要对齐:

sudo chown -R 1000:1000 /path/to/sites

如果用的是命名卷而非绑定挂载,一般不会有这个问题,所以生产环境优先用命名卷。

reading choices 报错:这是 Frappe 前端读取字段选项时的报错,多半是站点没设默认或缓存没刷新。执行:

docker compose -p frappe exec backend bench --site frontend clear-cache docker compose -p frappe exec backend bench --site frontend migrate

OAuth / 登录跳转异常:如果接了 SSO 或 OAuth,回调地址必须和实际域名一致。检查site_config.json里的host_name:

docker compose -p frappe exec backend cat sites/frontend/site_config.json

不一致就改掉再重启。

备份与恢复:生产环境必须配定时备份。手动备份命令:

docker compose -p frappe exec backend bench --site frontend backup --with-files

备份文件在sites/frontend/private/backups/。恢复时先停服务,再执行:

docker compose -p frappe exec backend bench --site frontend restore /path/to/backup.sql.gz --with-public-files /path/to/files.tar --with-private-files /path/to/private-files.tar

恢复后跑一次bench migrate和clear-cache。回滚方案同理:保留上一个版本的镜像 tag,出问题时把CUSTOM_TAG改回旧版本,重新up -d即可,数据卷不动。

6. 长期编码与 Agent 场景下的通道管理建议

ERPNext 部署不是一次性动作,后续会有自定义应用开发、报表脚本、定时任务、Agent 自动化等需求。这些场景里模型调用会越来越频繁,凭据管理如果一开始没规划好,后面会变成技术债。

我的建议是把 TaoToken 的统一 Key 通道当成基础设施的一部分来管。具体做法:在custom.env里只放一个 Key,所有自定义应用通过环境变量读取;不同环境(开发、测试、生产)用不同的 Key,在 https://taotoken.net/api-keys 里分别创建,命名带环境后缀;Key 轮换时只改.env一处,重启容器生效,不用动代码。

如果你用 Claude Code 或类似编码工具辅助写 ERPNext 自定义应用,它的配置也是同一套三件套:Base URL 指向https://taotoken.net/api,Key 用统一 Key,Model ID 按文档选。这样编码工具和运行时应用共用一套凭据体系,排查问题时不用在两套配置之间切换。

对于长期跑 Agent 任务(比如自动生成采购建议、库存预警摘要)的场景,建议单独申请一个 Key,和交互式应用隔离,方便按额度监控。Coding Plan 这类长期编码方案也适合放在这个通道下统一管理,避免多个 Key 散落。

最后给一个实用技巧:在custom.env里加一行注释记录 Key 的创建时间和用途,比如# TAOTOKEN_API_KEY created 2024-06 for erpnext-prod custom app。半年后回头看,能省下大量回忆成本。部署这件事,顺利跑通只是开始,能长期稳定维护才是生产环境的真正要求。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询