PixelFed 0.15.2 常用 CLI 命令详解
系统梳理 PixelFed v0.15.2 的 artisan 命令族(账号/迁移/队列与 Horizon/定时任务/媒体维护/数据导入/存储与密钥/站点诊断与维护模式),每条核心命令给出签名、实测回显与行为解读,并沉淀复跑幂等性与退出码差异。
PixelFed 0.15.2 常用 CLI 命令详解
目标:系统梳理 PixelFed v0.15.2 的 artisan 命令体系(账号管理、数据库迁移、队列与 Horizon、定时任务、媒体维护、数据导入、存储与密钥初始化、站点诊断与维护模式),每条核心命令都给出「签名 → 实测执行 → 回显 → 行为解读」的完整闭环。已在 Ubuntu 22.04 服务器(IP 192.168.146.128,端口 8135)逐条实测通过,包括命令复跑的幂等/报错行为与退出码。
一、环境信息
| 项目 | 实测值 |
|---|---|
| 操作系统 | Ubuntu 22.04(x86_64) |
| PixelFed | v0.15.2(官方编排形态部署) |
| Laravel Framework | 13.38.0(php artisan --version 实测) |
| PHP(CLI) | 8.5.12(php artisan about 实测) |
| 数据库 | MariaDB 11.8 |
| 缓存/队列 | Redis 8 |
| 部署目录 | /opt/pixelfed |
| 访问地址 | http://192.168.146.128:8135 |
| 演示账号 | admin / q1w2e3r4(管理员);demotest、adminflag(第四章实测创建,密码同为 q1w2e3r4) |
本文所有命令均在部署目录 /opt/pixelfed 下执行,php artisan 命令通过编排内执行形态调用(同《PixelFed 0.15.2 Docker Compose 部署指南》4.6 节的方式),下文示例统一简写为 docker compose exec pixelfed php artisan <命令>。
二、工具概览
PixelFed 基于 Laravel 框架,其 CLI 入口是框架自带的 artisan 工具——站点初始化、账号管理、队列维护、数据导入、故障诊断等全部运维动作都通过 php artisan <命令> 完成。本章先给出命令体系的自省方法与全景矩阵,后续章节按命令族逐一实测。
2.1 命令自省三件套
artisan 自身提供三个自省命令,遇到任何不熟悉的命令先用它们查签名,无需查阅外部文档:
cd /opt/pixelfed
docker compose exec pixelfed php artisan --version
实测回显:
Laravel Framework 13.38.0
# 列出全部命令(按命名空间分组)
docker compose exec pixelfed php artisan list
实测回显(输出节选,实测首尾):
Laravel Framework 13.38.0
Usage:
command [options] [arguments]
Options:
-h, --help Display help for the given command. When no command is given display help for the list command
--silent Do not output any message
-q, --quiet Only errors are displayed. All other output is suppressed
-V, --version Display this application version
--ansi|--no-ansi Force (or disable --no-ansi) ANSI output
-n, --no-interaction Do not ask any interactive question
--env[=ENV] The environment the command should run under
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Available commands:
about Display basic information about your application
clear-compiled Remove the compiled class file
completion Dump the shell completion script
db Start a new database CLI session
dev Run the dev processes
docs Access the Laravel documentation
down Put the application into maintenance / demo mode
env Display the current framework environment
help Display help for a command
horizon Start a master supervisor in the foreground
install CLI Installer
list List commands
migrate Run the database migrations
optimize Cache framework bootstrap, configuration, and metadata to increase performance
reload Reload running services
serve Serve the application on the PHP development server
test Run the application tests
tinker Interact with your application
ui Swap the front-end scaffolding for the application
up Bring the application out of maintenance mode
update Run pixelfed schema updates between versions.
admin
……(中间为 user / media / import / horizon / queue 等命名空间分组的全部命令,约 300 行)……
webpush
webpush:vapid Generate VAPID keys.
# 查看单条命令的签名(参数与选项、默认值)
docker compose exec pixelfed php artisan user:create --help
实测回显(输出节选,实测首尾):
Description:
Create a new user
Usage:
user:create [options]
Options:
--name[=NAME]
--username[=USERNAME]
--email[=EMAIL]
--password[=PASSWORD]
--is_admin[=IS_ADMIN] [default: "0"]
--confirm_email[=CONFIRM_EMAIL] [default: "0"]
-h, --help Display help for the given command. When no command is given display help for the list command
……(以下为 Laravel 通用全局选项,各命令相同)……
2.2 命令族全景矩阵
按 php artisan list 实测输出归纳,v0.15.2 的命令按命名空间分为以下命令族(条目数为实测清点):
| 命令族 | 条目数 | 用途 | 代表命令 |
|---|---|---|---|
| user | 13 | 账号生命周期管理(创建/提权/密码诊断/注销) | user:create、user:admin |
| migrate | 7 | 数据库迁移 | migrate、migrate:status |
| horizon | 17 | 队列消费器(Horizon)管理 | horizon:status、horizon:list |
| queue | 14 | 队列作业管理(失败重试/清空/监控) | queue:failed、queue:retry |
| schedule | 8 | 定时任务查看与控制 | schedule:list |
| media | 5 | 媒体维护(优化/垃圾回收/修复) | media:optimize、media:gc |
| import | 2 | 数据导入(城市/自定义表情) | import:cities、import:emojis |
| storage | 3 | 存储符号链接与清理 | storage:link、storage:maintenance |
| passport | 5 | OAuth 密钥与客户端管理 | passport:keys、passport:client |
| instance | 1 | 实例 Actor(联邦身份)生成 | instance:actor |
| gc | 3 | 周期性垃圾回收 | gc:sessions、gc:failedjobs |
| story | 1 | 过期故事清理 | story:gc |
| status | 8 | 账号/媒体/实例元数据诊断 | status:user、status:media |
| fix | 6 | 数据修复(用户名/点赞数/头像等) | fix:usernames、fix:likes |
| app | 26 | 实例运维与联邦诊断 | app:federation、app:home-feed-rebuild |
| admin | 6 | 管理员维护(计数修正/存储迁移) | admin:fixPostCounts |
| config / db / key | 4 / 5 / 1 | 配置查看 / 数据库信息 / 应用密钥 | config:show、db:table、key:generate |
解读:日常运维高频的是 user、media、gc、schedule、horizon 五族;初始化阶段关键是 migrate、storage:link、passport:keys、import:cities、instance:actor;排障首选 app:federation 与 status 族。本文第四章按此优先级展开。
三、前置条件
- 已完成 v0.15.2 部署且迁移通过——迁移状态确认命令与回显见 4.2 节(实测 268 个迁移全部 Ran);部署与 5 个服务健康状态确认见《PixelFed 0.15.2 Docker Compose 部署指南》4.7 节;
- 已有管理员账号 admin / q1w2e3r4(创建过程见部署指南 4.6 节);
- 明确「编排内执行形态」:本文所有
docker compose exec pixelfed php artisan ...都在部署目录 /opt/pixelfed 下执行,等价于在应用运行环境内以正确的工作目录与用户身份执行 artisan; - 部分命令(user:admin、user:checkpassword)为交互式或需标准输入,自动化调用方式见 4.1 节实测与第五章注意事项。
四、核心命令族详解
4.1 账号管理(user 命令族)
user 命令族覆盖账号从创建到注销的完整生命周期。本节以一组连续实测走通「创建 → 查表 → 诊断 → 提权 → 邮箱确认」全链路。
user:create 创建用户(签名见 2.1 节):
docker compose exec pixelfed php artisan user:create \
--name="Demo Tester" --username=demotest \
--email=demotest@example.com --password=q1w2e3r4
实测回显:
Creating a new user...
Successfully created user!
user:table 查看用户表(创建前后各执行一次):
docker compose exec pixelfed php artisan user:table
创建前实测回显:
+----+----------+-------+-----------------------------+
| ID | Username | Name | Registered |
+----+----------+-------+-----------------------------+
| 1 | admin | admin | 2026-10-26T16:45:32.000000Z |
+----+----------+-------+-----------------------------+
创建后实测回显:
+----+----------+-------------+-----------------------------+
| ID | Username | Name | Registered |
+----+----------+-------------+-----------------------------+
| 2 | demotest | Demo Tester | 2026-10-26T17:36:26.000000Z |
| 1 | admin | admin | 2026-10-26T16:45:32.000000Z |
+----+----------+-------------+-----------------------------+
user:show 查看单用户概况:
docker compose exec pixelfed php artisan user:show demotest
实测回显:
User ID: 2
Username: demotest
Email: demotest@example.com
Joined: 0 seconds ago
Status Count: 0
user:checkpassword 密码诊断(只读):该命令验证候选密码与库中哈希是否匹配,并给出登录被拒的诊断线索。候选密码经标准输入传入(隐藏输入、不落存储),自动化场景用管道:
echo 'q1w2e3r4' | docker compose exec -T pixelfed php artisan user:checkpassword demotest
实测回显(正确密码,全文):
User: demotest (id 2)
Email on record: demotest@example.com
Login authenticates by EMAIL + password (LoginController defaults to the "email" field).
Email is unique in the users table. ✓
The web guard resolves to this same row. ✓
Stored hash algorithm: bcrypt
Stored hash cost: 10
Enter the password you are trying to log in with (hidden, not stored):
>
✓ PASSWORD MATCHES the stored hash for this row.
If web login still fails with this exact password + email "demotest@example.com", the problem is NOT the password:
- check for a duplicate email row above,
- confirm you are typing the email exactly (no trailing spaces),
- confirm the app server and CLI share the same database & APP_KEY,
- check for login throttling (5 failed attempts / 60 min lockout).
输入错误密码 wrong-pass-123 时,前段输出(用户定位、哈希算法等 10 行)完全相同,差异为结尾判定(实测节选):
✗ PASSWORD DOES NOT MATCH the stored hash for this row.
Re-run: php artisan user:setpassword demotest and set it again, then re-check here.
If it still will not match after setting, the CLI and web app likely point at different databases.
解读:该命令不改动任何数据,适合在用户报「登录不上」时先行定位——若密码匹配仍被拒,回显已给出四条后续排查方向(重复邮箱、输入误差、APP_KEY 不一致、登录节流 5 次/60 分钟锁定)。
user:admin 提权(交互确认):
echo yes | docker compose exec -T pixelfed php artisan user:admin demotest
实测回显:
Found username: demotest
Add admin privileges to this user? (yes/no) [no]:
>
Successfully changed permissions!
⚠️ user:create 的 --is_admin 选项实测不持久化:签名虽有 --is_admin[=IS_ADMIN],但传入 1 后查库确认 is_admin 仍为 false(v0.15.2 实测行为)。完整复测:先用 --is_admin=1 创建 adminflag,随即用 tinker 查询:
docker compose exec pixelfed php artisan user:create \
--name="Admin Flag" --username=adminflag \
--email=adminflag@example.com --password=q1w2e3r4 --is_admin=1
docker compose exec pixelfed php artisan tinker --execute='$u=\App\Models\User::where("username","adminflag")->first(); echo "is_admin="; var_export($u->is_admin);'
实测回显:
Creating a new user...
Successfully created user!
is_admin=false
再用 user:admin 提权后复查(前半段回显同上,略):
is_admin=true
结论:提权统一走 user:admin,不要依赖 --is_admin 选项。
user:verifyemail 跳过邮箱验证:
docker compose exec pixelfed php artisan user:verifyemail demotest
实测回显:
Successfully verified email address for demotest
user 命令族全量表(用途取自各命令实测 --help 描述):
| 命令 | 用途 |
|---|---|
| user:create | 创建新用户 |
| user:admin | 设为/移除管理员(交互确认) |
| user:checkpassword | 只读密码诊断(stdin 传候选密码) |
| user:setpassword | 重设密码(安全提示输入,bcrypt 哈希) |
| user:show | 查看用户概况 |
| user:table | 显示最新用户列表 |
| user:verifyemail | 标记用户邮箱已验证 |
| user:2fa | 关闭指定用户的两步验证 |
| user:delete | 删除账号 |
| user:unsuspend | 解除本地用户封禁 |
| user:avatar-delete | 删除头像并重置为默认 |
| user:app-magic-link | 为应用内注册未收确认邮件的用户获取魔法链接 |
| user:storage:recalculate | 按实际媒体重算 users.storage_used(修复配额计数) |
4.2 数据库迁移(migrate 命令族)
migrate 命令族管理数据库结构版本。部署初始化后最常用的是状态确认;fresh/reset/rollback 属破坏性命令,生产环境慎用(见第五章)。
migrate:status 确认迁移状态:
docker compose exec pixelfed php artisan migrate:status | tail -5
docker compose exec pixelfed php artisan migrate:status | grep -c 'Ran'
实测回显:
2026_09_30_042509_add_block_sync_url_to_instances_table ............ [1] Ran
2026_10_06_000001_normalize_legacy_user_languages .................. [1] Ran
2026_10_06_000001_widen_remote_url_on_avatars_table ................ [1] Ran
2026_10_07_000001_normalize_legacy_user_filter_morph_types ......... [1] Ran
268
解读:268 个迁移全部 [1] Ran(批次 1)且无 Pending,即结构初始化完成。该命令也是升级版本后的第一验证项。
migrate 命令族全量表:
| 命令 | 用途 | 生产建议 |
|---|---|---|
| migrate | 执行待运行迁移 | 升级后必执行 |
| migrate:status | 显示每个迁移的状态 | 日常确认用 |
| migrate:rollback | 回滚上一次迁移 | 慎用 |
| migrate:reset | 回滚全部迁移 | 破坏性,禁用于生产 |
| migrate:refresh | 重置并重跑全部迁移 | 破坏性,禁用于生产 |
| migrate:fresh | 删表后重跑全部迁移 | 破坏性,禁用于生产 |
| migrate:install | 创建迁移仓库表 | 初始化自动完成 |
4.3 队列与 Horizon(horizon / queue 命令族)
PixelFed 的缩略图生成、媒体优化、联邦投递等异步任务由 Horizon 消费 Redis 队列完成,Horizon 停摆会直接表现为「上传成功但缩略图不生成」(见《PixelFed 0.15.2 配置参数详解》第七章 Q4)。
horizon:status 确认消费器运行:
docker compose exec pixelfed php artisan horizon:status
实测回显:
INFO Horizon is running.
horizon:list 查看部署实例与监督器:
docker compose exec pixelfed php artisan horizon:list
实测回显:
+-------------------+-----+-----------------------------------------------------------------------------------------------------+---------+
| Name | PID | Supervisors | Status |
+-------------------+-----+-----------------------------------------------------------------------------------------------------+---------+
| a261455df413-iJ2A | 1 | supervisor-priority, supervisor-fanout, supervisor-deliver, supervisor-media, supervisor-background | running |
+-------------------+-----+-----------------------------------------------------------------------------------------------------+---------+
解读:当前 Horizon 主监督器运行中,下辖 priority / fanout / deliver / media / background 五个监督器,分别消费不同队列组;各队列的实时积压可在 4.8 节 app:federation 输出的 QUEUES 表中看到(default/high/shared/follow/inbox/delete/story/feed/low/move 十个队列均 Worker=yes、Pending=0)。
queue:failed 查看失败作业:
docker compose exec pixelfed php artisan queue:failed
实测回显:
INFO No failed queue jobs found.
常用 horizon/queue 命令速查(清单取自实测 php artisan list,其中 horizon:status、horizon:list、queue:failed 已实测):
| 命令 | 用途 |
|---|---|
| horizon:terminate | 通知主监督器优雅退出(改动配置/代码后重启消费器用) |
| horizon:pause / horizon:continue | 暂停/恢复作业消费 |
| horizon:snapshot | 立即存储一次队列指标快照(调度表每 5 分钟自动执行) |
| horizon:forget | 删除单条失败作业 |
| horizon:clear | 清空指定队列的作业 |
| queue:retry | 重试失败作业(配合 queue:failed 使用) |
| queue:flush | 清空失败作业表 |
| queue:monitor | 监控指定队列的积压规模 |
4.4 定时任务(schedule 命令族)
PixelFed 内置一批周期维护任务(媒体优化、垃圾回收、指标快照等),由常驻调度进程按 cron 表达式触发(该进程在部署编排中独立运行,见部署指南 4.5 节的服务构成)。schedule:list 列出全部计划任务及下次执行时间:
docker compose exec pixelfed php artisan schedule:list
实测回显(全文):
40 * * * * php artisan media:optimize ... Next Due: 3 minutes from now
5 * * * * php artisan media:gc ........ Next Due: 28 minutes from now
*/5 * * * * php artisan horizon:snapshot . Next Due: 3 minutes from now
*/5 * * * * php artisan story:gc ......... Next Due: 3 minutes from now
0 3 * * * php artisan gc:failedjobs ...... Next Due: 9 hours from now
41 9 * * * php artisan gc:passwordreset .. Next Due: 16 hours from now
0 13,23 * * * php artisan gc:sessions ........ Next Due: 5 hours from now
15 4 * * * php artisan storage:maintenance Next Due: 10 hours from now
20 4 * * 2 php artisan app:weekly-instance-scan Next Due: 10 hours from now
0 1 * * * php artisan app:cleanup-expired-app-registrations Next Due: 7 hours from now
20 */4 * * * php artisan passport:purge ..... Next Due: 2 hours from now
33 */6 * * * php artisan notifications:prune-old Next Due: 56 minutes from now
0 13,22 * * * php artisan app:transform-imports Next Due: 4 hours from now
51 * * * * php artisan app:import-upload-garbage-collection Next Due: 14 minutes from now
37 * * * * php artisan app:import-remove-deleted-accounts Next Due: 5 seconds from now
32 1,13 * * * php artisan app:import-upload-clean-storage Next Due: 7 hours from now
25 * * * * php artisan app:hashtag-cached-count-update Next Due: 48 minutes from now
25 */6 * * * php artisan app:account-post-count-stat-update Next Due: 48 minutes from now
45 1,13 * * * php artisan app:instance-update-total-local-posts Next Due: 8 hours from now
40 3 * * * php artisan federation:block-sync-reconcile Next Due: 10 hours from now
解读(关键行):媒体优化每小时第 40 分钟、媒体垃圾回收每小时第 5 分钟、指标快照与故事清理每 5 分钟、失败作业清理每日 03:00、会话清理每日 13/23 点、存储维护每日 04:15、Passport 令牌清理每 4 小时。也就是说 4.5/4.9 节的维护命令平时无需手工执行,手工执行主要用于补跑与排障。
schedule 族其余命令(schedule:run 立即执行到期任务、schedule:work 前台常驻、schedule:pause/resume 暂停恢复、schedule:interrupt 中断当前运行、schedule:test 试运行指定任务、schedule:clear-cache 清理调度互斥缓存)按 --help 签名使用即可。
4.5 媒体维护(media 命令族)
media:optimize 补跑媒体优化:找出尚未优化的媒体并入队,由 Horizon 消费。签名支持 --limit(单次入队上限,实测默认 1000):
docker compose exec pixelfed php artisan media:optimize
实测回显:
Queued 0 media candidates.
解读:0 表示当前无待优化积压(此前上传的媒体均已由队列完成优化,媒体 processed 状态可在配置篇 5.7 节的行为佐证中复核)。
media:gc 清理孤儿媒体:删除未挂到任何活跃帖子上的媒体记录。用 tinker 先数一遍孤儿(上一章相册上限实验遗留 2 条):
docker compose exec pixelfed php artisan tinker --execute='echo "total=".\App\Models\Media::count()." orphan=".\App\Models\Media::whereNull("status_id")->count();'
实测回显:
total=10 orphan=2
执行清理:
docker compose exec pixelfed php artisan media:gc
实测回显:
0 [░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░]
执行后再次计数(回显仍为 total=10 orphan=2):孤儿数未变化——media:gc 只回收产生超过 2 小时的孤儿媒体,刚产生的孤儿会被保留,给「误删后恢复帖子」留窗口。这与配置篇 5.4 节「第 5 张媒体被静默跳过成为孤儿」的现象闭环:孤儿会在 2 小时后由本命令(或每小时 :05 的计划任务)自动回收。
💡 技术拓展:清理「无主媒体/存储残留」有三条命令可选——
命令 清理对象 时机 media:gc 未挂到活跃帖子的孤儿媒体记录 2 小时保留期后(每小时的计划任务) media:filtercleanup 帖子已不存在等异常状态的媒体维护 手工排障 storage:maintenance remcache 临时文件与空目录(存储层残留) 每日 04:15 计划任务 本文按「先记录级(media:gc)、再存储级(storage:maintenance)」的顺序执行,media:filtercleanup 留给异常排查场景。
4.6 数据导入(import 命令族)
import:cities 导入城市数据:城市数据支撑发帖时的地点/位置功能。发行包不含数据文件,直接执行会报错(实测回显):
Error: The file storage/app/cities.json is missing. Run `git checkout storage/app/cities.json` to download it.
解决:从 GitHub 对应 tag 下载 cities.json 放入存储目录(实测文件 12977722 字节),再执行导入(命令与《PixelFed 0.15.2 Docker Compose 部署指南》第十一章 FAQ Q8 同源):
curl -fsSL -o /opt/pixelfed/storage/app/cities.json \
https://raw.githubusercontent.com/pixelfed/pixelfed/v0.15.2/storage/app/cities.json
chown 33:33 /opt/pixelfed/storage/app/cities.json
docker compose exec pixelfed php artisan import:cities
签名中的 [<chunk>] 为分批写入大小(默认 1000)。导入完成后用 db:table 验证数据落位:
docker compose exec pixelfed php artisan db:table places
实测回显(输出节选,实测首尾):
pixelfed.places ............................................................
Columns ................................................................. 13
Size .............................................................. 42.16 MB
Engine .............................................................. InnoDB
Collation ............................................... utf8mb4_unicode_ci
Column ................................................................ Type
id bigint, autoincrement ............................... bigint(20) unsigned
slug varchar, utf8mb4_unicode_ci .............................. varchar(255)
name varchar, utf8mb4_unicode_ci .............................. varchar(255)
state varchar, nullable, utf8mb4_unicode_ci .............. NULL varchar(255)
country varchar, utf8mb4_unicode_ci ........................... varchar(255)
……(中间为 aliases/lat/long/score/created_at/updated_at/cached_post_count/last_checked_at 各列与 8 个索引定义)……
Index ......................................................................
places_country_index country ......................................... btree
places_slug_country_lat_long_unique slug, country, lat, long btree, compound, unique
primary id .................................................. btree, primary
docker compose exec pixelfed php artisan tinker --execute='echo \Illuminate\Support\Facades\DB::table("places")->count();'
实测回显:
128769
解读:places 表 42.16 MB、128769 行城市记录(唯一索引对原始数据做了去重),位置功能数据就绪。
import:emojis 导入自定义表情:签名要求必填 <path>(表情 tar.gz 包路径),并有 --prefix/--suffix/--overwrite/--disabled 四个选项。缺参直接执行会报错(实测回显):
Not enough arguments (missing: "path").
(提示前后各有一行空白填充,属 Symfony 命令行的标准错误格式。)本环境未制作表情包,仅验证签名与缺参行为;需要自定义表情时,把打好的 tar.gz 放到应用可读路径后传入即可。
4.7 存储与密钥初始化(storage / passport / key / instance 命令族)
这一组命令集中在初始化阶段执行,重复执行的行为各不相同——本节逐一复跑验证,这是升级或迁移环境时最容易踩坑的地方。
storage:link 创建公开存储符号链接(首次执行创建成功;部署指南 4.5 节已实测首次执行),复跑实测:
docker compose exec pixelfed php artisan storage:link
实测回显:
ERROR The [public/storage] link already exists.
passport:keys 生成 OAuth 加密密钥,复跑实测:
docker compose exec pixelfed php artisan passport:keys
实测回显:
ERROR Encryption keys already exist. Use the --force option to overwrite them.
key:generate 查看应用密钥(--show 只展示不落盘,密钥本身在 .env 的 APP_KEY,见配置篇 5.1 节):
docker compose exec pixelfed php artisan key:generate --show
实测回显:
base64:bm8hWRcRAgQ9LFRyvDgraqvX1J23z2mSht7dKIp3n70=
(每环境生成值不同,不可照抄他人值。)
instance:actor 生成实例 Actor(联邦身份记录,初始化时执行),复跑实测:
docker compose exec pixelfed php artisan instance:actor
实测回显:
Instance actor succesfully generated. You do not need to run this command again.
幂等性对照小结:
| 命令 | 复跑行为 | 退出码 |
|---|---|---|
| storage:link | 报 ERROR「已存在」 | 0 |
| passport:keys | 报 ERROR「已存在」,提示 --force 覆盖 | 1 |
| instance:actor | 正常重新生成并提示无需再跑 | 0 |
| media:gc / gc:sessions / story:gc | 无待处理项时静默完成 | 0 |
解读:脚本化判断成败不能只看是否打印 ERROR——storage:link 报错但退出码为 0;跨命令统一以退出码为准,且 passport:keys 的 --force 会覆盖密钥(旧令牌全部失效),非排障不要加。
4.8 站点诊断与维护模式(about / app:federation / down / up)
about 一屏总览运行环境:
docker compose exec pixelfed php artisan about
实测回显(全文):
Environment ................................................................
Application Name .................................................. Pixelfed
Laravel Version .................................................... 13.38.0
PHP Version ......................................................... 8.5.12
Composer Version .................................................... 2.10.3
Environment ..................................................... production
Debug Mode ............................................................. OFF
URL ................................................... 192.168.146.128:8135
Maintenance Mode ....................................................... OFF
Timezone ............................................................... UTC
Locale ............................................................... en-US
Cache ......................................................................
Config .............................................................. CACHED
Events .............................................................. CACHED
Routes .............................................................. CACHED
Views ............................................................... CACHED
Drivers ....................................................................
Broadcasting ........................................................... log
Cache ................................................................ redis
Database ............................................................. mysql
Logs ......................................................... stack / daily
Mail ................................................................... log
Queue ................................................................ redis
Session ........................................................... database
Storage ....................................................................
public/storage ...................................................... LINKED
Pulse ......................................................................
Enabled ................................................................ OFF
Version ............................................................. v1.8.1
Livewire ...................................................................
Livewire ............................................................ v4.4.8
解读:排障第一入口——Maintenance Mode 行对应 4.8 节 down/up 状态;Cache 节四个 CACHED 对应配置/路由缓存已构建(清缓存后变灰);public/storage LINKED 对应 storage:link 成效。
app:federation 联邦全链路诊断:对配置、实例 Actor、本地端点、HTTP 签名、队列、投递健康、运行环境做体检:
docker compose exec pixelfed php artisan app:federation
实测回显(本环境 ACTIVITY_PUB=false 单实例形态,全文照抄):
================================================================
CONFIG
================================================================
✓ APP_ENV is production
✗ ActivityPub is disabled env=false admin setting=false
↳ Set ACTIVITY_PUB=true, then run php artisan config:cache.
! Inbox (AP_INBOX) is disabled
! Outbox (AP_OUTBOX) is disabled
! Shared inbox (AP_SHAREDINBOX) is disabled
! Remote follow (AP_REMOTE_FOLLOW) is disabled
✓ WebFinger enabled
✓ NodeInfo enabled
· Authorized fetch disabled (env=false)
· Followers sync (FEP-8fcf) enabled
· Delivery tuning timeout=30s concurrency=10 failure_threshold=5 max_backoff=604800s
✗ APP_URL is not https http://192.168.146.128:8135
↳ Actor ids are built from APP_URL and Pixelfed only accepts https ActivityPub URLs.
✓ APP_URL host matches APP_DOMAIN 192.168.146.128
✓ Cached config is newer than .env
· Cache store redis
✓ No pending migrations
================================================================
INSTANCE ACTOR
================================================================
✓ Instance actor exists http://192.168.146.128:8135/i/actor
✓ Instance actor keypair is valid 2048 bit RSA, public key derives from private key
✓ Cached private key matches the database
✓ Cached public key matches the database
· Cached actor document not cached yet
================================================================
LOCAL ENDPOINTS (outside-in)
================================================================
✓ host-meta points at /.well-known/webfinger
✓ WebFinger acct:admin@192.168.146.128 self link is http://192.168.146.128:8135/users/admin
✓ NodeInfo discovery http://192.168.146.128:8135/api/nodeinfo/2.0.json
✓ NodeInfo document pixelfed 0.15.2, protocols: activitypub
✓ Instance actor document id, inbox and publicKeyPem all match
✗ Actor @admin as application/activity+json HTTP 302, expected 200
↳ Redirects to http://192.168.146.128:8135/admin. Remote servers do not reliably follow redirects here, APP_URL should be the canonical origin.
✗ Actor @admin as application/ld+json HTTP 302, expected 200
↳ Redirects to http://192.168.146.128:8135/admin. Remote servers do not reliably follow redirects here, APP_URL should be the canonical origin.
✓ Shared inbox route reaches Laravel GET /f/inbox returned 405 as expected
================================================================
HTTP SIGNATURES
================================================================
✓ All active local profiles have a keypair 2 profiles
✓ POST signature round trip as @admin signed headers: (request-target) host date digest content-type user-agent
✓ GET signature round trip as the instance actor signed headers: (request-target) host date accept
================================================================
QUEUES
================================================================
· Queue connection redis (redis driver)
✓ Horizon is running 1 master supervisor(s)
+---------+--------+---------+------+-------------------------------------------------+
| Queue | Worker | Pending | Wait | Carries |
+---------+--------+---------+------+-------------------------------------------------+
| default | yes | 0 | 0s | outbound status delivery |
| high | yes | 0 | 0s | user inbox activities |
| shared | yes | 0 | 0s | shared inbox activities |
| follow | yes | 0 | 0s | inbound and outbound follows |
| inbox | yes | 0 | 0s | inbound actor deletes |
| delete | yes | 0 | 0s | inbound deletes |
| story | yes | 0 | 0s | story deletes |
| feed | yes | 0 | 0s | likes, home feed inserts after ingest |
| low | yes | 0 | 0s | shares, signing actor discovery, remote avatars |
| move | yes | 0 | 0s | account migration |
+---------+--------+---------+------+-------------------------------------------------+
✓ No failed federation jobs in the last 24h 0 failed jobs scanned
================================================================
DELIVERY HEALTH
================================================================
· Known instances 0 total, 0 banned
✓ No hosts with delivery failures
· Banned domain cache not cached yet
· Audience of @admin 0 inboxes on 0 hosts, 0 host(s) currently skipped
================================================================
ENVIRONMENT
================================================================
· PHP 8.5.12 (cli)
✓ Required PHP extensions and dns_get_record() are available
✗ Own domain does not pass the public IP check from this server 192.168.146.128 -> 192.168.146.128
↳ Helpers::validateLocalUrl() fails here, so inbound Follows, replies (inReplyTo) and Undos that reference local URLs are dropped. One private or reserved record (split-horizon DNS, internal resolver, ULA AAAA) is enough. Negative results are cached for 5 minutes.
✗ Outbound HTTPS to https://pixelfed.org failed ConnectionException: cURL error 28: Connection timed out after 5001 milliseconds (see https://curl.se/libcurl/c/libcurl-errors.html) for https://pixelfed.org
↳ If every outbound request fails, look at the egress firewall, DNS and the CA bundle (curl.cainfo).
================================================================
SUMMARY
================================================================
23 ok, 4 warning(s), 6 failure(s), 0 skipped
FAILURES:
✗ [config] ActivityPub is disabled
✗ [config] APP_URL is not https
✗ [endpoints] Actor @admin as application/activity+json
✗ [endpoints] Actor @admin as application/ld+json
✗ [env] Own domain does not pass the public IP check from this server
✗ [env] Outbound HTTPS to https://pixelfed.org failed
WARNINGS:
! [config] Inbox (AP_INBOX) is disabled
! [config] Outbox (AP_OUTBOX) is disabled
! [config] Shared inbox (AP_SHAREDINBOX) is disabled
! [config] Remote follow (AP_REMOTE_FOLLOW) is disabled
解读:SUMMARY 的 6 项 failure 全部源于「内网 HTTP + 联邦关闭」的单实例形态——ACTIVITY_PUB=false 与 APP_URL 非 https 是配置选择(配置篇 5.8 节有逐项解读);ENVIRONMENT 两项 ✗ 是纯内网环境的预期表现(私网地址过不了公网解析检查、无公网出站)。QUEUES 节是 Horizon 十个队列的健康快照。开启联邦前跑一次本命令、按 ✗ 逐项清零,是最稳的启用路径。
down / up 维护模式开关(含行为验证):
docker compose exec pixelfed php artisan down
curl -s -o /dev/null -w '%{http_code}\n' -H 'Host: 192.168.146.128' http://127.0.0.1:8135/login
docker compose exec pixelfed php artisan up
curl -s -o /dev/null -w '%{http_code}\n' -H 'Host: 192.168.146.128' http://127.0.0.1:8135/login
实测回显:
INFO Application is now in maintenance mode.
503
INFO Application is now live.
200
解读:down 后所有请求 503(升级维护窗口的标准姿势),up 即刻恢复 200。curl 带 Host 头是因为路由按 APP_DOMAIN 域名约束注册,直接以 127.0.0.1 访问会 404(配置篇 5.3 节有该行为的完整实测)。
4.9 垃圾回收(gc / story 命令族)
gc 族与 story:gc 均已进入调度表(见 4.4 节),手工执行用于补跑。三者对待处理项为空时静默完成(无输出),实测退出码均为 0:
docker compose exec pixelfed php artisan gc:sessions; echo "exit=$?"
docker compose exec pixelfed php artisan story:gc; echo "exit=$?"
实测回显:
exit=0
exit=0
| 命令 | 清理对象 | 调度计划 |
|---|---|---|
| gc:failedjobs | 超过 1 个月的失败队列作业 | 每日 03:00 |
| gc:passwordreset | 超过 24 小时的密码重置令牌 | 每日 09:41 |
| gc:sessions | 数据库会话(SESSION_DRIVER=database 时) | 每日 13/23 点 |
| story:gc | 过期故事 | 每 5 分钟 |
五、注意事项
- 破坏性命令清单:migrate:fresh / migrate:reset / migrate:refresh(删表重迁)、db:wipe(清空全库)、user:delete(删号)、horizon:terminate(停消费器)、queue:flush(清空失败作业)、passport:keys --force(覆盖密钥致旧令牌失效)——生产执行前必须确认备份;日常巡检只读命令(status、list、db:table、horizon:status)可放心使用。
- 复跑行为不一致:同是「已存在」类报错,storage:link 退出码为 0、passport:keys 为 1、instance:actor 幂等成功(4.7 节对照表)。脚本里判断成败以退出码为准,不要 grep 关键字。
- 交互式命令的自动化:user:admin 的 yes/no 确认、user:checkpassword 的隐藏密码输入都走标准输入,自动化统一用管道(
echo yes |、echo 'q1w2e3r4' |),并给 exec 加-T关闭伪终端分配。 - 清缓存类命令与实例开关的联动:optimize:clear / config:clear 会连同实例配置缓存一起失效,实例级开关(如注册、故事)会回到 .env 取值,修改 .env 后需按「清缓存 + 重建缓存」两步走,完整机制与实测见《PixelFed 0.15.2 配置参数详解》第三章。
- 命令执行形态:所有命令经编排内执行形态调用(部署目录 /opt/pixelfed 下
docker compose exec pixelfed php artisan ...),不要在宿主机直接找 php 可执行文件——CLI 与 Web 必须共用同一数据库与 APP_KEY(user:checkpassword 的诊断回显同样如此提示)。
六、常见问题
Q1:horizon:status 显示 stopped 或无输出
Horizon 常驻消费器未运行。先确认编排中 horizon 服务存活(部署指南 4.5 节的服务构成与 4.7 节的验证方式),再用 php artisan horizon:list 查看监督器是否注册;修改队列配置后需 horizon:terminate 让其按新配置重启。
Q2:media:gc 执行后孤儿媒体还在 不是故障:实测确认 media:gc 只回收产生超过 2 小时的孤儿(4.5 节前后计数不变即此因)。等下一个整点 :05 的计划任务或届时手工补跑即可。
Q3:import:cities 报 cities.json is missing
发行包不含城市数据文件,按 4.6 节两步走:从 GitHub v0.15.2 tag 下载 cities.json 放入存储目录并修正属主,再执行导入;导入结果用 db:table places 与行数查询验证(实测 42.16 MB / 128769 行)。
Q4:用户反馈登录不上,如何定位
先用 user:checkpassword <用户名> 做只读诊断(4.1 节实测):密码匹配仍被拒时按回显四条线索排查(重复邮箱、输入误差、APP_KEY 不一致、5 次/60 分钟登录节流);密码不匹配用 user:setpassword 重置后再验。
Q5:app:federation 一片 ✗ 是不是装坏了 对照 SUMMARY 分节看:[config]/[endpoints] 的 ✗ 来自 ACTIVITY_PUB=false 或 APP_URL 非 https(内网单实例的配置选择),[env] 的两项 ✗ 是纯内网环境的预期;只要 INSTANCE ACTOR、HTTP SIGNATURES、QUEUES 三节全 ✓,单实例功能即健康。
Q6:命令应该在哪个目录、什么身份执行
统一在部署目录 /opt/pixelfed 下以编排内执行形态运行(docker compose exec pixelfed php artisan ...),由编排保证工作目录与运行用户;千万不要绕开编排直接以其他身份操作存储目录——属主错乱会导致日志/缓存写入失败(部署指南第四章 FAQ 有该坑实录)。