Crafty Controller 4.11.0 常用 CLI 命令与工具详解
Crafty Controller 4.11.0 命令行工作面全解:main.py 四参数源码行为与 root 拒绝/双实例互斥排障、sqlite3 逐表排查与 .backup 在线备份、logging.json 缺失致日志缺勤实录、自签证书与元数据核验、探活与运行时工具链,全部回显 2026-11-02/03 实测。
Crafty Controller 4.11.0 常用 CLI 命令与工具详解
目标:把 Crafty Controller 4.11.0 的命令行工作面讲透——主程序
main.py的全部启动参数与源码行为、SQLite 数据库的逐表排查与在线备份、8 个日志文件的用途与真实样本、自签证书与元数据文件的核验方法、服务探活与运行时工具链,全部命令与回显为 2026-11-02/03 实测,含 root 拒绝启动、双实例互斥、logging.json 缺失三类排障实录。
一、环境信息
- 操作系统:Ubuntu 24.04.5 LTS(x86_64),服务运行环境内 Python 3.12.3;
- 软件版本:Crafty Controller 4.11.0(
config/version.json实测{"major": 4, "minor": 11, "sub": 0};上游最新稳定版核实过程见《Crafty Controller 介绍与选型指南》); - 部署路线:本文沿用本专栏《Crafty Controller Docker Compose 部署指南》的 Compose 部署形态,服务安装根目录
/crafty,程序目录/crafty/app; - 数据文件双视角:
config/、logs/、servers/、backups/、import/五个目录同时存在于服务环境(/crafty/...)与 compose 目录(./docker/...),是同一份文件,宿主侧可直接用常规工具读写; - 数据库:
/crafty/app/config/db/crafty.sqlite(即 compose 目录docker/config/db/crafty.sqlite),WAL 模式; - Web 入口:服务监听 8443/HTTPS,宿主侧映射
https://127.0.0.1:8135;管理账号admin(演示口令q1w2e3r4); - 配置参数含义见《Crafty Controller 4.11.0 配置参数详解》,本文不重复。
💡 说明:本文"服务运行环境"指 Crafty 进程所在的执行环境(进入方式见部署篇),"宿主侧"指 compose 目录所在的 Ubuntu 服务器。两组命令的输入与回显均为实测逐条抄录。
二、工具概览
Crafty Controller 4.11.0 没有独立的 crafty-cli 二进制,命令行能力由六类工具拼成:
| 类别 | 工具 | 位置 | 用途 |
|---|---|---|---|
| 主程序 CLI | python3 main.py(-h/-i/-v/-d) | 服务环境 /crafty | 启动、调试、会话锁处理 |
| 数据库 | sqlite3 3.45.1 | 宿主侧(服务环境未装该 CLI) | 逐表排查、在线备份、完整性检查 |
| 数据库兜底 | Python 标准库 sqlite3 模块 | 服务环境 venv 内 | 无 sqlite3 CLI 时的等价查询 |
| 日志 | commander/session/schedule/tornado-access/auth/auth_tracker/audit/cmd_queue 共 8 个 .log | logs/ 目录 | 排障主战场 |
| 证书 | openssl | 两侧均有 | 自签证书有效期/主体核验 |
| 运行时 | java(OpenJDK 25.0.4)、pip、curl(宿主侧)、ss(宿主侧) | 服务环境/宿主侧 | 游戏服进程、依赖查看、探活、端口核验 |
实测服务环境内工具缺口(重要,影响排障路线选择):
$ command -v sqlite3 curl ss netstat lsof git
none of netstat/lsof/ss
即服务运行环境没有 sqlite3/curl/ss/netstat/lsof/git,数据库与网络排查要么用宿主侧工具对着 bind 目录做,要么用服务环境内的 Python 标准库做。本文两种路线都给了实测回显。
三、前置条件
- 面板进程以非 root 用户
crafty运行,实测进程链:
$ ps -ef | grep "[m]ain.py"
root 1 0 0 Nov02 ? 00:00:00 sudo -u crafty bash -c source ./.venv/bin/activate && exec python3 main.py -d -i
crafty 23 1 0 Nov02 ? 00:00:04 python3 main.py -d -i
- 主程序对 root 直接运行有硬性拒绝(见 4.4 排障实录),所有
main.py命令必须在服务环境内切到crafty用户执行; - 宿主侧操作数据文件需对
docker/config/db/有读权限(文件属主 crafty、组 root,权限rw-rw-r--); - 数据库排查建议在面板低峰期做;WAL 模式允许并发读,见第五章注意事项。
四、主程序 CLI:python3 main.py
4.1 帮助输出(实测)
main.py 位于安装根 /crafty,argparse 定义在 main.py 第 330 行起。以服务用户执行:
$ cd /crafty && source ./.venv/bin/activate && python3 main.py --help
usage: Crafty Controller - A Server Management System [-h] [-i] [-v] [-d]
options:
-h, --help show this help message and exit
-i, --ignore Ignore session.lock files
-v, --verbose Sets logging level to debug.
-d, --daemon Runs Crafty in daemon mode (no prompt)
4.2 参数逐项详解
| 参数 | 类型 | 行为(源码实测核对) |
|---|---|---|
-h, --help | 内置 | 打印上方 usage 后退出 |
-i, --ignore | store_true | 启动时若存在 config/session.lock 直接删除再继续(helpers.py 的 create_session_file():if ignore and os.path.exists(self.session_file): os.remove(...)),随后写入自己的 pid |
-v, --verbose | store_true | 日志级别设为 DEBUG:logging_config["loggers"][""]["level"] = "DEBUG",且控制台 Console.level = "debug" |
-d, --daemon | store_true | 守护模式,不带交互 prompt |
4.3 默认启动参数
服务入口脚本把参数原样透传给 python3 main.py,本实例默认启动参数为 -d -i,启动行实测:
Wrapper | 🚀 Launching crafty with [-d -i]
也就是说线上面板本身就是"守护模式 + 忽略会话锁"起跑的——-i 让每次重启无条件重建 session.lock,这是官方为单实例托管场景做的取舍;手工排障时不要随手加 -i(见 4.5)。
4.4 排障实录一:root 直接运行被拒
以 root 身份跑 python3 main.py --help,usage 一个字都不会打印,实测回显:
$ cd /crafty && .venv/bin/python3 main.py --help
[+] Crafty: 11/03/26 00:12:43 - CRITICAL: Root detected. Root/Admin access denied. Run Crafty again with non-elevated permissions.
[+] Crafty: 11/03/26 00:12:48 - CRITICAL: Crafty shutting down. Root/Admin access denied.
源码位置 main.py 37–44 行:helper.check_root() 命中后打印两条 CRITICAL、time.sleep(5),然后 sys.exit(0)。两个坑:
- 检查发生在 argparse 之前,所以
--help也被拦; - 退出码是 0,脚本里用返回码判断"启动成功"会被骗过——要判断成败应 grep
Root/Admin access denied。
4.5 排障实录二:双实例互斥(session.lock)
面板在跑时再起第二个实例(不带 -i),实测回显:
$ cd /crafty && sudo -u crafty bash -c "source ./.venv/bin/activate && timeout 40 python3 main.py 2>&1 | tail -8"
///////////////////////////////////////////////////////////////////////////
# Server Manager / Web Portal for your Minecraft server #
# Homepage: www.craftycontrol.com #
///////////////////////////////////////////////////////////////////////////
[+] Crafty: 11/03/26 00:15:50 - CRITICAL: Another Crafty Controller agent seems to be running...
pid: 23
started on: 03-11-2026, 00:14:58
$ echo "rc=$?"
rc=1
行为链(create_session_file() 源码核对):读 config/session.lock 取 pid → psutil.pid_exists(pid) 为真 → CRITICAL + logger.critical("Found running crafty process. Exiting.") → sys.exit(1)。若 pid 已不存在(上次崩溃残留的锁),则打印 No process found for pid. Assuming crafty crashed. Deleting stale session.lock 并自动清锁继续——所以崩溃后的陈旧锁不需要人工删,正常重启会自愈;人工删锁只应发生在"确认旧进程已死但锁 JSON 解析失败"的场景(该分支同样会 sys.exit(1),报错文案为 Failed to locate existing session.lock with error: ...)。
session.lock 本体实测(面板在跑时):
$ cat /crafty/app/config/session.lock
{
"pid": 23,
"started": "03-11-2026, 00:14:58"
}
五、SQLite 数据库工具:sqlite3
5.1 版本与总表
宿主侧对 bind 目录里的库文件直接操作(服务环境无 sqlite3 CLI,见 5.7 兜底):
$ sqlite3 --version
3.45.1 2024-01-30 16:01:20 e876e51a0ed5c5b3126f52e532044363a014bc594cfefa87ffb5b82257ccalt1 (64-bit)
$ sqlite3 docker/config/db/crafty.sqlite ".tables"
api_keys passkey_challenges server_stats user_roles
backups passkey_data servers users
crafty_settings role_servers totp_data webhooks
host_stats roles totp_recovery
migratehistory schedules user_crafty
18 张表,与面板功能面对得上:users/user_roles/roles(账号与权限)、servers(游戏服定义)、server_stats/host_stats(指标时序)、schedules(计划任务)、backups(备份记录)、api_keys/webhooks(自动化)、totp_*/passkey_*(二次认证)、crafty_settings(Web 侧设置)、migratehistory(迁移流水)。
5.2 运行模式与完整性
$ sqlite3 docker/config/db/crafty.sqlite "PRAGMA journal_mode; PRAGMA integrity_check;"
wal
ok
WAL 是面板启动时由 peewee 强制设置的,main.py 建库参数实测源码:
database = peewee.SqliteDatabase(
helper.db_path,
pragmas={
"journal_mode": "wal",
"cache_size": -1024 * 10,
"busy_timeout": 5000, # Allows a wait to hold for up to 5s before dropping.
"synchronous": 1, # NORMAL mode, decrease WAL commit interval.
},
)
busy_timeout 5000 意味着排障脚本撞锁最多等 5 秒;db/ 目录三件套实测:
$ ls -la docker/config/db/
total 836
drwxrwsr-x 2 crafty root 4096 Nov 3 00:14 .
drwxrwsr-x 4 root root 4096 Nov 3 00:15 ..
-rw-rw-r-- 1 crafty root 765952 Nov 3 00:14 crafty.sqlite
-rw-rw-r-- 1 crafty root 32768 Nov 3 00:15 crafty.sqlite-shm
-rw-rw-r-- 1 crafty root 41232 Nov 3 00:16 crafty.sqlite-wal
⚠️ 备份不要直接
cp主库文件——WAL 里可能有未合并的写入。用 5.6 的在线备份命令。
5.3 账号与服务器排查(只读)
$ sqlite3 -header -column docker/config/db/crafty.sqlite "SELECT user_id, username, superuser, enabled, last_login FROM users;"
user_id username superuser enabled last_login
------- -------- --------- ------- --------------------------
1 admin 1 1 2026-11-02 21:13:08.274723
2 system 0 0 2026-11-02 21:13:17.639322
$ sqlite3 docker/config/db/crafty.sqlite "SELECT 'servers',COUNT(*) FROM servers UNION ALL SELECT 'api_keys',COUNT(*) FROM api_keys UNION ALL SELECT 'webhooks',COUNT(*) FROM webhooks UNION ALL SELECT 'schedules',COUNT(*) FROM schedules UNION ALL SELECT 'backups',COUNT(*) FROM backups UNION ALL SELECT 'server_stats',COUNT(*) FROM server_stats UNION ALL SELECT 'host_stats',COUNT(*) FROM host_stats UNION ALL SELECT 'migratehistory',COUNT(*) FROM migratehistory;"
servers|0
api_keys|0
webhooks|0
schedules|0
backups|0
server_stats|0
host_stats|273
migratehistory|64
解读:admin 是超级用户(superuser=1);system 是面板内置伪用户(enabled=0,Web 登录名会被它占用,建号时不要用 system);host_stats 273 行是 30 秒一次的宿主指标采样(stats_update_frequency_seconds=30,见配置详解篇),server_stats 为 0 因为还没纳管游戏服;migratehistory 64 条是版本迁移流水:
$ sqlite3 -header -column docker/config/db/crafty.sqlite "SELECT * FROM migratehistory ORDER BY id DESC LIMIT 3;"
id name migrated_at
-- -------------------------- --------------------------
64 20260609_custom_logos 2026-11-02 13:13:04.583974
63 20260604_og_embed 2026-11-02 13:13:04.580812
62 20260216_dashboard_columns 2026-11-02 13:13:04.575276
面板升级后核对"迁移是否跑完"就看这张表的最新条目;启动日志里的对应行是 Starting migrations → There is nothing to migrate(见第六章样本)。
5.4 游戏服定义表结构(servers)
$ sqlite3 docker/config/db/crafty.sqlite "SELECT sql FROM sqlite_master WHERE name='servers';" | head -5
CREATE TABLE "servers" ("server_id" VARCHAR(255) NOT NULL PRIMARY KEY, "created" DATETIME NOT NULL, "server_name" VARCHAR(255) NOT NULL, "path" VARCHAR(255) NOT NULL, "executable" VARCHAR(255) NOT NULL, "log_path" VARCHAR(255) NOT NULL, "execution_command" VARCHAR(255) NOT NULL, "auto_start" INTEGER NOT NULL, "auto_start_delay" INTEGER NOT NULL, "crash_detection" INTEGER NOT NULL, "stop_command" VARCHAR(255) NOT NULL, "executable_update_url" VARCHAR(255) NOT NULL, "server_ip" VARCHAR(255) NOT NULL, "server_port" INTEGER NOT NULL, "logs_delete_after" INTEGER NOT NULL, "type" VARCHAR(255) NOT NULL, "ignored_exits" VARCHAR(255) NOT NULL, "show_status" INTEGER NOT NULL, "created_by" INTEGER NOT NULL, "shutdown_timeout" INTEGER NOT NULL, "app_id" INTEGER, "count_players" INTEGER NOT NULL, "update_watcher" INTEGER NOT NULL)
排障常用点:path(世界目录,必须在 servers/ 挂载内)、execution_command(启动命令)、server_port(对外的 MC 端口,落在 compose 映射的 25500-25510 段内才连得进)。新建/改服走 Web 界面,不要 INSERT 手工造行——server_id 与目录结构、权限组由面板创建流程一起生成。
5.5 Web 侧设置表(crafty_settings)
单行宽表,密钥与外观都在这里面:
$ sqlite3 docker/config/db/crafty.sqlite ".schema crafty_settings"
CREATE TABLE IF NOT EXISTS "crafty_settings" ("id" INTEGER NOT NULL PRIMARY KEY, "secret_api_key" VARCHAR(255) NOT NULL, "login_photo" VARCHAR(255) NOT NULL, "login_opacity" INTEGER NOT NULL, "master_server_dir" VARCHAR(255) NOT NULL, "cookie_secret" VARCHAR(255) NOT NULL, "og_enabled" INTEGER NOT NULL, "og_title" VARCHAR(255) NOT NULL, "og_description" VARCHAR(255) NOT NULL, "og_image" VARCHAR(255) NOT NULL, "og_color" VARCHAR(255) NOT NULL, "logo_full" VARCHAR(255) NOT NULL, "logo_square" VARCHAR(255) NOT NULL);
$ sqlite3 -header -column docker/config/db/crafty.sqlite "SELECT id, master_server_dir, login_opacity, og_enabled, og_title, logo_full FROM crafty_settings;"
id master_server_dir login_opacity og_enabled og_title logo_full
-- ----------------- ------------- ---------- -------- ---------
1 /crafty/servers 100 1
注意查询时避开 secret_api_key 与 cookie_secret 两列——它们分别用于 API 签名与会话 cookie 加密,泄露即会话可伪造;排障只需要上面这些非敏感列。
5.6 在线备份与恢复核验
面板在跑时做一致性快照,用 sqlite3 的 .backup 内建命令:
$ sqlite3 docker/config/db/crafty.sqlite ".backup ./backup_demo.sqlite"
$ sqlite3 ./backup_demo.sqlite "PRAGMA integrity_check; SELECT COUNT(*) FROM users;"
ok
2
恢复演练口径:停服 → 把快照替换 crafty.sqlite(同时清掉旧 -shm/-wal)→ 起服,面板会重建 WAL 三件套。生产备份建议 cron 里跑 .backup 后连同 config.json、web/certs/ 一起打包(备份范围与敏感件清单见配置详解篇第九章)。
5.7 兜底路线:服务环境内用 Python 标准库
服务环境没有 sqlite3 CLI,但 venv 的 Python 自带 sqlite3 模块(内置 SQLite 3.45.1),等价查询实测:
$ python3 -c "import sqlite3; print(sqlite3.sqlite_version)"
3.45.1
$ sudo -u crafty python3 -c "import sqlite3; c=sqlite3.connect('/crafty/app/config/db/crafty.sqlite'); print(c.execute('SELECT COUNT(*) FROM users').fetchone()); print(c.execute('SELECT username, superuser FROM users').fetchall())"
(2,)
[('admin', 1), ('system', 0)]
以 crafty 用户操作自己的库文件,权限路线与宿主侧 root 读 bind 目录互为备份,两条都验证可用。
六、日志工具:logs/ 目录 8 个文件
6.1 文件清单与用途
$ ls -la /crafty/logs/
total 52
drwxrwsr-x 2 root root 4096 Nov 3 00:14 .
drwxrwsrwx 1 crafty root 4096 Nov 3 00:15 ..
-rw-rw-r-- 1 crafty root 0 Nov 2 21:13 audit.log
-rw-r--r-- 1 crafty root 0 Nov 3 00:14 auth.log
-rw-rw-r-- 1 crafty root 2 Nov 3 00:14 auth_tracker.log
-rw-r--r-- 1 crafty root 0 Nov 3 00:14 cmd_queue.log
-rw-rw-r-- 1 crafty root 12553 Nov 3 00:15 commander.log
-rw-r--r-- 1 crafty root 3052 Nov 3 00:15 schedule.log
-rw-r--r-- 1 crafty root 12553 Nov 3 00:15 session.log
-rw-r--r-- 1 crafty root 0 Nov 3 00:14 tornado-access.log
| 文件 | 记录器 | 用途 |
|---|---|---|
commander.log | [Crafty] | 面板主日志:启动序列、迁移、Web 绑定、BigBucket 检查 |
session.log | [Crafty] | 与主日志同源的第二落点(含异常堆栈) |
schedule.log | [Schedules] | APScheduler 任务流水(指标采集、版本检查、头像刷新) |
tornado-access.log | [Tornado] | HTTP 访问日志,JSON 多行格式,含状态码/路径/来源 IP/耗时 |
auth.log | 认证 | 登录/登出/权限事件(有登录动作才写) |
auth_tracker.log | 认证计数 | 登录限流计数器,JSON 字典,空闲时就是 {} |
audit.log | [Audit] | JSON 格式审计流水(需 enable_audit_logging,默认关) |
cmd_queue.log | 命令队列 | 队列化服务器命令的执行记录 |
6.2 主日志:启动序列样本
$ head -12 /crafty/logs/commander.log
2026-11-03 00:14:58,169 - [Crafty] - INFO - __main__ - ***** Crafty Controller Started *****
2026-11-03 00:14:58,169 - [Crafty] - INFO - app.classes.shared.migration - Starting migrations
2026-11-03 00:14:58,172 - [Crafty] - INFO - app.classes.shared.migration - There is nothing to migrate
2026-11-03 00:14:58,183 - [Crafty] - INFO - __main__ - Initializing all servers defined
2026-11-03 00:14:58,183 - [Crafty] - INFO - app.classes.helpers.helpers - SSL Cert File is set to: /crafty/app/config/web/certs/commander.cert.pem
2026-11-03 00:14:58,183 - [Crafty] - INFO - app.classes.helpers.helpers - SSL Key File is set to: /crafty/app/config/web/certs/commander.key.pem
2026-11-03 00:14:58,183 - [Crafty] - INFO - app.classes.helpers.helpers - Cert and Key files already exists, not creating them.
2026-11-03 00:14:58,184 - [Crafty] - INFO - app.classes.web.tornado_handler - Starting Web Server on ports https:8443
2026-11-03 00:14:58,190 - [Crafty] - INFO - app.classes.web.tornado_handler - https://10.89.62.2:8443 is up and ready for connections.
2026-11-03 00:15:00,701 - [Crafty] - INFO - app.classes.big_bucket.bigbucket - Checking Big Bucket status
2026-11-03 00:15:02,194 - [Crafty] - INFO - __main__ - Checking Internet. This may take a minute.
2026-11-03 00:15:03,367 - [Crafty] - ERROR - app.classes.big_bucket.bigbucket - Unable to connect to big bucket due to error: HTTPSConnectionPool(host='jars.arcadiatech.org', port=443): Read timed out. (read timeout=2)
排障读法:Starting Web Server on ports https:8443 确认监听;最后一行 BigBucket 超时是受限网络访问官方 jar 源失败的典型表现(不影响面板本身,处置见配置详解篇下载源章节与部署篇 FAQ)。
6.3 调度日志:指标采集心跳
$ grep -m3 "Running job" /crafty/logs/schedule.log
2026-11-03 00:15:30,699 - [Schedules] - INFO - Running job "Stats.record_stats (trigger: interval[0:00:30], next run at: 2026-11-03 00:16:00 CST)" (scheduled at 2026-11-03 00:15:30.699226+08:00)
30 秒间隔与 host_stats 行数互相印证(面板起了约 14 分钟,采样 273 行含历史累计)。
6.4 访问日志:JSON 逐请求
对宿主端口打两枪后实测 tornado-access.log 全文:
$ curl -sk -o /dev/null -w "GET / -> %{http_code}\n" https://127.0.0.1:8135/
GET / -> 302
$ curl -sk -o /dev/null -w "GET /login -> %{http_code}\n" https://127.0.0.1:8135/login
GET /login -> 200
$ cat /crafty/logs/tornado-access.log
2026-11-03 00:15:37,683 - [Tornado] - [Access] - INFO - {
"Status_Code": 302,
"Method": "GET",
"URL": "/",
"Remote_IP": "10.89.62.1",
"Elapsed_Time": "0.21ms"
}
2026-11-03 00:15:37,699 - [Tornado] - [Access] - INFO - {
"Status_Code": 200,
"Method": "GET",
"URL": "/login",
"Remote_IP": "10.89.62.1",
"Elapsed_Time": "3.89ms"
}
每条请求 5 行 JSON,grep -A5 '"URL": "/login"' 是最常用检索。未登录访问受保护路径会被 302 到登录页(见第八章探活)。
6.5 排障实录三:logging.json 缺失导致日志文件"缺勤"
本实例首启后 logs/ 里只有 3 个文件(audit.log 0 字节、auth_tracker.log 2 字节、commander.log 0 字节),session/schedule/tornado-access/auth/cmd_queue 五个文件根本不生成。原因实测核对 main.py 源码:日志器全部由 config/logging.json 的 dictConfig 定义,文件缺失时走 logging.basicConfig(level=DEBUG) 兜底并打印 Unable to read logging config from ...——主日志改走进程 stdout,文件日志器只剩代码里显式 open() 预建的三个。处置(与部署篇 FAQ 10.2 同一路线):
# 从程序目录的出厂配置副本取回 logging.json(连同 motd_format.json)
$ cp /crafty/app/config_original/logging.json /crafty/app/config/logging.json
$ cp /crafty/app/config_original/motd_format.json /crafty/app/config/motd_format.json
# 重启服务(docker compose restart,操作口径见部署篇)
$ ls -la /crafty/app/config/ | grep -E "logging|motd"
-rw-rw-r-- 1 root root 3326 Nov 3 00:14 logging.json
-rw-rw-r-- 1 root root 467 Nov 3 00:14 motd_format.json
$ ls /crafty/logs/
audit.log auth.log auth_tracker.log cmd_queue.log commander.log schedule.log session.log tornado-access.log
8 个文件齐备,主日志开始落盘(commander.log 12553 字节)。结论:日志文件"少了一半"不是坏了,是 logging.json 没了;升级/迁移时把 config 目录整包带上即可避免。
七、证书与元数据文件
7.1 自签 TLS 证书核验
面板首启自签 commander.cert.pem/commander.key.pem(config/web/certs/)。两侧核验命令同一份文件,宿主侧实测:
$ openssl x509 -in docker/config/web/certs/commander.cert.pem -noout -subject -issuer -dates
subject=C = US, ST = Indiana, O = "Arcadia Technology, LLC", OU = Crafty Controller, CN = 729d129f27ab, emailAddress = info@arcadiatech.org
issuer=C = US, ST = Indiana, O = "Arcadia Technology, LLC", OU = Crafty Controller, CN = 729d129f27ab, emailAddress = info@arcadiatech.org
notBefore=Nov 2 13:13:09 2026 GMT
notAfter=Nov 2 13:13:09 2027 GMT
读法:subject=issuer 即自签;CN 取的是运行环境主机名;有效期整一年,到期前面板不会自动续签——生产域名应反代挂正式证书(base_url/use_https 配置见配置详解篇),别指望这张自签证书撑过 2027-11-02。私钥权限实测组内可读(-rw-rw-r-- crafty root),宿主侧排查用 root 即可,无需改权限。
7.2 版本与会话元数据
$ cat /crafty/app/config/version.json
{
"major": 4,
"minor": 11,
"sub": 0
}
version.json 每次启动由入口脚本从程序目录强制刷新(保持与运行版本一致),排障时用它核对"数据目录被哪个版本动过"。session.lock 语义见 4.5。
7.3 初始管理员凭据文件
首启生成的 config/default-creds.txt(权限 rw-rw----,比其它配置文件更严)实测格式:
$ cat /crafty/app/config/default-creds.txt
{
"username": "admin",
"password": "<64位随机口令,此处按安全规范省略>",
"info": "This is NOT where you change your password. This file is only a means to give you a default password."
}
要点:口令只在首次初始化时生效,改密码不写回该文件(info 字段明说);如果希望初始口令可预期,用官方机制在 config 目录预置 default.json(同结构,本实例实测预置 {"username": "admin", "password": "q1w2e3r4"} 后初始账号即为演示账号),首启后删除该文件或开启 delete_default_json 防口令残留。default-creds.txt 属敏感件,备份包加密存放(口径同配置详解篇)。
八、探活与运行时工具链
8.1 HTTP 探活(宿主侧 curl)
$ curl -sk -o /dev/null -w "GET / -> %{http_code} redirect=%{redirect_url}\n" https://127.0.0.1:8135/
GET / -> 302 redirect=https://127.0.0.1:8135/panel/dashboard
$ curl -sk -o /dev/null -w "GET /api/servers -> %{http_code}\n" https://127.0.0.1:8135/api/servers
GET /api/servers -> 302
302 → /panel/dashboard 即面板活着;未带凭据访问 API 路径被 302 甩向登录(401/403 与 302 的差别取决于路径与 XSRF 校验阶段,排障时以 302 为"服务正常、未认证"的默认预期)。
8.2 端口核验(宿主侧 ss)
服务环境无 ss/netstat/lsof,端口面在宿主侧核验:
$ ss -ltn | grep -E "8135|8123|25500"
LISTEN 0 4096 0.0.0.0:8123 0.0.0.0:*
LISTEN 0 4096 0.0.0.0:8135 0.0.0.0:*
LISTEN 0 4096 0.0.0.0:25500 0.0.0.0:*
8135(面板 HTTPS)、8123(Dynmap 通道)、25500-25510(游戏服端口段)分别对应部署篇的三段端口映射。
8.3 游戏服运行时与面板依赖
纳管 Minecraft 服依赖 Java,服务环境实测:
$ java -version
openjdk version "25.0.4" 2026-07-21
OpenJDK Runtime Environment (build 25.0.4+7-1-24.04-Ubuntu)
OpenJDK 64-Bit Server VM (build 25.0.4+7-1-24.04-Ubuntu, mixed mode, sharing)
面板自身依赖以 venv 内实测为准(升级排障对照用):
$ .venv/bin/pip list | grep -Ei "^(tornado|peewee|APScheduler|psutil)"
APScheduler 3.10.4
peewee 3.13.0
psutil 5.9.5
tornado 6.5.4
venv 里另有 httpx、cbor2(passkey/WebAuthn 依赖)等工具入口;不要向该 venv 手工 pip install——升级时程序目录整体替换,手工包会丢,且依赖冲突直接拖垮面板。
九、注意事项
- root 不能跑主程序:拒绝逻辑在 argparse 之前且退出码为 0(4.4),脚本化探活别依赖返回码。
-i不是万能重启开关:它无条件删锁再起,若旧进程没死透就会出现双实例写同一 SQLite——官方默认启动带-i是因为托管形态"重启即接管",手工排障时先确认旧 pid 已死再考虑它。- 数据库写操作一律走 Web/API:
users.password、crafty_settings.secret_api_key/cookie_secret、migratehistory都不要手工 UPDATE/DELETE;只读排查随便查。 - WAL 三件套同生共死:备份用
.backup(5.6);恢复时旧-shm/-wal必须清掉再放新库。 - 日志文件数量以
logging.json为准:缺文件先查配置目录(6.5),别先怀疑面板坏了。 - 服务环境工具极简:无 sqlite3/curl/ss/git,排障路线按本文第二/五/八章的"宿主侧 + Python 兜底"两条走。
- 敏感文件权限保持默认:
default-creds.txt是rw-rw----,排查时别把它 chmod 成全局可读。
十、常见问题
Q1:python3 main.py --help 只打出两行 CRITICAL?
你正以 root 跑。切到面板运行用户(本实例为 crafty)再执行,见 4.4。
Q2:手工再起一个实例秒退,日志 Found running crafty process. Exiting.?
双实例互斥保护,属正常。先停掉在跑的实例,或确认 session.lock 里的 pid 已死(陈旧锁面板自己会清,见 4.5)。
Q3:服务环境里 sqlite3 命令不存在?
官方发行形态不带该 CLI。用宿主侧 sqlite3 对着 bind 目录操作(第五章),或服务环境内 Python 标准库兜底(5.7),两条路线均实测可用。
Q4:logs/ 里只有一两个空文件?
config/logging.json 缺失,主日志走了 stdout。从 app/config_original/ 补回并重启(6.5 排障实录)。
Q5:auth_tracker.log 内容就一个 {},坏了吗?
没坏。它是登录限流计数器,空闲即空字典;连续登录失败时会写入对应 IP 的计数。
Q6:面板升级后怎么确认数据库迁移完成?
SELECT * FROM migratehistory ORDER BY id DESC LIMIT 3; 对照新版本迁移名(5.3),同时 commander.log 里 Starting migrations 后不再出现报错。
Q7:自签证书快到期了,面板会自己续吗?
不会。有效期硬编码一年(7.1),到期前换正式证书走反代,或删掉 web/certs/ 两件套让面板重启时重新自签(客户端会看到新证书告警)。
十一、参考链接
- 官方仓库(主程序
main.py与app/config_original/源码):https://gitlab.com/crafty-controller/crafty-4 - 官方文档:https://docs.craftycontrol.com
- 项目主页:https://craftycontrol.com
- 部署与首启:《Crafty Controller Docker Compose 部署指南》
- 配置项含义:《Crafty Controller 4.11.0 配置参数详解》
- 选型背景:《Crafty Controller 介绍与选型指南》
(实测日期 2026-11-02/03;联网链接核实日期 2026-11-02。)