ShellHub 常用 CLI 命令详解
ShellHub v0.27.4 管理命令全实测:make 与官方包装器服务栈管理、登录与 API key 生命周期(天数档与角色降级规则)、设备配对与打标、公钥 base64 注册、会话审计与 SSH 审批确认 API,附 6 条实测排障。
ShellHub 常用 CLI 命令详解
目标:把 ShellHub v0.27.4 日常管理的命令入口一次讲全——服务栈启停、认证与凭证、设备管理、公钥管理、会话审计与 SSH 审批。ShellHub 不提供独立的 CLI 二进制,官方管理面由三部分组成:服务栈管理走
make目标与官方包装器./bin/docker-compose,功能操作走 HTTP API(curl直调,官方同时发布 OpenAPI 规范与 Web 控制台)。本文所有命令与回显均为本机实测(2026-10-27,部署与配置背景见本专栏 《ShellHub Docker Compose 部署实战》 与 《ShellHub 配置参数详解》)。
一、环境信息
- 实测版本:ShellHub v0.27.4 社区版(Apache-2.0)
- 实测环境:Ubuntu 24.04.5 LTS / Docker 29.9.2 / Compose v5.6.1;服务栈 gateway+server+ui+postgres+redis
- 实验地址:
http://shellhub.lab:8131(API/Web/agent 回连)、SSH 端口 8133 - 实验账号:admin / q1w2e3r4(owner),命名空间 demo(Tenant ID
94f7d6f1-c805-40d9-b596-b88a503674ee) - 实验设备:shellhub-device(已接受,在线)
- 素材基准:仓库
server/api/routes/(v0.27.4 标签)与 docs.shellhub.io/api
约定:下文 $TOKEN 为 POST /api/login 返回的 JWT,$TEN 为 Tenant ID,$DU 为设备 UID(32 字节十六进制)。
二、管理入口总览
| 入口 | 形态 | 用途 |
|---|---|---|
make start/stop/restart/keygen | Makefile 目标 | 服务栈生命周期与密钥生成 |
./bin/docker-compose | 官方包装器 | 编排级操作(ps/logs/down),勿用裸 docker compose(会漏 PostgreSQL 编排层) |
| HTTP API(curl) | REST + JWT/API key | 设备/公钥/会话/审批等一切功能操作 |
| Web 控制台 | 浏览器 :8131 | 与 API 同源的操作界面 |
install.sh | 设备端脚本 | 设备 agent 安装(服务端自动下发) |
三、服务栈管理命令
$ make start # 启动全栈(自动补 keygen)
$ make stop # 停止
$ make restart # 重启(配置变更后生效方式)
$ ./bin/docker-compose ps
NAME IMAGE SERVICE STATUS PORTS
shellhub-v0274-stack-gateway-1 shellhubio/gateway:v0.27.4 gateway Up 33 minutes (healthy) 0.0.0.0:8131->80/tcp
shellhub-v0274-stack-postgres-1 postgres:18.0 postgres Up 35 minutes (healthy) 5432/tcp
shellhub-v0274-stack-redis-1 valkey/valkey:9.1-alpine redis Up 35 minutes 6379/tcp
shellhub-v0274-stack-server-1 shellhubio/server:v0.27.4 server Up 30 minutes (healthy) 0.0.0.0:8133->2222/tcp
shellhub-v0274-stack-ui-1 shellhubio/ui:v0.27.4 ui Up 35 minutes (healthy) 8080/tcp
$ ./bin/docker-compose logs -f server # 跟踪单服务日志
实例健康与版本查询:
$ curl -s http://shellhub.lab:8131/api/info
{"version":"v0.27.4","endpoints":{"api":"shellhub.lab:8131","ssh":"shellhub.lab:8133"},"setup":true,"authentication":{"local":true}}
$ curl -s -o /dev/null -w '%{http_code}\n' http://shellhub.lab:8131/api/healthcheck
200
/api/info 的 setup:true 表示已有首个账号(false 时浏览器访问会强制跳 /setup)。
四、认证与凭证命令
4.1 初始化与登录
# 首账号创建(仅当无账号时可用;完成后端点即失效)
$ curl -s -X POST http://shellhub.lab:8131/api/setup -H 'Content-Type: application/json' \
-d '{"name":"Admin","email":"admin@shellhub.lab","username":"admin","password":"q1w2e3r4","namespace":"demo"}'
HTTP 200
# 登录取 JWT
$ curl -s -X POST http://shellhub.lab:8131/api/login -H 'Content-Type: application/json' \
-d '{"username":"admin","password":"q1w2e3r4"}'
{"token":"eyJhbGciOiJSUzI1NiIs...","user":"admin","origin":"local","auth_methods":["local"],
"name":"Admin","id":"17865734-009a-4b9d-b7b8-a3ce825061ee","tenant":"94f7d6f1-c805-40d9-b596-b88a503674ee",
"email":"admin@shellhub.lab","role":"owner","mfa":false,"admin":true,"max_namespaces":-1}
$ export TOKEN=<上一步的 token>; export TEN=94f7d6f1-c805-40d9-b596-b88a503674ee
⚠️ 连续错误密码 2 次后即触发账号锁出(第 3 次起 429,锁出期内正确密码也 429;默认首锁 1 分钟、每次 4 倍递增,
SHELLHUB_ACCOUNT_LOCKOUT_BASE可调)。脚本重试务必读取 401/429 区分,盲目重试会把账号锁死。
4.2 API key(命名空间级长期凭证)
API key 是给自动化管道用的命名空间级凭证,认证头为 X-API-Key,与 JWT 二选一。实测全生命周期:
# 创建(明文只返回这一次;role 留空时 owner 账号创建的 key 自动降级为 administrator)
$ curl -s -X POST http://shellhub.lab:8131/api/namespaces/api-key \
-H "Authorization: Bearer $TOKEN" -H "X-Tenant-ID: $TEN" -H 'Content-Type: application/json' \
-d '{"name":"lab-key","expires_at":30}'
{"id":"c47b8f06-24b1-45d9-a7ec-4a508addd7a7","key":"16d538c1-9675-4a33-9aed-311d462e35b0",
"name":"lab-key","created_by":"17865734-...","tenant_id":"94f7d6f1-...",
"role":"administrator","created_at":"2026-10-27T08:57:57Z","updated_at":"...","expires_in":1795683477}
# 用 API key 列设备(无需 JWT)
$ curl -s -H "X-API-Key: 16d538c1-9675-4a33-9aed-311d462e35b0" \
'http://shellhub.lab:8131/api/devices?page=1&per_page=3'
[{"name":"shellhub-device","online":true,...},...]
# 列出(不含明文)
$ curl -s -H "Authorization: Bearer $TOKEN" -H "X-Tenant-ID: $TEN" http://shellhub.lab:8131/api/namespaces/api-key
# 删除
$ curl -s -X DELETE -H "Authorization: Bearer $TOKEN" -H "X-Tenant-ID: $TEN" \
http://shellhub.lab:8131/api/namespaces/api-key/lab-key
HTTP 200
两条强约束(实测踩中):
expires_at不是时间戳而是天数,只接受-1(永不过期)/30/60/90/365,传其他值报invalid entity;role不能授予 owner(owner 只能授 administrator 及以下),显式传owner报role is forbidden;不传 role 时 key 继承创建者角色并强制降到 administrator。
4.3 公钥注册(供 SSH 登录)
# 公钥 data 字段必须 base64 编码(v0.27 实测,原文直传 422)
$ PUB=$(cat ~/.ssh/shellhub_lab.pub)
$ DATA=$(printf '%s' "$PUB" | base64 -w0)
$ curl -s -X POST http://shellhub.lab:8131/api/sshkeys/public-keys \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d "{\"name\":\"lab-key\",\"username\":\"root\",\"filter\":{\"hostname\":\".*\"},\"data\":\"$DATA\"}"
{"created_at":"2026-10-27T08:33:16Z","tenant_id":"94f7d6f1-...","fingerprint":"SHA256:GuG5Aj...",
"name":"lab-key","username":"root","filter":{"hostname":".*"},"data":"...","id":"08998948-..."}
filter.hostname 正则或 tags 数组决定这把钥匙能开哪些设备。删除走 DELETE /api/sshkeys/public-keys/{id}。
五、设备管理命令
5.1 列表、详情与重命名
$ curl -s -H "Authorization: Bearer $TOKEN" 'http://shellhub.lab:8131/api/devices?page=1&per_page=10'
[{"uid":"08196998...","name":"be-4d-e4-b8-2c-4f","online":true,"status":"accepted","namespace":"demo",
"identity":{"mac":"be:4d:e4:b8:2c:4f"},"info":{"id":"ubuntu","pretty_name":"Ubuntu 24.04.5 LTS",
"version":"v0.27.4","arch":"amd64","platform":"docker"},"last_seen":"2026-10-27T08:44:12Z",...}]
$ export DU=081969989ac9a7c078984024a4739c33b124f2e61a79f1347a0fdb1948b8f8bb
$ curl -s -H "Authorization: Bearer $TOKEN" http://shellhub.lab:8131/api/devices/$DU | python3 -m json.tool
# 重命名(改名后 SSHID 同步变为 demo.shellhub-device@shellhub.lab)
$ curl -s -X PATCH -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"shellhub-device"}' http://shellhub.lab:8131/api/devices/$DU
HTTP 200
5.2 配对与接受(v0.27 注册流程)
新设备 agent 启动后打印配对码(如 FHJX-QK6A),10 分钟内有效。浏览器确认页为 /accept-device?code=FHJXQK6A;API 等价:
$ curl -s -X POST -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"tenant_id":"'$TEN'"}' \
http://shellhub.lab:8131/api/devices/pairing/FHJXQK6A/accept
{"uid":"08196998...","tenant_id":"94f7d6f1-...","namespace":"demo","owner_id":"17865734-..."}
agent 侧确认上线(实测回显):
level=info msg="Listening for connections" status=accepted tenant_id=94f7d6f1-...
level=info msg="Server connection established" sshid=demo.shellhub-device@shellhub.lab transport=tunnel transport_version=2
5.3 标签管理(两步:先建标签,再挂设备)
# ① 命名空间内创建标签
$ curl -s -X POST -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"lab"}' http://shellhub.lab:8131/api/tags # 201,返回标签 id
$ curl -s -X POST -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"edge"}' http://shellhub.lab:8131/api/tags
# ② 挂到设备(路径式;摘除用 DELETE /api/devices/$DU/tags/$NAME)
$ curl -s -X POST -H "Authorization: Bearer $TOKEN" http://shellhub.lab:8131/api/devices/$DU/tags/lab # 204
$ curl -s -X POST -H "Authorization: Bearer $TOKEN" http://shellhub.lab:8131/api/devices/$DU/tags/edge # 204
# ③ 回读
$ curl -s -H "Authorization: Bearer $TOKEN" http://shellhub.lab:8131/api/devices/$DU | \
python3 -c 'import json,sys; print([t["name"] for t in json.load(sys.stdin)["tags"]])'
['lab', 'edge']
⚠️ 标签必须先在命名空间创建:跳过第 ① 步直接挂设备报 404
tag not found(实测)。另外POST /api/devices/{uid}/tags整体提交是 405——v0.27 的挂载动作是路径式POST .../tags/{name}。
六、会话与审计命令
# 会话列表(谁、何时、从哪个 IP、经哪台设备、recorded 与否)
$ curl -s -H "Authorization: Bearer $TOKEN" 'http://shellhub.lab:8131/api/sessions?page=1&per_page=5'
[{"uid":"22819c6d...","username":"root","principal":{"kind":"user","id":"17865734-..."},
"ip_address":"10.89.66.1","started_at":"2026-10-27T08:44:25Z","active":false,
"authenticated":true,"recorded":false,"web":false,
"events":{"types":["exec","exit-status"],"seats":[0],"first":"exec"},...}]
# 实例统计
$ curl -s -H "Authorization: Bearer $TOKEN" http://shellhub.lab:8131/api/stats
{"registered_devices":1,"online_devices":1,"active_sessions":0,"pending_devices":1,"rejected_devices":0}
principal.kind: user 标明会话经哪个账号授权;events.types 记录 exec/exit-status 等事件。开启录制后(企业版对象存储)recorded: true,可在控制台回放。
七、SSH 登录审批命令
v0.27 身份制接入下,新密钥首次 SSH 登录会挂起等待审批,客户端终端显示审批链接与审批码。服务端/控制台侧的确认 API(实测可用,自动化管道可编程确认):
$ curl -s -X POST -H "Authorization: Bearer $TOKEN" \
http://shellhub.lab:8131/api/ssh-approvals/<审批码>/confirm \
-H 'Content-Type: application/json' -d '{}'
{"confirmation_code":"..."}
把返回的 confirmation_code 输回 SSH 客户端的提示即完成登录;该密钥身份此后免审批。拒绝登录的对应端点为 /api/ssh-approvals/{code}/refuse。
八、实测排障实录
- API key
expires_at传时间戳被拒:响应{"message":"invalid entity"}。源码校验只允许-1/30/60/90/365五个天数档;改传30成功。 - API key 授 owner 被拒:响应
{"message":"role is forbidden"}。v0.27 设计上 API key 永远不能拿 owner(owner 权威不含 owner 本身);不传 role 让系统降级为 administrator。 - 设备打标 405/404 连环坑:先试
POST /api/devices/{uid}/tags整体提交 → 405(正确是路径式.../tags/{name});再试路径式 → 404tag not found(标签须先经POST /api/tags创建)。两步走通后 204。 - 公钥
data字段非 base64 报 422:服务端日志illegal base64 data at input byte 3;base64 -w0编码后注册成功。 - 锁出误伤脚本:错误密码连续重试把正确密码也锁进 429(账号级锁出,非请求级限流);自动化应捕获 429 直接退避,切勿换密码重试。
- JWT 的两处过期:登录 JWT 有时效,过期统一表现为 401;重新
POST /api/login即可。长任务建议改用 API key。
九、参考链接
- 官方 HTTP API 文档:https://docs.shellhub.io/api
- OpenAPI 规范(源码内):https://github.com/shellhub-io/shellhub/tree/v0.27.4/openapi
- 自托管管理命令:https://docs.shellhub.io/selfhosted/quickstart
- 官方 MCP Server(AI 代理接入 API 的新方式):https://docs.shellhub.io/api/mcp
- 本站姊妹篇:《ShellHub 介绍与选型指南》、《ShellHub Docker Compose 部署实战》、《ShellHub 配置参数详解》