Frappe Helpdesk 1.31 Docker Compose 部署指南

使用 Frappe 官方 frappe_docker 编排以 Docker Compose 部署 Helpdesk 1.31.0 的实测指南:镜像选型、.env 与 override 组织、建站加固、持久化与备份恢复闭环、环境变量表、日常运维与排障实录。

Frappe Helpdesk自托管2026/10/23

Frappe Helpdesk 1.31 Docker Compose 部署指南

目标:在一台装好 Docker 的 Ubuntu 服务器上,使用 Frappe 官方编排仓库 frappe_docker 以 Docker Compose 部署 Frappe Helpdesk 1.31.0 生产栈,覆盖镜像选型、编排文件组织、建站、持久化验证、备份恢复闭环、日常运维与卸载。文中所有命令与回显均为 2026-10-23 在 Docker 29.8.0 + Compose v5.5.1 环境实测的原始输出。产品定位见[《Frappe Helpdesk 1.31 介绍与选型指南》](https://www.quzuo.net/document/xtxb3uZrBRAB),bench 手工路径见本专栏安装指南篇。

一、环境信息

项目实测值
操作系统Ubuntu 22.04.5 LTS
Docker Engine29.8.0
Docker Composev5.5.1(docker compose version 实查)
编排仓库github.com/frappe/frappe_docker(main 分支,2026-10-23 克隆)
Helpdesk 镜像ghcr.io/frappe/helpdesk:stable
MariaDB 镜像mariadb:11.8(官方编排 compose.mariadb.yaml 指定)
Redis 镜像redis:8.6-alpine(官方编排 compose.redis.yaml 指定)
栈内应用版本frappe 15.123.1 / helpdesk 1.31.0 / telephony 0.0.1(bench version 实查)
Compose 项目名frappe-helpdesk-1-31-0-stack

说明:Helpdesk 官方 README 的生产部署推荐 easy-install.py 一键脚本(内部同样拉起 frappe_docker 编排);本文采用手工组织 compose 文件的方式,与脚本产物同构,但每一步可控可复盘。

二、镜像选型

2.1 官方镜像

Frappe 官方在 GitHub Container Registry 发布 Helpdesk 应用镜像:ghcr.io/frappe/helpdesk。该镜像内含 Frappe 框架、helpdesk 与 telephony 应用(bench version 实测回显):

frappe 15.123.1
helpdesk 1.31.0
telephony 0.0.1

标签选择:

标签含义适用
stable跟随最新稳定版(撰写本文时即 1.31.0,与官方 easy-install 文档 --version=stable 一致)生产推荐
v1.31.0 等具体版本号锁定版本需要版本固定、灰度回退
develop开发分支测试尝鲜,勿用于生产

2.2 依赖镜像

来自 frappe_docker 官方 override 文件(实查原文),无需自行选型:

  • mariadb:11.8(overrides/compose.mariadb.yaml,带 healthcheck 与 MARIADB_AUTO_UPGRADE: 1)
  • redis:8.6-alpine(overrides/compose.redis.yaml,cache 与 queue 各一实例)

⚠️ 实测提示:网上旧资料常见 mariadb:10.6 + redis:6.2 组合,现行 frappe_docker main 分支已升级为上表组合。Frappe Framework 恢复数据时会提示 Warning: MariaDB version ['11.8', '9'] is more than 10.8 which is not yet tested with Frappe Framework.——属官方已知警告,功能可正常使用(本文备份恢复实测通过)。

三、前置条件

docker --version
# Docker version 29.8.0
docker compose version
# Docker Compose version v5.5.1

准备编排目录(示例规划 /opt/frappe-helpdesk,可按需调整):

git clone --depth 1 https://github.com/frappe/frappe_docker.git
mkdir -p /opt/frappe-helpdesk && cd /opt/frappe-helpdesk
cp ~/frappe_docker/compose.yaml .
cp -r ~/frappe_docker/overrides .

⚠️ 若服务器访问 GitHub/GHCR 缓慢或失败,先为当前会话配置代理(export http_proxy=... https_proxy=...)或为 Docker 守护进程配置镜像加速后再继续;docker compose pull 同样遵循该代理配置。

四、部署步骤

4.1 环境变量文件

在编排目录创建 .env(本文示例密码统一 q1w2e3r4,生产请替换):

DB_PASSWORD=q1w2e3r4
CUSTOM_IMAGE=ghcr.io/frappe/helpdesk
CUSTOM_TAG=stable
PULL_POLICY=missing

键位说明见第六章。CUSTOM_IMAGE/CUSTOM_TAG 是把官方编排中的默认应用镜像(frappe/erpnext)替换为 Helpdesk 官方镜像的关键。

4.2 端口发布 override

⚠️ 实测重要:现行 frappe_docker 的 compose.yaml 不再默认发布 8080 端口(面向反代前置的部署形态)。直连测试需要自建一个小 override,新建 compose.ports.yml:

services:
  frontend:
    ports:
      - "8080:8080"

4.3 项目名与启动命令

⚠️ 实测坑:Compose 项目名不允许包含点号,frappe-helpdesk-1.31.0-stack 会被直接拒绝:

invalid project name "frappe-helpdesk-1.31.0-stack": must consist only of lowercase alphanumeric characters, hyphens, and underscores as well as start with a letter or number

本文使用 frappe-helpdesk-1-31-0-stack。把四个 -f 参数固化为 shell 变量后启动(生产建议写成 deploy.sh 或 Makefile 固化):

CF="-f compose.yaml -f overrides/compose.mariadb.yaml -f overrides/compose.redis.yaml -f compose.ports.yml"
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF up -d

实测回显(末段):

 Container frappe-helpdesk-1-31-0-stack-queue-short-1 Started
 Container frappe-helpdesk-1-31-0-stack-backend-1 Started
 Container frappe-helpdesk-1-31-0-stack-queue-long-1 Started
 Container frappe-helpdesk-1-31-0-stack-scheduler-1 Started
 Container frappe-helpdesk-1-31-0-stack-websocket-1 Started
 Container frappe-helpdesk-1-31-0-stack-frontend-1 Started

查看状态(9 个服务 + 1 个一次性初始化任务):

docker compose --project-name frappe-helpdesk-1-31-0-stack $CF ps --format "table {{.Service}}\t{{.Status}}"

实测回显:

SERVICE       STATUS
backend       Up 21 seconds
db            Up 29 seconds (healthy)
frontend      Up 20 seconds
queue-long    Up 21 seconds
queue-short   Up 21 seconds
redis-cache   Up 29 seconds
redis-queue   Up 29 seconds
scheduler     Up 21 seconds
websocket     Up 21 seconds

configurator 是一次性服务:首次 up 时向公共站点配置写入 db_host、db_port、redis_cache、redis_queue、redis_socketio、socketio_port、chromium_path 后即退出(Exited 状态属正常,restart: on-failure 只在失败时重跑)。

4.4 创建站点并安装 Helpdesk

docker compose --project-name frappe-helpdesk-1-31-0-stack $CF exec backend \
  bench new-site hd.example.com \
  --mariadb-root-password q1w2e3r4 \
  --admin-password q1w2e3r4 \
  --install-app helpdesk

实测回显(末段,进度条略):

Installing frappe...
Updating DocTypes for frappe        : [========================================] 100%
Updating Dashboard for helpdesk
[]
*** Scheduler is disabled ***

站点创建即完成 helpdesk 应用安装(镜像内自带)。开启调度器:

docker compose --project-name frappe-helpdesk-1-31-0-stack $CF exec backend \
  bench --site hd.example.com enable-scheduler
# Enabled for hd.example.com

⚠️ 关键加固步骤(不做出栈重启后会挂,见 11.3):把站点数据库用户的 host 从「创建时的 backend 服务 IP」规范化为任意主机:

docker compose --project-name frappe-helpdesk-1-31-0-stack $CF exec db mariadb \
  -uroot -pq1w2e3r4 \
  -e "RENAME USER '_54c76d77917ea10b'@'172.18.0.6' TO '_54c76d77917ea10b'@'%';"

其中数据库名/用户名取自 site_config.json(docker compose ... exec backend cat sites/hd.example.com/site_config.json 实测回显):

{
 "db_name": "_54c76d77917ea10b",
 "db_password": "jlkoUKNIvH4jwlsI",
 "db_type": "mariadb"
}

host 原值以 SELECT User,Host FROM mysql.user WHERE User='<db_name>'; 实查为准(本文实测为 172.18.0.6)。

4.5 验证

wget -qO- --header "Host: hd.example.com" http://localhost:8080/api/method/ping
# {"message":"pong"}
wget -S -qO /dev/null --header "Host: hd.example.com" http://localhost:8080/helpdesk 2>&1 | head -1
#   HTTP/1.1 200 OK

多站点按 Host 头路由:直接访问 http://<服务器IP>:8080 不带正确 Host 会拿不到目标站点,浏览器验证请把 hd.example.com 解析到服务器 IP(或本机测试写入 hosts)。坐席端地址 http://hd.example.com:8080/helpdesk,账号 Administrator,密码为 4.4 节 --admin-password 设置值。

创建一张工单做数据验证(后端内直接调用 API 层):

docker compose --project-name frappe-helpdesk-1-31-0-stack $CF exec backend \
  bench --site hd.example.com execute frappe.client.insert \
  --kwargs '{"doc": {"doctype": "HD Ticket", "subject": "B2 持久化验证工单"}}'

实测回显(节选——可见 SLA 引擎已自动生效):

{"name": "0002", "owner": "Administrator", "subject": "B2 持久化验证工单", "status": "Open", "priority": "Medium", "sla": "Standard", "response_by": "2026-10-26 12:05:39.745169", "agreement_status": "First Response Due", "doctype": "HD Ticket"}

五、持久化说明

5.1 数据卷布局

官方编排使用三个命名卷(docker volume ls 实测回显):

frappe-helpdesk-1-31-0-stack_db-data
frappe-helpdesk-1-31-0-stack_redis-queue-data
frappe-helpdesk-1-31-0-stack_sites
卷内容挂载点
sites全部站点目录(含 site_config、上传文件、备份)backend / frontend / websocket 共享 /home/frappe/frappe-bench/sites
db-dataMariaDB 数据目录db /var/lib/mysql
redis-queue-data队列 Redis 持久化redis-queue /data

需要把数据直接落在宿主机目录时,官方提供现成 override:追加 -f overrides/compose.bind-mount-db-data.yaml(数据库)或 -f overrides/compose.bind-mount-sites.yaml(站点目录),并按其说明设置宿主路径。

5.2 重启持久化实测

创建工单(4.5 节,count=2)后做完整启停循环:

docker compose --project-name frappe-helpdesk-1-31-0-stack $CF down
docker volume ls --format "{{.Name}}" | grep frappe
# frappe-helpdesk-1-31-0-stack_db-data
# frappe-helpdesk-1-31-0-stack_redis-queue-data
# frappe-helpdesk-1-31-0-stack_sites
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF up -d

重启后复查(实测回显):

2          ← HD Ticket 数量,数据完好
{"message":"pong"}

down 不带 -v 时三个卷全部保留;down -v 会连卷一起删除,等于清库,只应在按第十章恢复演练时使用。

六、环境变量表

以下默认值全部取自 frappe_docker compose.yaml 与 overrides 实查原文:

变量默认值说明
DB_PASSWORD123MariaDB root 密码(db 服务的 MYSQL_ROOT_PASSWORD)
CUSTOM_IMAGEfrappe/erpnext应用镜像仓库,Helpdesk 部署必须改为 ghcr.io/frappe/helpdesk
CUSTOM_TAG$ERPNEXT_VERSION应用镜像标签,Helpdesk 部署设为 stable 或具体版本
PULL_POLICYalways镜像拉取策略;离线/本地已有镜像时设 missing
RESTART_POLICYunless-stopped业务服务重启策略
NGINX_LISTEN_PORT8080frontend(nginx)监听端口
FRAPPE_SITE_NAME_HEADER$$host按 Host 头匹配站点;单站点固定域名时可设为站点名
UPSTREAM_REAL_IP_ADDRESS127.0.0.1真实客户端 IP 的反代来源
UPSTREAM_REAL_IP_HEADERX-Forwarded-For真实 IP 传递头
UPSTREAM_REAL_IP_RECURSIVEoff递归解析真实 IP
PROXY_READ_TIMEOUT120nginx 上游读超时(秒)
CLIENT_MAX_BODY_SIZE50m上传体积上限
GUNICORN_WORKERS2backend gunicorn 进程数
GUNICORN_THREADS4backend gunicorn 线程数
GUNICORN_TIMEOUT120gunicorn 请求超时(秒)
DB_HOST / DB_PORT由 mariadb override 注入 db / 3306configurator 写入公共配置
REDIS_CACHE / REDIS_QUEUE由 redis override 注入 redis-cache:6379 / redis-queue:6379同上
SOCKETIO_PORT9000(固定)websocket 服务端口

七、配置说明

分层配置模型:

  • 编排层:.env + 四个 -f 文件,决定「跑什么镜像、怎么联网、卷怎么挂」;
  • 公共站点配置:configurator 首次启动写入 sites 卷下 common_site_config.json(db_host、redis 地址、socketio_port 等),可用 docker compose ... exec backend bench set-config -g <键> <值> 修改;
  • 站点配置:sites/<站点名>/site_config.json(db_name、db_password、maintenance_mode 等),修改方式与逐键含义见本专栏《Frappe Helpdesk 1.31 配置参数详解》。

站点内配置修改示例(改完无需重启 backend,即时生效):

docker compose --project-name frappe-helpdesk-1-31-0-stack $CF exec backend \
  bench --site hd.example.com set-config maintenance_mode 1

八、挂载与数据卷管理

常用运维操作(均已实测):

# 查看卷占用
docker volume ls --format "{{.Name}}" | grep frappe-helpdesk

# 进入 backend 交互终端
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF exec backend bash

# 把备份产物从 backend 拷到编排目录(配合第十章恢复演练)
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF \
  cp backend:/home/frappe/frappe-bench/sites/hd.example.com/private/backups/. ./backups/

生产建议:至少把 sites 卷对应的站点目录(含 private/backups)纳入定期备份计划;数据库卷可用快照 + bench --site backup 双通道兜底。

九、与等价 docker run 的关系

Helpdesk 官方发布形态就是多服务编排(backend、frontend、websocket、两个队列 worker、scheduler、db、双 Redis,共 9 个常驻服务 + 1 个一次性 configurator),没有官方单容器镜像。用裸 docker run 等价复现需要手工建网络、逐个起 9 个容器、手工对齐共享卷与依赖顺序,可维护性远低于 compose,因此本文不提供逐步 docker run 形态,直接采用官方 compose 文件(其本身即「docker run 参数的声明式写法」)。理解 compose 内部发生了什么的最小等价视角:up -d = 建网 + 按依赖顺序 run 全部服务;down = stop + rm(卷默认保留)。

十、日常运维命令

CF="-f compose.yaml -f overrides/compose.mariadb.yaml -f overrides/compose.redis.yaml -f compose.ports.yml"

# 状态与日志
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF ps
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF logs -f backend

# 重启单个服务
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF restart scheduler backend

# 数据库备份(含附件)
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF exec backend \
  bench --site hd.example.com backup --with-files

备份实测回显:

Backup Summary for hd.example.com at 2026-10-23 12:08:07.718592
Config  : ./hd.example.com/private/backups/20261023_120807-hd_example_com-site_config_backup.json 94.0B
Database: ./hd.example.com/private/backups/20261023_120807-hd_example_com-database.sql.gz         270.8KiB
Public  : ./hd.example.com/private/backups/20261023_120807-hd_example_com-files.tar               10.0KiB
Private : ./hd.example.com/private/backups/20261023_120807-hd_example_com-private-files.tar       10.0KiB
Backup for Site hd.example.com has been successfully completed with files

备份产物位于 sites 卷 hd.example.com/private/backups/ 下,按第八章 compose cp 拷出留存。

10.1 灾难恢复闭环(实测)

目标场景:三个卷全部丢失后,从备份文件把站点恢复回来。以下为本文实测通过的全流程:

# 1. 彻底清场(卷一并删除,模拟灾难)
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF down -v

# 2. 全新拉起并创建同名空站点(仍需 --install-app helpdesk 提供表结构)
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF up -d
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF exec backend \
  bench new-site hd.example.com --mariadb-root-password q1w2e3r4 --admin-password q1w2e3r4 --install-app helpdesk

# 3. 把第十章拷出的备份文件送回 backend
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF cp \
  ./backups/20261023_121003-hd_example_com-database.sql.gz backend:/tmp/
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF cp \
  ./backups/20261023_121003-hd_example_com-files.tar backend:/tmp/
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF cp \
  ./backups/20261023_121003-hd_example_com-private-files.tar backend:/tmp/

# 4. 恢复(显式传 root 密码,避免交互卡住)
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF exec backend \
  bench --site hd.example.com restore /tmp/20261023_121003-hd_example_com-database.sql.gz \
  --db-root-password q1w2e3r4 \
  --with-public-files /tmp/20261023_121003-hd_example_com-files.tar \
  --with-private-files /tmp/20261023_121003-hd_example_com-private-files.tar

恢复完成实测回显(MariaDB 11.8 警告属官方已知提示,可忽略):

Warning: MariaDB version ['11.8', '9'] is more than 10.8 which is not yet tested with Frappe Framework.
App frappe already installed
Site hd.example.com has been restored with files

恢复后复核(实测回显):

2          ← 恢复前创建的工单数量
{"message":"pong"}

10.2 版本升级

# 1. 修改 .env 中 CUSTOM_TAG(如 stable → v1.32.0,或保持 stable 重新拉取)
# 2. 拉新镜像并重建业务服务
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF pull
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF up -d
# 3. 数据库迁移(所有站点)
docker compose --project-name frappe-helpdesk-1-31-0-stack $CF exec backend bench --site hd.example.com migrate

升级前务必先执行第十章备份;stable 标签跨大版本时先阅读官方 release notes 中的 breaking change 说明。

十一、常见问题与排障实录

11.1 project name 含点号被拒 现象:invalid project name "frappe-helpdesk-1.31.0-stack": must consist only of lowercase alphanumeric characters, hyphens, and underscores ...。解决:改用连字符命名(本文 frappe-helpdesk-1-31-0-stack)。

11.2 部署完 8080 端口不通 原因:现行 frappe_docker compose.yaml 默认不发布端口(预期前面有反代)。解决:按 4.2 加 compose.ports.yml override 或自建反代。

11.3 重启后全站 500,backend 日志 Access denied for user 实测现象:docker compose down → up 后接口报 pymysql.err.OperationalError: (1045, "Access denied for user '_54c76d77917ea10b'@'172.18.0.8' (using password: YES)"),frontend 返回 500。根因:bench new-site 在 db 服务内创建的站点用户,其 host 字段被钉死为创建时 backend 的容器 IP(实测 172.18.0.6);服务重建后 backend 换了 IP(172.18.0.8),授权记录不再匹配。解决:建站后立即执行 4.4 节的 RENAME USER ...@'%' 规范化;已踩坑时对现存用户执行同样的 RENAME USER 即可,无需重建数据。

11.4 configurator 一直 Exited 属正常:它是一次性初始化任务,成功退出即完成使命。只有反复重启失败时才需要 docker compose logs configurator 排查(常见原因是 db 未 healthy 就被拉起,编排已通过 condition: service_healthy 规避)。

11.5 bench restore 卡在 MySQL root password 交互 原因:restore 需要 root 权限重建数据库,未传参会交互询问,脚本/管道场景直接挂住。解决:加 --db-root-password <密码>(见 10.1)。

11.6 恢复时报 MariaDB version more than 10.8 not yet tested 官方对 MariaDB 11.x 的兼容性提示,实测备份恢复全流程可正常完成(本文 10.1 节即在该警告下通过)。保守派可将 override 中 db 镜像改回 mariadb:10.6 并重建卷。

11.7 wget/curl 测试时 Host 头必须带上 多站点按 Host 路由,--header "Host: hd.example.com" 缺失时命中的不是目标站点(表现为 404 或默认站点)。生产环境靠 DNS 解析自然携带正确 Host。

十二、参考链接