Zammad 常用 CLI 命令详解

Zammad 7.2.2 三层命令面逐条实测:zammad 包装器全子命令树、systemd 服务管理、rake/rails 高频任务(索引重建/数据库/系统报告)与 rails r 实战脚本(密码重置/API Token),含排障实录。

Zammad工单系统邮件服务器2026/10/21

Zammad 常用 CLI 命令详解

目标:系统整理 Ubuntu 22.04 包安装形态下 Zammad 7.2.2 的三层命令面——zammad 包装器、systemd 服务单元、Rails/Rake 任务——并把运维高频操作(服务管理、日志、搜索索引重建、数据库任务、管理员密码重置、API Token 创建等)逐条跑通「命令 → 实测回显 → 结果验证」。本文全部命令与回显均在 Zammad 7.2.2 实测环境(Ubuntu 22.04 包安装,安装过程见《Ubuntu 22.04 安装 Zammad 指南》)执行通过(2026-10-21)。

一、环境信息

本章给出本文所有命令的实测环境基线,读者在相近环境(Ubuntu 20.04/24.04 包安装)下可对号入座。

  • 操作系统:Ubuntu 22.04 (jammy),x86_64
  • Zammad 版本:7.2.2-1792508402.43c767a.ubuntu22(官方 packager.io stable 仓库安装,zammad run rails r "puts Version.get" 实测回显;上游最新稳定版 2026-10-21 复查仍为 7.2.2,7.3.0 尚处 alpha 预发布,见《Zammad 7.2.2 介绍与选型指南》)
  • Elasticsearch:9.5.5(搜索索引后端)
  • PostgreSQL:14.24(业务数据库 zammad)
  • Redis:6.0.16(缓存与会话后端)
  • Nginx:1.18.0(反向代理,Web 入口 80 端口)
  • 安装路径:/opt/zammad/,配置目录 /etc/zammad/,日志目录 /var/log/zammad/
  • 运行用户:zammad(uid 999)
  • 示例管理员账号:admin / 密码 q1w2e3r4(邮箱 admin@lab.local,首次向导创建,密码策略实测结论见《Ubuntu 22.04 安装 Zammad 指南》第六章)

💡 说明:本文主线命令均在 root(或 sudo)环境执行;zammad run 系列命令无论由谁发起,实际都会降权到 zammad 用户执行(实测验证见 4.2 节)。

二、工具概览

本章先建立 Zammad 命令面的全景认知:包安装形态下,Zammad 的运维命令分布在三层,各自解决不同问题,混用是新手最常见的出错来源。

层次命令入口管什么典型场景
包装器层/usr/bin/zammad应用级封装:以 zammad 用户跑 Rails/Ruby、看日志、设环境变量、重启服务日常运维首选入口
服务管理层systemctl进程生命周期:状态、启停、开机自启、journal 日志排障、确认服务健康
应用任务层zammad run rails/rake <task>数据与索引:迁移、种子、搜索索引重建、系统报告升级、索引异常、巡检

三层的分工与依赖关系:

  • 包装器层是官方推荐的应用入口(/usr/bin/zammad 由包安装生成,pkgr 工具链打包),它解决两个关键问题:一是降权——Zammad 不允许以 root 运行 Rails 进程,zammad run 自动切换到 zammad 用户并加载 /etc/default/zammad 与 /etc/zammad/conf.d/ 的环境变量;二是跨发行版一致——restart、scale 等子命令在内部转译为对应发行版的 systemctl 调用,命令形态不随发行版变化。
  • 服务管理层是 systemd 原生能力。包安装为 Zammad 注册了一组 systemd 单元(详见第五章),zammad restart 底层就是调 systemctl,但当你需要 systemctl status、journalctl -u 这类细粒度排障时,必须直接面对 systemctl。
  • 应用任务层是 Ruby on Rails 框架的 rake 任务体系。Zammad 的数据面操作(数据库迁移、搜索索引、系统报告、翻译同步)全部以 rake 任务形式提供,且必须通过 zammad run 包装执行——直接以 root 跑 /opt/zammad/bin/rails 会因运行用户与环境变量不对而失败。

💡 技术拓展:Rails 应用的任务入口有 rake 与 rails 两套形态(rake db:migrate 与 rails db:migrate)。Rails 5 起官方推荐 rails 形态(它先加载 Rails 环境再分发任务,能感知应用上下文),rake 形态仍兼容。本文实测两种形态在 Zammad 7.2.2 下等价可用(对比验证见 6.2 节),行文统一采用官方文档使用的 zammad run rails <task> 形态。

三、前置条件

本章列出具实测命令的前提检查项,全部满足后后续章节命令可直接照做。

  1. Zammad 已完成包安装并跑通初始化:本文命令基于「官方仓库在线安装 + 首次设置向导已完成」的实例(zammad 服务 active、Web 可访问)。从零安装见《Ubuntu 22.04 安装 Zammad 指南》。
  2. 以 root 或具备 sudo 权限的用户登录服务器:包装器与 systemctl 操作均需 root 权限(写 /etc/zammad/conf.d/、调 systemctl)。
  3. 确认服务在跑:
systemctl is-active zammad

实测回显:

active
  1. 确认应用版本(本文所有回显基于该版本):
zammad run rails r "puts Version.get"

实测回显:

7.2.2-1792508402.43c767a.ubuntu22

⚠️ 注意:若 zammad 命令提示不存在,说明包装器未安装(通常只出现在手工解包场景),包安装(apt/yum)默认都会生成 /usr/bin/zammad。

四、zammad 包装器命令详解

本章逐条实测 /usr/bin/zammad 包装器的全部子命令。先看总览,再按「执行入口 → 日志 → 配置 → 伸缩 → 重启」的运维动线逐个展开。

4.1 命令总览(usage 全文)

不带任何参数执行 zammad,包装器会打印完整用法说明并以退出码 64 结束——这份 usage 就是包装器的「官方命令清单」,逐字照录如下:

zammad

实测回显(完整):

Usage:
  zammad run COMMAND [options]
  zammad scale TYPE=NUM
  zammad logs [--tail|-n NUMBER]
  zammad config:get VAR
  zammad config:set VAR=VALUE
  zammad config:unset VAR
  zammad configure
  zammad reconfigure
  zammad restart

Details:
  zammad configure [-f FILE|-]
    * If using an installer:
      This command will launch the installer wizard.
      You can pass the installer seed file as argument or on STDIN.
   * Without installer:
      This will execute the configure script at /opt/zammad/packaging/scripts/configure (if any).
      A file containing environment variables can be given as argument or on STDIN (-f -), and will be saved in the /etc/zammad/conf.d folder.

  zammad reconfigure
    This command allows to reconfigure the application. Only useful if using an installer.

  zammad restart [process]
    This will restart the application (or the given process), in a distribution-independent manner.

对 usage 的逐项解读:

子命令功能本章小节
run COMMAND以 zammad 用户执行任意命令(Rails 控制台、rake 任务、单行脚本)4.2–4.5
scale TYPE=NUM调整某类进程的实例数4.8
logs聚合查看应用日志4.6
config:get/set/unset读写环境变量配置4.7
configure安装器向导(或执行包的 configure 脚本)4.9
reconfigure重新配置(仅安装器场景有效)4.9
restart [process]重启全部或指定进程4.9

⚠️ 注意:usage 里没有 status 子命令。实测输入 zammad status 会得到与上面完全相同的 usage 输出并以退出码 64 退出——状态检查要走 systemctl(排障实录见 4.10 节,服务状态检查方法见 5.2 节)。

包装器启动时加载的环境文件是 /etc/default/zammad(定义应用路径与运行身份),内容实测如下:

cat /etc/default/zammad

实测回显(完整):

# Generated by pkgr
export APP_HOME="/opt/zammad"
export APP_NAME="zammad"
export APP_SAFE_NAME="zammad"
export APP_GROUP="zammad"
export APP_USER="zammad"
export APP_WIZARDS=""
export APP_RUNNER_TYPE="systemd"
export APP_RUNNER_CLI="systemctl"
export PORT=${PORT:=6000}

export HOME="/home/zammad"

逐项说明:APP_HOME(应用根目录 /opt/zammad)、APP_USER/APP_GROUP(降权目标 zammad:zammad)、APP_RUNNER_CLI(包装器转译 systemctl 的依据,确认本环境为 systemd 托管)、PORT(内部基线端口,默认 6000,与 Puma 实际监听的 3000 不同,后者由 systemd 单元模板单独指定)、HOME(zammad 用户家目录)。

4.2 zammad run:以应用身份执行任意命令

zammad run 是整个命令面中使用频率最高的入口:它把 COMMAND 放到「zammad 用户 + 应用环境变量 + production 环境」的完整上下文里执行。无论是跑 Rails 控制台、rake 任务还是一段 Ruby,都要经过它。

先验证它的降权行为——让 Rails 打印当前进程的 uid 与用户名:

zammad run rails r "require 'etc'; puts Process.uid; puts Etc.getpwuid(Process.uid).name"

实测回显:

999
zammad

uid 999 对应 zammad 用户,证明即使以 root 发起,zammad run 内部也完成了降权。这正是「Zammad 拒绝 root 运行」约束下的标准做法:永远通过 zammad run 执行应用侧命令,不要手工 su - zammad 再拼环境变量。

zammad run 最常用的三个通道(后续小节逐一展开):

通道形态用途
单行 Rubyzammad run rails r "<Ruby 代码>"快速查询/修改数据,自动化脚本
交互控制台zammad run console交互式探索与调试(pry)
rake 任务zammad run rails <task> / zammad run rake <task>官方预置的运维任务

4.3 zammad run rails r:单行 Ruby 运维脚本

rails r(runner)把一段 Ruby 代码放进完整 Rails 环境执行,是免交互的数据操作通道。查一个配置项:

zammad run rails r "puts Setting.get('product_name')"

实测回显:

Quzuo Lab Helpdesk

(product_name 是本实例在首次向导中设置的组织名,该参数的完整实测见《Zammad 7.2.2 配置参数详解》第四章。)

统计类查询同样一行搞定:

zammad run rails r "puts User.count"
zammad run rails r "puts Ticket.count"

实测回显(两条分别执行):

3
1

更多实战脚本(管理员查询、密码重置、Token 创建)集中在第七章。

4.4 zammad run console:交互式控制台(pry)

需要多步探索、反复试错时用交互控制台。它加载 production 环境的完整应用上下文,交互 shell 是 pry:

zammad run console

实测进入后的头部回显(随后执行一条查询并退出):

Loading production environment (Rails 8.0.5.1)
[1] pry(main)> Setting.get('product_name')
[1] pry(main)> exit

逐行说明:Loading production environment (Rails 8.0.5.1) 表示已加载 production 环境(Zammad 7.2.2 基于 Rails 8.0.5.1);[1] pry(main)> 是 pry 的提示符,可直接调用任何模型与 Setting;exit 退出。

⚠️ 注意:在非交互管道里喂入代码时,pry 会对回显做 TTY 检测,命令结果的打印可能不显示(tput 相关告警同理)。非交互场景请改用 4.3 节的 rails r,它在管道下输出行为完全确定。

4.5 zammad run rails routes 与 dbconsole

routes 打印全部 HTTP 路由表,用于确认某 API 端点是否存在及其控制器(API 全集见《Zammad 7.2.2 介绍与选型指南》对 API 能力的概述):

zammad run rails routes

实测回显(头部节选,实际输出数百行):

                                                         Prefix Verb                        URI Pattern                                                                                       Controller#Action
                                                           init GET                         /init(.:format)                                                                                   init#index
                                                            app GET                         /app(.:format)                                                                                    init#index
                                                           root GET                         /                                                                                                 init#index
                                                                POST|PUT|DELETE|OPTIONS     /                                                                                                 errors#routing
                                         api_v1_activity_stream GET                         /api/v1/activity_stream(.:format)                                                                 activity_stream#show
                                               api_v1_ai_agents GET                         /api/v1/ai_agents#index
                                        api_v1_ai_agents_search GET|POST                    /api/v1/ai_agents/search(.:format)                                                                ai_agents#search

(输出节选——实测首部 8 行;实际表很宽,终端下可配合 grep api_v1_ticket 过滤目标端点。)

dbconsole(简写 db)直接打开业务数据库的命令行客户端(本环境为 PostgreSQL 的 psql),并按 config/database.yml 自动带上连接参数。执行一条 SQL 验证:

zammad run rails dbconsole

进入 psql 后输入 SQL 与退出命令:

SELECT count(*) FROM users;
\q

实测回显:

 count
-------
     3
(1 row)

与 4.3 节 User.count 的结果 3 一致,两条通道可互为验证。

4.6 zammad logs:日志聚合查看

zammad logs 一次性聚合展示三路日志:应用主日志 /var/log/zammad/production.log、搜索索引重建日志 /var/log/zammad/searchindex-rebuild.log、以及 systemd journal 中 zammad 服务的输出(Puma 启动信息等)。默认每个文件展示尾部若干行,--tail N(或 -n N)控制行数:

zammad logs --tail 3

实测回显(节选,三个日志源依次出现):

==> /var/log/zammad/production.log <==
I, [2026-10-21T06:43:04.887813#11034-91224]  INFO -- : execute Channel.fetch_async (try_count 0)...
I, [2026-10-21T06:43:04.888195#11034-91224]  INFO -- : ended Channel.fetch_async took: 0.001650461 seconds.
I, [2026-10-21T06:43:12.675907#11034-90680]  INFO -- : ProcessScheduledJobs running...

==> /var/log/zammad/searchindex-rebuild.log <==
I, [2026-10-21T04:22:39.626531#8322-2944]  INFO -- : Using Zammad's file store as Rails cache store.
There was an error trying to connect to Redis.
#<Redis::CannotConnectError: Failed to connect to localhost:6379 (ECONNREFUSED) (redis://localhost:6379)>

Oct 21 04:30:02 zammad[11030]: Puma starting in single mode...
Oct 21 04:30:02 zammad[11030]: * Puma version: 8.0.2 ("Into the Arena")
Oct 21 04:30:02 zammad[11030]: * Listening on http://127.0.0.1:3000

(输出节选——实测首尾;中间的 journal 段与 production.log 后续行省略。)

三点解读:

  • 每段开头的 ==> 文件路径 <== 标明日志来源,tail -f 式的连续查看可对单个文件直接 tail -f /var/log/zammad/production.log。
  • searchindex-rebuild.log 里出现 Redis 连接失败属历史残留:那是本实例早期(Redis 未就绪时)一次重建尝试的记录,时间戳 04:22 早于当前会话;当前 Redis 已正常(production.log 中任务调度持续输出即可佐证)。读到旧报错先看时间戳,不要被历史日志误导——这是日志聚合命令最典型的误读场景。
  • journal 段显示 Puma 监听 127.0.0.1:3000,对外 80 端口由 Nginx 反代(架构见《Zammad 7.2.2 介绍与选型指南》)。

4.7 zammad config:get / config:set / config:unset:环境变量配置

这一组子命令管理的是进程环境变量(如 Ruby GC 参数、RAILS_LOG_TO_STDOUT),落盘位置为 /etc/zammad/conf.d/ 目录——注意它与数据库里的业务配置(Setting 体系)是两套体系:环境变量影响进程行为,Setting 影响业务功能(后者见《Zammad 7.2.2 配置参数详解》)。

先读一个内置变量:

zammad config:get PORT

实测回显:

6000

写入一个测试变量并查看落盘文件:

zammad config:set TEST_CLI_DEMO=hello
cat /etc/zammad/conf.d/other

实测回显(config:set 本身无输出;other 文件内容如下):

export MALLOC_ARENA_MAX="2"
export RUBY_GC_MALLOC_LIMIT="1077216"
export RUBY_GC_MALLOC_LIMIT_MAX="2177216"
export RUBY_GC_OLDMALLOC_LIMIT="2177216"
export RUBY_GC_OLDMALLOC_LIMIT_MAX="3000100"
export RAILS_LOG_TO_STDOUT=""
export TEST_CLI_DEMO="hello"

逐项解读:文件里前 6 行是包安装预置的 Ruby 内存分配器(glibc malloc arena)与 GC 调优参数——这是 Zammad 官方为 Ruby 进程做的性能默认值,非特殊性能问题不要动;最后一行 export TEST_CLI_DEMO="hello" 就是刚才 config:set 追加的。读回验证:

zammad config:get TEST_CLI_DEMO

实测回显:

hello

删除测试变量并确认:

zammad config:unset TEST_CLI_DEMO
zammad config:get TEST_CLI_DEMO

实测回显(unset 无输出;get 一个不存在的变量无输出且退出码为 1):

(无输出,退出码 1)

⚠️ 注意:config:set 修改的是环境变量文件,已运行进程不会自动重载,改完需要 zammad restart 才对新启动的进程生效。

4.8 zammad scale:进程实例伸缩

scale 调整某类进程的 systemd 实例数(基于 /usr/share/zammad/scaling/systemd/ 下的单元模板实例化)。先试一个幂等操作——把 web 进程设为 1 实例(当前就是 1):

zammad scale web=1

实测回显:

Nothing to do.

Nothing to do. 说明目标状态与当前一致,无需变更。scale 不带参数时静默退出(退出码 0,无输出)。

可伸缩的进程类型就是第五章 systemd 单元清单中的五类:web(HTTP 服务)、websocket(长连接推送)、worker(后台任务调度)、rake/console(按需拉起的临时实例类型)。小规模部署保持默认 1 实例即可;当单实例 CPU 持续打满时,可 zammad scale web=2 横向加实例(每个实例是一个独立 systemd 单元 zammad-web-1、zammad-web-2,以此类推)。

4.9 zammad restart / configure / reconfigure

restart 重启应用进程组,可全量重启,也可只重启指定进程(web、websocket、worker 之一):

zammad restart web
systemctl is-active zammad-web

实测回显(restart 静默完成,退出码 0;验证命令输出):

active

全量重启同样静默:

zammad restart

实测回显:无输出,退出码 0。重启后用 systemctl is-active zammad 验证回到 active(实测通过)。

⚠️ 注意:restart 执行期间(通常数秒到十几秒)Web 界面会短暂不可用,脚本化重启建议在 restart 之后轮询 systemctl is-active 直到恢复再继续。

configure 与 reconfigure 属于安装器(Linux 一键安装脚本)场景的命令:有安装器时 configure 启动配置向导(可从文件或标准输入传入种子变量),无安装器时它转而执行 /opt/zammad/packaging/scripts/configure(若存在)。本环境是 apt 包安装、无安装器且包内无 configure 脚本,实测两条命令均静默成功(无输出,退出码 0)——包安装用户无需关心这两个命令。

4.10 排障实录:zammad status 不是有效子命令

排查服务状态时,直觉会敲 zammad status(很多同类工具确实有该子命令),但 Zammad 包装器没有这个子命令:

zammad status

实测回显(完整 usage,同 4.1 节):

Usage:
  zammad run COMMAND [options]
  zammad scale TYPE=NUM
  zammad logs [--tail|-n NUMBER]
  zammad config:get VAR
  zammad config:set VAR=VALUE
  zammad config:unset VAR
  zammad configure
  zammad reconfigure
  zammad restart
...

退出码实测为 64(usage 的固定退出码)。

定位过程:从 4.1 节 usage 全文可见子命令清单里没有 status;包装器脚本头部(/usr/bin/zammad 由 pkgr 生成)确认 APP_RUNNER_TYPE="systemd",状态查询归 systemctl 管。

解决方案:状态检查一律用 systemctl(完整用法见第五章):

systemctl is-active zammad

实测回显:

active

五、systemd 服务管理

包装器只覆盖「重启」这一类生命周期操作;状态细查、单服务启停、开机自启、journal 日志都要直接面对 systemd。本章给出 Zammad 包注册的完整单元清单与高频 systemctl 操作。

5.1 服务单元清单与架构

systemctl list-units 'zammad*' --no-pager --no-legend

实测回显(完整):

  zammad-web-1.service       loaded active running zammad-web-1.service
  zammad-web.service         loaded active running zammad-web.service
  zammad-websocket-1.service loaded active running zammad-websocket.service
  zammad-websocket.service   loaded active running zammad-websocket.service
  zammad-worker-1.service    loaded active running zammad-worker-1.service
  zammad-worker.service      loaded active running zammad-worker.service
  zammad.service             loaded active running zammad.service

单元命名与架构解读:

单元角色
zammad.service汇总单元(不含进程),聚合下面三组,systemctl is-active zammad 查的是它
zammad-web.service + zammad-web-1.serviceHTTP 服务(Puma,监听 127.0.0.1:3000);-1 是第 1 实例,scale web=N 会增减 -N 实例
zammad-websocket.service + zammad-websocket-1.serviceWebSocket 长连接服务(会话推送)
zammad-worker.service + zammad-worker-1.service后台任务调度器(邮件收取、定时任务、通知发送)

💡 技术拓展:这种「基础单元 + -N 实例单元」的组合是 systemd 模板单元思想的手工应用(同族方案还有 @ 模板单元如 zammad-web@1.service,以及 socket 激活)。pkgr 选择显式 -N 命名是为了让 zammad scale 能用确定的单元名直接 start/stop 对应实例。对本运维而言只需记住:实例数交给 zammad scale 管,单元本身不要手工增删。

依赖组件 PostgreSQL、Redis、Elasticsearch、Nginx 各自独立单元(postgresql、redis-server、elasticsearch、nginx),不在 zammad* 命名空间内,全链路巡检时要一并检查。

5.2 状态检查与进程验证

三个状态命令的分工与实测回显:

systemctl is-active zammad

实测回显:

active

(单值结论,适合脚本判断;可能的取值还有 inactive、failed。)

systemctl status zammad-web

实测回显(头部节选):

● zammad-web.service - Zammad web
     Loaded: loaded (/etc/systemd/system/zammad-web.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2026-10-21 12:29:57 CST; 2h 30min ago
   Main PID: 11030 (puma)
      Tasks: 9 (limit: 4650)
     Memory: 250.0M
        CPU: 33.655s
     CGroup: /system.slice/zammad-web.service
             └─11030 puma 8.0.2 (tcp://127.0.0.1:3000) [Zammad]

(输出节选——实测首部;进程列表段省略。)可以看到 web 服务的二进制是 Puma 8.0.2、监听 tcp://127.0.0.1:3000、开机自启已启用(enabled)。

全链路健康验证(Web 入口可达性):

curl -sI http://127.0.0.1/ | head -1

实测回显:

HTTP/1.1 200 OK

5.3 单服务重启与日志

改配置后往往只需重启单个服务而非全量 zammad restart(例如只动了 Nginx 配置就只 reload Nginx):

systemctl restart zammad-web
systemctl is-active zammad-web

实测回显:

active

journal 方式查看单个服务的实时日志(与 zammad logs 相比,journal 能看到进程启动期的标准输出,如 Puma 横幅):

journalctl -u zammad-web --since "10 minutes ago" --no-pager

实测回显(节选):

Oct 21 04:30:02 zammad[11030]: => Run `bin/rails server --help` for more startup options
Oct 21 04:30:02 zammad[11030]: Puma starting in single mode...
Oct 21 04:30:02 zammad[11030]: * Puma version: 8.0.2 ("Into the Arena")
Oct 21 04:30:02 zammad[11030]: * Ruby version: ruby 3.4.9 (2026-03-11 revision 76cca827ab) +YJIT +PRISM [x86_64-linux]
Oct 21 04:30:02 zammad[11030]: *  Min threads: 5
Oct 21 04:30:02 zammad[11030]: *  Max threads: 30
Oct 21 04:30:02 zammad[11030]: *  Environment: production
Oct 21 04:30:02 zammad[11030]: *          PID: 11030
Oct 21 04:30:02 zammad[11030]: * Listening on http://127.0.0.1:3000

(输出节选——实测首部;启动完成后的运行期日志省略。)从回显可直接读到运行时关键值:Ruby 3.4.9(启用 YJIT)、Puma 线程池 5–30、production 环境。

六、常用 rake / rails 任务详解

数据面运维(迁移、索引、报告)以 rake 任务提供,全部经 zammad run 执行。本章按「清单 → 数据库 → 搜索索引 → 系统报告 → 其他」展开,每个任务给出实测回显。

6.1 查看任务清单(rails -T)

rails -T 列出全部可用任务及一句话描述,是任务名的权威来源:

zammad run rails -T

实测回显(zammad 命名空间节选,完整清单 100+ 行):

bin/rails zammad:bootstrap:init                              # Initializes a Zammad instance for the first time
bin/rails zammad:bootstrap:reset                             # Resets a Zammad instance and reinitializes it
bin/rails zammad:db:init                                     # Initializes (creates, migrates and seeds) the DB
bin/rails zammad:db:max_connections                          # Calculates recommended max_connections value for PostgreSQL
bin/rails zammad:db:rebuild                                  # Clears the Cache and reloads the Settings
bin/rails zammad:db:reset                                    # Truncates and seeds the database, clears the cache and reloads the settings
bin/rails zammad:searchindex:configured                      # Is the search index backend configured?
bin/rails zammad:searchindex:create                          # Create all search indexes
bin/rails zammad:searchindex:rebuild[worker]                 # Full re-creation of all search indexes and re-indexing of all data
bin/rails zammad:searchindex:refresh                         # Refresh all search indexes
bin/rails zammad:store:move_files                            # Move files/attachments from one store provider to another
bin/rails zammad:store:verify_files                          # Verify files/attachments checksums
bin/rails zammad:system_report                               # Fetches the system report
bin/rails zammad:translations:sync                           # Synchronize latest translations from i18n/*.po to the database

(输出节选——实测经 grep "zammad:" 过滤后的首尾部;zammad:package:*、zammad:email_parser:*、zammad:ci:* 等子族从略,读者以本机 rails -T 输出为准。)

关键差异解读:zammad:db:* 族动数据库(高危),zammad:searchindex:* 族动 Elasticsearch(可安全重跑),zammad:bootstrap:reset 会清空全部数据重新初始化(仅测试环境用)。本章后续小节只展开运维高频且低危的任务。

6.2 数据库任务

数据库任务覆盖版本确认与容量规划。先看当前库的 schema 版本号(判断升级是否完成迁移的依据):

zammad run rails db:version

实测回显:

database: zammad
Current version: 20261009130000

迁移状态明细(每个迁移文件是否已应用):

zammad run rails db:migrate:status

实测回显(首尾节选,完整输出约 300 行):

 database: zammad

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20120101000001  Create base
   up     20120101000010  Create ticket
   up     20150979000001  Update timestamps
...
   up     20261006120000  Add alternative fqdn setting
   up     20261009130000  Alternative fqdn frontend

解读:全部迁移 up 且末行 Migration ID 与 6.2 第一个任务的 Current version 一致(20261009130000),说明 schema 完整无欠账;升级后若出现 down 状态迁移即欠迁移。

zammad:db:max_connections 按实际进程数推荐 PostgreSQL 的 max_connections 值。注意它是交互式任务,会依次询问三类进程数量(Web 实例数 → cron 并发数 → 其他 rails 进程并发数),直接回车取默认值即可。非交互管道下会因读不到 stdin 报错(排障实录见 9.2 节),这里用管道预喂三个默认值(1、0、0):

printf "1\n0\n0\n" | zammad run rails zammad:db:max_connections

实测回显:

Connections pool size: 50
How many web server instances/pods do you have? (DEFAULT=1) WEB_CONCURRENCY=0
ZAMMAD_PROCESS_SESSIONS_JOBS_WORKERS=0
ZAMMAD_PROCESS_SCHEDULED_JOBS_WORKERS=0
ZAMMAD_MANAGE_SESSIONS_JOBS_WORKERS=0
ZAMMAD_PROCESS_DELAYED_JOBS_WORKERS=0
ZAMMAD_PROCESS_DELAYED_AI_JOBS_WORKERS=0
ZAMMAD_PROCESS_DELAYED_COMMUNICATION_INBOUND_JOBS_WORKERS=0
Do you have any cronjobs running Zammad, how many run concurrently? (DEFAULT=0) Do you have any other processes running Zammad via rails command, how many run concurrently? (DEFAULT=0) Total Zammad processes: 3
Recommended PostgreSQL max_connections value: 150

解读:任务先报出每个 Zammad 进程的连接池大小(50,含 6 类 worker 池变量),按「Web 实例 1 + cron 0 + 其他 0」汇总为 3 个进程,最终给出建议值 150。该值与官方安装文档要求 PostgreSQL max_connections 至少 150 吻合,扩容实例后应重跑本任务重新校准(多实例部署的容量规划见《Zammad 7.2.2 介绍与选型指南》硬件参考节)。

补充验证:rake 与 rails 两种入口等价(对照 2 章末尾的技术拓展说明):

zammad run rake db:version

实测回显:

database: zammad
Current version: 20261009130000

与 zammad run rails db:version 输出完全一致。

6.3 搜索索引任务

搜索索引(Elasticsearch)是 Zammad 全文搜索的底座,索引异常(改配置、ES 重装、数据不同步)后的标准动作就是本节任务。先确认索引后端是否已配置:

zammad run rails zammad:searchindex:configured

实测回显:无输出,退出码 0 表示已配置(未配置时退出码非 0)——这个任务用退出码而非文本回答问题,脚本判断应写 zammad run rails zammad:searchindex:configured && echo "configured" 之类的形式。

轻量刷新(把数据库增量同步进索引,秒级):

zammad run rails zammad:searchindex:refresh

实测回显:

Refreshing all indexes... done.

全量重建(删掉全部索引重新创建并回灌数据,数据量大时耗时数分钟到数小时):

zammad run rails zammad:searchindex:rebuild

实测回显(本实例数据量小,全程 6.6 秒;头尾节选):

Dropping indexes... done.
Deleting pipeline... done.
Creating indexes... done.
Creating pipeline... done.
Reloading data...
  - AI::Agent...
    done in 0 seconds.
  - AI::ProviderConnection...
    done in 0 seconds.
  - AI::TextTool...
    done in 0 seconds.
  - AuditLog...
    done in 0 seconds.
  - Chat::Session...
    done in 0 seconds.
  - CoreWorkflow...
    done in 0 seconds.
  - Cti::Log...
    done in 0 seconds.
  - Group...
    done in 0 seconds.
...
  - Ticket...
    done in 0 seconds.
  - Trigger...
    done in 0 seconds.
  - User...
    done in 0 seconds.
  - Webhook...
    done in 0 seconds.

解读:流程为「删索引 → 删管道 → 建索引 → 建管道 → 逐模型回灌」,回灌清单覆盖全部可索引模型(Ticket、User、Organization 等)。验证重建结果——查询一次工单搜索(经 API,确认索引可用):

zammad run rails r "puts Ticket.search(query: '*', limit: 5).count"

实测回显:

1

与 4.3 节 Ticket.count(1 条)一致,索引重建后搜索链路完整可用。

查看每个索引模型的 ES 层配置(字段数上限、分页窗口、分析器):

zammad run rails zammad:searchindex:settings:show

实测回显(节选):

AI::Agent => {"index.mapping.total_fields.limit" => 2000, "index.max_result_window" => 1000000, "analysis.analyzer.default.type" => "custom", "analysis.analyzer.default.tokenizer" => "standard", "analysis.analyzer.default.filter" => ["lowercase", "asciifolding"]}
AuditLog => {"index.mapping.total_fields.limit" => 2000, "index.max_result_window" => 1000000, "analysis.analyzer.default.type" => "custom", "analysis.analyzer.default.tokenizer" => "standard", "analysis.analyzer.default.filter" => ["lowercase", "asciifolding"]}
Ticket => {"index.mapping.total_fields.limit" => 2000, "index.max_result_window" => 1000000, "analysis.analyzer.default.type" => "custom", "analysis.analyzer.default.tokenizer" => "standard", "analysis.analyzer.default.filter" => ["lowercase", "asciifolding"]}

(输出节选——实测首尾部;每行一个模型,中间模型省略。)所有模型默认同构:字段上限 2000、单页最大 1,000,000、standard 分词 + 小写 + ASCII 折叠过滤。中文分词等定制需求通过 settings:set 调整后重建索引生效。

6.4 系统报告任务

zammad:system_report:plugins 列出报告的插件清单(即报告会覆盖的信息面):

zammad run rails zammad:system_report:plugins

实测回显(完整):

["Addons","Channel","Counts","LastCreatedAt","Ticket","User","Environment","FailedEmails","Hardware","MacAddress","Os","PostgreSql","RailsRoot","Redis","Ruby","SearchIndex","Setting","Version"]

zammad:system_report 生成完整报告 JSON(版本、实体计数、环境、硬件等 18 类信息),用于提交技术支持或自检:

zammad run rails zammad:system_report

实测回显(JSON 头部节选,完整输出 40KB+):

{"system_report":{"Addons":[],"Channel":{"Email::Notification":1},"Entities":{"Counts":{"ActiveJobLock":0,"ActivityStream":0,"AI::Agent":0,"AI::Analytics::Run":0,"AI::Analytics::Usage":0,"AI::FeatureProvider":0,"AI::ProviderConnection":0,"AI::StoredResult":0,"AI::TextTool":5,"AuditLog":0,"Authorization":0,"Avatar":2,"Calendar":1,"Channel":2,"Chat::Agent":0,"Chat::Message":0,"Chat::Session":0,"Chat":1,"Checklist::Item":0,"Checklist":0,"ChecklistTemplate::Item":0,"ChecklistTemplate":0,"CoreWorkflow":10,"Cti::CallerId":0,"Cti::Log":0,"DataPrivacyTask":0,"EmailAddress":0,"ExternalCredential":0,"ExternalSync":0,"FailedEmail":0,"Group":1,"History::Attribute":3,"History::Object":5,"History::Type":3,"History":10,"HttpLog":0,"ImportJob":0,"Job":0,...

(输出节选——实测首部;Entities.Counts 后续、Environment、Hardware 等段省略。)解读:Entities.Counts 给出每类实体的数量(如本实例 Setting: 304、Scheduler: 30、Role: 3),巡检时可与业务预期对照;报告末段的 Version 键即应用版本,与 3 节 Version.get 结果一致。

6.5 附件校验与翻译同步

附件存储完整性校验(比对每个附件的校验和,排查存储损坏):

zammad run rails zammad:store:verify_files

实测回显:

Verifying files checksums...
Done.

翻译同步(把打包内置的 i18n 翻译文件刷新进数据库,升级后界面文案未更新时使用):

zammad run rails zammad:translations:sync

实测回显:

Synchronizing the latest translations from i18n/*.po to the database...
done.

七、rails r 实战脚本集

本章沉淀日常运维中最高频的 rails r 一行脚本,全部实测。脚本约定:输出一律 puts,字符串统一用 %q(...) 写字面量避免 shell 引号纠缠——但要注意 %q(...) 内部不做 #{} 插值(实测踩坑见 9.3 节),需要插值时改用双引号并转义。

7.1 系统信息查询

应用版本(排障时先报版本):

zammad run rails r "puts Version.get"

实测回显:

7.2.2-1792508402.43c767a.ubuntu22

读任意业务配置(对照 Setting 名单见《Zammad 7.2.2 配置参数详解》参数速查表):

zammad run rails r "puts Setting.get('fqdn')"

实测回显:

zammad.lab.local

7.2 用户与账号运维

查管理员账号及角色(账号被误改角色后快速核对):

zammad run rails r "u = User.find_by(email: %q(admin@lab.local)); puts [u.id, u.login, u.roles.map(&:name).join(%q(,))].join(%q( | ))"

实测回显:

5 | admin | Admin,Agent

解读:该账号 id=5、登录名 admin、同时具备 Admin,Agent 双角色(首次向导创建的账号即此配置)。

重置管理员密码(忘记密码或被锁时的兜底手段;Zammad 的密码策略对弱口令有复杂度校验,q1w2e3r4 为实测可用的合规值):

zammad run rails r "u = User.find_by(email: %q(admin@lab.local)); u.update!(password: %q(q1w2e3r4)); puts \"password updated for #{u.login}\""

实测回显:

password updated for admin

验证:用新密码登录 Web 界面成功(实测通过);update! 在校验失败(如密码过短)时会直接抛异常中止并打印原因,不会静默半改。

创建 API Token(给第三方集成签发凭据,API 调用方式见官方 API 文档):

zammad run rails r "t = Token.create!(user_id: User.find_by(email: %q(admin@lab.local)).id, name: %q(cli-demo), action: %q(api)); puts t.token"

实测回显:

PKvz069YqVNrfyMgz2Oo0_1UyD02xfP7LNDH30zA-nZP2bQ2qVX7cNUi_MXcuWhb

验证:拿该 Token 调一次 API(HTTP 头 Authorization: Token token=<值>)返回 200(实测通过)。演示 Token 用完立即删除:

zammad run rails r "t = Token.find_by(name: %q(cli-demo)); t.destroy!; puts %q(demo token removed)"

实测回显:

demo token removed

7.3 数据统计

巡检用的计数脚本(用户/工单/组织三件套):

zammad run rails r "puts User.count"
zammad run rails r "puts Ticket.count"
zammad run rails r "puts Organization.count"

实测回显(三条分别执行):

3
1
1

数字与 6.4 节系统报告 Entities.Counts 的对应值一致,两条通道可互为对账。

八、注意事项

综合全部实测,把容易踩坑的约定集中列出:

  1. 一切应用侧命令走 zammad run:它会补齐 zammad 用户身份、production 环境与 /etc/default/zammad + /etc/zammad/conf.d/ 的环境变量。直接以 root 跑 /opt/zammad/bin/rails 会因用户与环境不对而行为异常。
  2. zammad status 不存在:状态检查用 systemctl is-active zammad(4.10 节排障实录)。
  3. 两套配置体系不要混淆:zammad config:* 管进程环境变量(落 /etc/zammad/conf.d/),Setting.get/set 管业务配置(落数据库);改环境变量要 zammad restart 才生效,业务配置多数即时生效。
  4. 交互式 rake 任务在脚本里会卡死或报错:zammad:db:max_connections 等任务依赖 stdin 问答,自动化场景用 printf "1\n0\n0\n" | 预喂答案(9.2 节)。
  5. %q(...) 不插值:rails r 脚本里 puts %q(#{u.login}) 会原样输出 #{u.login};要插值用双引号形式 puts "value: #{u.login}" 并注意 shell 层的引号转义(9.3 节)。
  6. 搜索索引任务按轻重选择:增量同步用 refresh(秒级),动过 ES 配置或索引损坏才 rebuild(全量重建);rebuild 会先删后建,期间搜索结果不全。
  7. zammad:bootstrap:reset、zammad:db:reset、zammad:db:truncate 是销毁级任务:清空数据重新初始化,生产环境禁用。
  8. 日志三路分流:应用日志在 /var/log/zammad/production.log,索引重建在 searchindex-rebuild.log,进程启动输出在 journal——zammad logs 一次聚合三路但每路只给尾部,深查单路时直接对源文件或 journalctl -u 操作。
  9. Token 用完即删:7.2 节演示了创建与销毁闭环;线上长期 Token 应绑定专用集成账号而非管理员,并定期轮换。

九、常见问题(FAQ)

Q1:执行 zammad status 打出一堆 Usage 还退出异常,是不是装坏了? 不是。包装器本来就没有 status 子命令,任何未识别的子命令都会打印完整 usage 并以退出码 64 退出(4.1 节)。状态检查用 systemctl is-active zammad,返回 active 即健康;细查看 systemctl status zammad-web(5.2 节)。

Q2:脚本/管道里跑 zammad:db:max_connections 报 NoMethodError: undefined method 'chomp' for nil? 该任务是交互式的,靠 $stdin.gets 逐个读答案;管道下第一个问题若无输入,gets 返回 nil,chomp 就炸了(实测完整回显见 6.2 节)。解法是预喂答案:任务实际有三问(Web 实例数、cron 并发数、其他 rails 进程数),printf "1\n0\n0\n" | zammad run rails zammad:db:max_connections 即可全自动完成,实测输出 Total Zammad processes: 3 与 Recommended PostgreSQL max_connections value: 150。

Q3:rails r 脚本里 puts 出来的是 #{u.login} 字面量而不是用户名? %q(...) 是 Ruby 的单引号字面量,不做插值。实测:puts %q(password updated for #{u.login}) 输出字面 password updated for #{u.login};改成双引号 puts "password updated for #{u.login}" 后正确输出 password updated for admin。写脚本时字面量用 %q(...)、要插值用双引号(7.2 节两个版本都有实测)。

Q4:zammad run rake about 报 Don't know how to build task 'about'? Zammad 的任务集里没有 about 任务(rake --tasks 可证实)。查看可用任务用 zammad run rails -T(6.1 节);确认数据库版本用 db:version(6.2 节)。同理,任何任务的准确名称都先以 rails -T 输出为准,不要凭其他 Rails 项目的记忆照搬。

Q5:zammad logs 里看到 Redis::CannotConnectError: Failed to connect to localhost:6379,搜索是不是坏了? 先看时间戳。该行来自 searchindex-rebuild.log 的历史段落——本实例 Redis 就绪前的早期重建尝试留下的记录(实测时间戳 04:22,早于服务正常运行的 04:30)。zammad logs 聚合三路日志时会把历史报错一并带出,当前是否健康以 systemctl is-active redis-server 与 production.log 最新时间为准(4.6 节有完整分析)。

Q6:改了 /etc/zammad/conf.d/ 下的变量为什么不生效? 环境变量在进程启动时读取,运行中的进程不会重载。zammad config:set 落盘后执行 zammad restart(或针对单个服务 systemctl restart zammad-web),再验证 zammad run rails r "puts ENV['变量名']" 输出新值(4.7 节实测了 set/get/unset 全闭环)。

十、参考链接