Claper 3.2.0 常用 CLI 命令与工具详解
Claper 3.2.0 服务器运维命令面全解:发布包入口 bin/claper 的 11 个子命令逐一实测(eval/rpc/remote/version/pid)、管理员改密与空壳事件处置实录、SECRET_KEY_BASE 注入与轮换双向会话失效验证、PostgreSQL 42 表备份恢复演练、日志排查路径与 /events 500 KeyError 排障实录。
Claper 3.2.0 常用 CLI 命令与工具详解
目标:系统讲清 Claper 3.2.0 在服务器上的运维命令面——发布包入口
bin/claper的 11 个子命令逐一实测(eval / rpc / remote / version / pid 等)、管理员口令与演示事件的服务器端处置、SECRET_KEY_BASE环境变量注入与轮换验证、PostgreSQL 演示事件数据备份恢复演练、日志排查路径与一则/events500 崩溃排障实录。全部输入输出为 Ubuntu 22.04 运维主机实测(2026-11-01)。部署过程见 《Claper Docker Compose 部署指南》,参数含义见 《Claper 3.2.0 配置参数详解》,产品背景见 《Claper 介绍与选型指南》。
一、环境信息
本文按 systemd 托管的服务器形态叙述:
| 项目 | 值 |
|---|---|
| 操作系统 | Ubuntu 22.04(x86_64) |
| Claper 版本 | 3.2.0(version 子命令实测回显 claper 3.2.0) |
| 运行时 | Erlang/OTP 28(erts-16.0.1)、Elixir 1.18.4、cowboy 2.19.0、phoenix_live_view 1.0.19(均取自实测回显) |
| 发布包安装目录 | /opt/claper,命令入口 /opt/claper/bin/claper |
| 环境变量文件 | /opt/claper/.env(BASE_URL、DATABASE_URL、SECRET_KEY_BASE 等,含义见 C1 篇) |
| 服务单元 | claper.service(启动序列先执行 eval 'Claper.Release.migrate(); Claper.Release.seeds()' 再 start,为官方发布包的既定启动方式) |
| 演示文件存储目录 | /opt/claper/uploads(PRESENTATION_STORAGE_DIR) |
| 数据库 | PostgreSQL 15.19,本机 5432,库/用户均为 claper |
| 对外访问 | http://localhost:8129(BASE_URL) |
| 示例管理账号 | admin@claper.co / q1w2e3r4(官方种子账号 admin@claper.co/claper 部署后已改密) |
二、工具概览
Claper 是 Elixir/Phoenix 发布包(release),全部服务器端运维能力集中在一个入口 /opt/claper/bin/claper,用法帮助以传入未知子命令触发(实测回显逐行照抄):
/opt/claper/bin/claper badcommand
Usage: claper COMMAND [ARGS]
The known commands are:
start Starts the system
start_iex Starts the system with IEx attached
daemon Starts the system as a daemon
daemon_iex Starts the system as a daemon with IEx attached
eval "EXPR" Executes the given expression on a new, non-booted system
rpc "EXPR" Executes the given expression remotely on the running system
remote Connects to the running system via a remote shell
restart Restarts the running system via a remote command
stop Stops the running system via a remote command
pid Prints the operating system PID of the running system via a remote command
version Prints the release name and version to be booted
ERROR: Unknown command badcommand
按运维频率分档:
| 档位 | 子命令 | 用途 |
|---|---|---|
| 日常必用 | version、pid、eval、rpc | 状态核对;冷执行(生成密钥、跑迁移);热执行(查改运行数据) |
| 深入排查 | remote | 连入运行节点的交互式控制台(IEx) |
| 服务控制 | start、start_iex、daemon、daemon_iex、restart、stop | 由服务管理器接管,日常勿手执(见 5.5 与注意事项) |
与常见预期的三处差异(均为实测,防按其他 Phoenix 应用的惯例踩空):
- 没有
migrate子命令。执行/opt/claper/bin/claper migrate实测回显ERROR: Unknown command migrate。迁移走eval 'Claper.Release.migrate()'(见 5.2)。 - 没有
phx.gen.secret子命令。实测同样ERROR: Unknown command phx.gen.secret。生成密钥用eval加 Erlang 随机数,或服务器上的openssl rand -base64 48(见 5.2、第六章)。 - 交互式控制台的子命令名是
remote,不是remote_console(后者实测ERROR: Unknown command remote_console)。
数据平面上还有两组工具配合使用:rpc/remote 里可直接调用应用上下文模块(Claper.Events、Claper.Accounts 等)做业务级查改;数据库层用 pg_dump/psql 做演示事件数据的备份恢复(第七章)。
三、前置条件
- 服务在跑。
/opt/claper/bin/claper pid有回显即运行中;rpc/remote/stop等远程类子命令都要求节点已启动。 - 运维账号对
/opt/claper有执行权限(root 或服务账号均可)。 remote需要交互式终端(有 TTY 的 SSH 会话),非交互管道会失败,见 5.4 实测。- 数据库运维需
psql/pg_dump客户端与凭据:
export PGHOST=127.0.0.1 PGUSER=claper PGPASSWORD=claper PGDATABASE=claper
- 改密、删事件等写操作前,先确认对应业务影响(口令变更会踢掉该用户全部会话,见 5.3)。
四、服务状态核对命令
4.1 version:核对发布版本
/opt/claper/bin/claper version
claper 3.2.0
注意 version 打印的是发布包将启动的版本,与服务当前是否运行无关,适合升级后核对。
4.2 pid:取运行进程号
/opt/claper/bin/claper pid
310
回显为运行节点的操作系统 PID。配合 top -p 310、cat /proc/310/status 可做资源核对;pid 无回显即服务未运行。
4.3 rpc 探活:确认节点真正可服务
/opt/claper/bin/claper rpc 'IO.inspect({:os.getpid() |> List.to_integer(), Application.get_env(:claper, ClaperWeb.Endpoint)[:url][:host]}, label: "info")'
info: {310, "localhost"}
返回 PID 与端点配置,与 4.2 的 pid 相互印证。
五、各命令详解
5.1 eval:冷执行(不起服务的临时系统)
eval "EXPR" 会新起一个未启动的临时系统执行表达式后退出,不与运行节点交互。最小示例:
/opt/claper/bin/claper eval 'IO.puts("eval-ok")'
eval-ok
两个高频运维用途:
(1)生成 SECRET_KEY_BASE(替代不可用的 phx.gen.secret,实测回显为 64 字符 base64):
/opt/claper/bin/claper eval 'IO.puts(:crypto.strong_rand_bytes(48) |> Base.encode64())'
7uxTF9Nr53NY/u50SHOnqKvmwexBtfAaVP58pMUDzfouRfoD8BN1olicnOIf36vW
(此值仅为演示生成、未投入使用;生产生成后直接写入 .env,不要粘贴到聊天/工单。)
(2)手动执行数据库迁移(Claper 3.2.0 的 migrate 命令不存在,官方启动序列即走此表达式):
/opt/claper/bin/claper eval 'Claper.Release.migrate()'
11:53:09.786 [info] Migrations already up
升级发布包后、切换启动新版本前执行一次,回显 Migrations already up 表示 schema 已就位;该表达式幂等,可安全重复执行。
5.2 rpc:热执行(连入运行节点)
rpc "EXPR" 在运行中的节点上执行表达式,能直接访问应用状态(Repo、上下文模块、运行时配置)。
第一个实测坑:rpc 不会自动打印表达式返回值。
/opt/claper/bin/claper rpc 'Node.list()'
(无任何输出,退出码 0)
表达式返回值被丢弃,必须自带 IO.puts/IO.inspect。修正写法与常用查询实测:
统计演示事件数:
/opt/claper/bin/claper rpc 'IO.inspect(Claper.Repo.query!("select count(*) from events").rows, label: "events_count")'
events_count: [[2]]
读取运行时全局配置表 global_configs(Web 界面「实例设置」的落库处,见 C1 篇第三章):
/opt/claper/bin/claper rpc 'IO.inspect(Claper.Repo.query!("select key, value from global_configs order by key").rows, limit: :infinity)'
[
["lti_enabled", "false"],
["transcription_api_key", nil],
["transcription_default_language", nil],
["transcription_enabled", "false"]
]
5.3 rpc 实录:服务器端修改管理员口令
Web 界面不可用(忘记密码、批量建号)时的服务器端处置。用 Claper.Accounts.update_user_password/3,第一个参数是当前口令做校验:
/opt/claper/bin/claper rpc 'u = Claper.Accounts.get_user_by_email("admin@claper.co"); IO.inspect(Claper.Accounts.update_user_password(u, "q1w2e3r4", %{"password" => "S8rotate!", "password_confirmation" => "S8rotate!"}))'
实测回显(成功返回 {:ok, 用户结构体},节选):
{:ok,
#Claper.Accounts.User<
__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
id: 1,
uuid: "fef7588f-708b-4321-8088-fda412f4cd42",
email: "admin@claper.co",
first_name: "Claper",
last_name: "Admin",
is_randomized_password: false,
confirmed_at: ~N[2026-11-01 10:30:33],
locale: nil,
deleted_at: nil,
...
updated_at: ~N[2026-11-01 11:54:10],
>}
curl 走登录接口验证新口令生效(Phoenix 表单参数须为 user[email] 嵌套形式,取 CSRF 令牌的方式见 B2 篇 4.6):
CSRF=$(curl -s -c jar.txt http://localhost:8129/users/log_in \
| grep -oE '<input name="_csrf_token"[^>]*value="[^"]+"' | grep -oE 'value="[^"]+"' | head -1 | cut -d'"' -f2)
curl -s -b jar.txt -c jar.txt -o /dev/null -w "LOGIN_NEWPW=%{http_code} REDIRECT=%{redirect_url}\n" \
-X POST http://localhost:8129/users/log_in \
--data-urlencode "user[email]=admin@claper.co" \
--data-urlencode "user[password]=S8rotate!" \
--data-urlencode "user[remember]=true" \
--data-urlencode "_csrf_token=$CSRF"
LOGIN_NEWPW=302 REDIRECT=http://localhost:8129/events
⚠️ 该函数会连带删除该用户全部 users_tokens(源码中 Ecto.Multi.delete_all(:tokens, ...)),即所有旧会话、记住登录、重置密码链接一次性作废,用户须重新登录。演示进行中切勿对演讲者账号执行。
验证后回滚到基准口令(同法,实测 LOGIN_REVERT=302 REDIRECT=http://localhost:8129/events、后续页面 EVENTS=200):
/opt/claper/bin/claper rpc 'u = Claper.Accounts.get_user_by_email("admin@claper.co"); IO.inspect(Claper.Accounts.update_user_password(u, "S8rotate!", %{"password" => "q1w2e3r4", "password_confirmation" => "q1w2e3r4"}))'
{:ok,
#Claper.Accounts.User<
__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
id: 1,
uuid: "fef7588f-708b-4321-8088-fda412f4cd42",
email: "admin@claper.co",
...
>}
5.4 remote:远程交互式控制台(IEx)
连入运行节点获得完整 Elixir 交互环境,适合逐步试探、查长结构体。
先实测一个坑:remote 需要 TTY。在非交互管道里执行(如 cron、CI 步骤)回显:
Erlang/OTP 28 [erts-16.0.1] [source] [64-bit] [smp:128:6] [ds:128:6:10] [async-threads:1] [jit:ns]
*** ERROR: Shell process terminated! (^G to start new job) ***
节点 banner 出现说明已连上,但 shell 因无终端立即终止——结论:remote 只能在交互式 SSH 会话里用;脚本化需求一律改用 rpc。
交互会话实测记录(登录后逐行键入):
Erlang/OTP 28 [erts-16.0.1] [source] [64-bit] [smp:128:6] [ds:128:6:10] [async-threads:1] [jit:ns]
Interactive Elixir (1.18.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(claper@60a8a7a8937a)1> IO.puts("remote-console-ok")
remote-console-ok
:ok
iex(claper@60a8a7a8937a)2>
提示符 iex(claper@节点名) 中的节点名即运行主机名。控制台内可直接调用 5.2 的全部表达式且返回值自动打印。
退出方式:按 Ctrl+C 进入中断菜单(实测回显):
BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
(l)oaded (v)ersion (k)ill (D)b-tables (d)istribution
按 a(abort)退出——只终止本地 shell 进程,不影响运行节点。切勿在控制台里执行 System.halt() 或 :init.stop(),那会停掉生产节点本身。
5.5 start / restart / stop:服务控制命令
start、daemon 用于前台/后台拉起系统,restart、stop 向运行节点发送远程停机指令。在 systemd 托管形态下日常不要手执这几条:服务主进程就是 start 拉起的节点,stop 会让主进程退出、单元随之进入停止态,restart 同理绕过服务管理器的重启策略与依赖顺序。服务重启统一用:
systemctl restart claper
本文取证环境全程在跑,stop/restart 未实测执行(执行即中断服务),仅给出结论性警告;pid 无回显 + systemctl status claper 是判断服务状态的正规路径。
六、环境变量注入运维与 SECRET_KEY_BASE 轮换
Claper 的全部运行参数经环境变量注入(三层配置体系见 《Claper 3.2.0 配置参数详解》)。运维要点:改 /opt/claper/.env 后必须 systemctl restart claper 才生效——eval/rpc 读到的都是进程已加载的值,改文件不影响运行中的进程。
注入生效的实测验证:为验证轮换影响,在同机以不同环境变量并行起了一个临时实例(端口 8139、数据库指向第七章的恢复库 claper_restore、注入新生成的 SECRET_KEY_BASE),与主实例(SECRET_KEY_BASE 前缀 xvAqu9LW)形成对照:
openssl rand -base64 48 | tee /dev/stderr | wc -c
M8KhDQ8w…(64 字符 base64,全文已省略)
LEN=64
(生成值仅注入临时实例、用后即毁;生产密钥同样不得外传。)
临时实例启动日志(逐行照抄,可见注入的 BASE_URL 生效):
11:57:06.990 [info] Migrations already up
Global settings seeded
11:57:08.300 [info] Running ClaperWeb.Endpoint with cowboy 2.19.0 at 0.0.0.0:4000 (http)
11:57:08.304 [info] Access ClaperWeb.Endpoint at http://localhost:8139
用 eval 读取两个实例已加载的密钥前缀核对注入结果:
/opt/claper/bin/claper eval 'IO.puts("loaded=" <> String.slice(Application.get_env(:claper, ClaperWeb.Endpoint)[:secret_key_base], 0, 8))'
loaded=xvAqu9LW
临时实例上同法执行回显 loaded=M8KhDQ8w——与注入值前缀一致,证明环境变量注入链路(.env → 进程启动 → 端点配置)成立。
轮换的会话影响(实测):会话 cookie 由 SECRET_KEY_BASE 签名,轮换后新旧密钥互不认账,双向验证:
# 主实例(旧密钥)签发的 cookie,访问新密钥实例:
curl -s -b jar.txt -o /dev/null -w "OLDCOOKIE_ON_ROT=%{http_code} REDIRECT=%{redirect_url}\n" http://localhost:8139/events
# 新密钥实例签发的 cookie,访问主实例:
curl -s -b jar4.txt -o /dev/null -w "ROTCOOKIE_ON_MAIN=%{http_code} REDIRECT=%{redirect_url}\n" http://localhost:8129/events
OLDCOOKIE_ON_ROT=302 REDIRECT=http://localhost:8139/users/log_in
ROTCOOKIE_ON_MAIN=302 REDIRECT=http://localhost:8129/users/log_in
两条 302 都跳回登录页:轮换即全员下线,正在演示的演讲者/观众会话全部失效。标准轮换流程:
- 选演示空档;
eval或openssl rand -base64 48生成新密钥,更新/opt/claper/.env的SECRET_KEY_BASE;systemctl restart claper;curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8129/验证返回 200,重新登录确认。
官方 README 特别警告:SECRET_KEY_BASE 泄露或沿用示例值,他人可伪造 user_id=1 的 admin 会话 cookie 直接接管实例(见 B2 篇第三章),泄露后必须立即轮换。
七、数据库运维:演示事件数据备份与恢复
Claper 的业务数据(事件、演示文件元数据、投票、问答、弹幕、用户)全部在 PostgreSQL claper 库,实测共 42 张表;演示文稿本体文件在 /opt/claper/uploads,备份必须库+目录成对做。
7.1 pg_dump 备份
pg_dump -h 127.0.0.1 -U claper claper > claper-backup-20261101.sql
ls -l claper-backup-20261101.sql
-rw-r--r-- 1 root root 110256 Nov 1 19:53 claper-backup-20261101.sql
备份文件头部(逐行照抄)确认来源版本与依赖扩展:
-- Dumped from database version 15.19 (Debian 15.19-1.pgdg13+2)
-- Dumped by pg_dump version 15.19 (Debian 15.19-1.pgdg13+2)
...
CREATE EXTENSION IF NOT EXISTS citext WITH SCHEMA public;
citext 扩展(大小写不敏感邮箱列)会随 dump 重建,目标库须允许该扩展。
7.2 恢复到新库验证
psql -h 127.0.0.1 -U claper -d postgres -c "CREATE DATABASE claper_restore OWNER claper"
psql -h 127.0.0.1 -U claper -d claper_restore -q < claper-backup-20261101.sql
CREATE DATABASE
恢复全程无报错(stderr 空文件),序列值重置输出(setval 若干行)正常。验证表结构与数据:
psql -h 127.0.0.1 -U claper -d claper_restore -c '\dt' -c 'select id, name, code from events order by id'
(42 rows)
id | name | code
----+--------------+--------
1 | Demo Event | demo01
2 | 中文事件测试 | zhtest
(2 rows)
42 张表全量重建,事件数据(含中文事件名)逐行还原——这也是 C1 篇中文编码修复后的回归验证。核心表速览(\dt 实测节选):events(演示事件)、presentation_files/presentation_states(演示文件与播放状态)、polls/poll_ballots/poll_votes(投票)、posts/reactions(弹幕与反应)、quiz_questions/quiz_responses(测验)、form_submits(表单)、users/users_tokens/roles(账号)、global_configs(实例设置)、oban_jobs(后台任务)、audit_logs(审计)。
7.3 表名坑:没有 presentations 表
按直觉查演示文件会踩空(实测):
psql -h 127.0.0.1 -U claper -d claper -c "select count(*) from presentations"
ERROR: relation "presentations" does not exist
LINE 1: select count(*) from presentations
^
真实表名是 presentation_files(文件元数据,含 status、slide_order)与 presentation_states(播放状态)。写巡检 SQL 前先 \dt 确认。
7.4 备份策略建议
- 每日
pg_dump+/opt/claper/uploads目录rsync,两者时间窗对齐(库里的文件哈希指向 uploads 里的实体); - 恢复演练按月做一次,像 7.2 一样恢复到旁库验证行数,勿在生产库直接灌 dump;
- 事件删除是级联的(
events→presentation_files→polls/posts等同删),恢复旁库后如需清理测试数据,优先走 5.4 控制台或rpc的应用层函数,让应用同步清理 uploads 实体文件。
八、日志排查路径
服务日志走标准输出,由 journald 收集:
journalctl -u claper -f # 实时跟踪
journalctl -u claper --since "10 min ago" | grep -v oban # 过滤后台任务噪音
8.1 启动基线
一次正常启动的标志性四行(实测照抄):
11:31:56.521 [info] Migrations already up
Global settings seeded
11:31:57.720 [info] Running ClaperWeb.Endpoint with cowboy 2.19.0 at 0.0.0.0:4000 (http)
11:31:57.723 [info] Access ClaperWeb.Endpoint at http://localhost:8129
缺行定位:无 Migrations already up → 数据库连接/迁移问题(查 DATABASE_URL);有迁移无 Running ... Endpoint → 端口或配置校验失败(对照 C1 篇启动校验规则);Access ... at 后的地址即 BASE_URL 注入结果,观众链接不对先查这行。
8.2 常态噪音(勿当故障)
- 健康探测:
GET /+Sent 200 in 501µs每 30 秒一对,来自服务可用性探测(curl --fail http://localhost:4000); - Oban 任务插件:
{"source":"oban","event":"plugin:stop",...}JSON 行每 30 秒一组,为后台任务队列心跳; - OIDC 周期报错(实测每 60 秒):
[error] GenServer Claper.OidcProviderConfig terminating
** (stop) {:configuration_load_failed, :timeout}
Last message: {:continue, :load_configuration}
未配置 OIDC 单点登录时该进程加载配置超时重启,属已知无害噪音,不影响登录与演示功能;若嫌干扰日志检索,grep -v OidcProviderConfig 过滤即可。
8.3 请求定位
每个请求带 request_id,日志两行成对:
11:54:18.544 request_id=GOPpuUQf7vbfqkIAAhoB [info] GET /events
11:54:18.551 request_id=GOPpuUQf7vbfqkIAAhoB [info] Sent 500 in 6ms
用户反馈页面异常时,让其提供页面源码/响应头里的 request_id,journalctl -u claper | grep GOPpuUQf 直接捞出全链路。
8.4 排障实录:/events 列表页 500(KeyError :status)
现象:管理员登录成功(LOGIN=302 REDIRECT=http://localhost:8129/events),但事件列表页返回 500:
11:54:18.551 request_id=GOPpuUQf7vbfqkIAAhoB [info] Sent 500 in 6ms
11:54:18.551 [error] #PID<0.3271.0> running ClaperWeb.Endpoint (connection #PID<0.3270.0>, stream id 1) terminated
Server: localhost:8129 (http)
Request: GET /events
** (exit) an exception was raised:
** (KeyError) key :status not found in: nil
If you are using the dot syntax, such as map.field, make sure the left-hand side of the dot is a map
(claper 3.2.0) lib/claper_web/live/event_live/event_card_component.ex:577: anonymous fn/2 in ClaperWeb.EventLive.EventCardComponent.render_mobile_card/1
(phoenix_live_view 1.0.19) lib/phoenix_live_view/diff.ex:414: Phoenix.LiveView.Diff.traverse/7
定位:栈顶直指 event_card_component.ex:577 的 render_mobile_card——渲染事件卡片时读演示文件的 status 字段,而该值为 nil。回库核对:
psql -h 127.0.0.1 -U claper -d claper -c "select id, event_id, status, length from presentation_files"
id | event_id | status | length
----+----------+--------+--------
1 | 1 | ready | 1
(1 row)
events 表有 2 个事件,presentation_files 只有事件 1 的记录——事件 2 是只建了壳、从未上传演示文稿的事件。结论:Claper 3.2.0 的事件列表组件未对「无演示文件的事件」判空,这类事件存在时整个列表页崩溃(移动端卡片分支 render_mobile_card 直接取 status)。
复现:用第七章的恢复库 + 新实例(8139)访问 /events,同一栈顶逐行一致:
** (KeyError) key :status not found in: nil
(claper 3.2.0) lib/claper_web/live/event_live/event_card_component.ex:577: anonymous fn/2 in ClaperWeb.EventLive.EventCardComponent.render_mobile_card/1
证明是数据驱动的确定性缺陷,非环境偶发。
处置:给该事件补传演示文稿,或删除空壳事件。删除走 rpc 应用层函数(同步清理关联数据与存储文件,实测回显节选,inspect 对非 ASCII 名按 \x{XXXX} 转义显示):
/opt/claper/bin/claper rpc 'IO.inspect(Claper.Events.delete_event(Claper.Events.get_event!(2)))'
{:ok,
%Claper.Events.Event{
__meta__: #Ecto.Schema.Metadata<:deleted, "events">,
id: 2,
uuid: "81ff5430-5bcf-483c-932f-039b99fe5df7",
name: "\x{4E2D}\x{6587}\x{4E8B}\x{4EF6}\x{6D4B}\x{8BD5}",
code: "zhtest",
presentation_file: nil,
...
>}
回显中 presentation_file: nil 与前述诊断互相印证。删除后列表页恢复:
EVENTS=200
九、注意事项
eval与rpc别混用:eval冷起临时系统,读不到运行中状态、也不影响运行节点,适合密钥生成与迁移;rpc依赖服务在跑,适合查改业务数据。服务停着时rpc会失败,先systemctl start claper。rpc返回值不打印,表达式必须自带IO.puts/IO.inspect(5.2 实测),否则「命令成功但毫无输出」极易误判为失败。remote只走交互式终端;脚本一律rpc。控制台退出用Ctrl+C→a,禁用System.halt()。stop/restart子命令与服务管理器冲突,重启统一systemctl restart claper。- 改密即踢会话:
update_user_password连带清空用户全部令牌(5.3),演示进行中禁止对演讲者账号执行。 - SECRET_KEY_BASE 轮换=全员下线(6 章双向 302 实测),且旧密钥泄露视同 admin 权限泄露,须立即轮换。
- 密钥值不落日志、不进工单;核对注入是否生效用前缀比对(
String.slice(0, 8))即可。 - 备份成对:数据库 dump +
/opt/claper/uploads目录,缺一即无法完整恢复演示。 - 中文运维:进程环境须带
ELIXIR_ERL_OPTIONS=+fnu(C1 篇第二章),否则文件名/事件名含非 ASCII 时字符串处理报错;IO.inspect默认把中文转义为\x{4E2D}形态属显示行为,非数据损坏。
十、常见问题
| 症状 | 原因 | 处置 |
|---|---|---|
ERROR: Unknown command migrate / phx.gen.secret / remote_console | Claper 3.2.0 发布包未收录这些子命令(第二章实测) | 分别用 eval 'Claper.Release.migrate()'、eval 随机数或 openssl rand -base64 48、remote |
rpc 执行后没有任何输出但退出码 0 | rpc 不打印返回值 | 表达式包 IO.inspect/IO.puts |
remote 报 *** ERROR: Shell process terminated! | 无 TTY(管道/cron 环境) | 换交互式 SSH,或改用 rpc |
登录后 /events 返回 500,日志 KeyError :status ... event_card_component.ex:577 | 存在未上传演示文稿的事件,列表卡片组件未判空(8.4 实录) | 补传演示文稿或 rpc 删除空壳事件 |
日志每 60 秒刷 OidcProviderConfig terminating {:configuration_load_failed, :timeout} | 未配置 OIDC 时的周期加载噪音(8.2) | 无害,grep -v 过滤 |
select ... from presentations 报表不存在 | 表名实为 presentation_files/presentation_states(7.3) | 先 \dt 核对表名 |
轮换 SECRET_KEY_BASE 后所有人都被踢回登录页 | 会话签名密钥变更,属预期安全行为(第六章) | 按空档轮换流程执行 |
eval 'Claper.Release.migrate()' 报连接错误 | DATABASE_URL 不可达或库不存在 | 核对 .env 后 systemctl restart claper,再查数据库服务 |
十一、参考链接
- Claper 官方仓库:https://github.com/ClaperCo/Claper (查询日期 2026-11-01)
- Claper 官方文档:https://docs.claper.co
- Elixir Releases(
bin/<app>子命令语义):https://hexdocs.pm/mix/Mix.Tasks.Release.html - Phoenix 配置与
secret_key_base:https://hexdocs.pm/phoenix/config.html - PostgreSQL pg_dump 文档:https://www.postgresql.org/docs/15/app-pgdump.html
- 站内:《Claper 介绍与选型指南》 | 《Claper Docker Compose 部署指南》 | 《Claper 3.2.0 配置参数详解》