ShellHub 常用 CLI 命令详解

ShellHub v0.27.4 管理命令全实测:make 与官方包装器服务栈管理、登录与 API key 生命周期(天数档与角色降级规则)、设备配对与打标、公钥 base64 注册、会话审计与 SSH 审批确认 API,附 6 条实测排障。

ShellHubSSH远程接入2026/10/27

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/keygenMakefile 目标服务栈生命周期与密钥生成
./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。

八、实测排障实录

  1. API key expires_at 传时间戳被拒:响应 {"message":"invalid entity"}。源码校验只允许 -1/30/60/90/365 五个天数档;改传 30 成功。
  2. API key 授 owner 被拒:响应 {"message":"role is forbidden"}。v0.27 设计上 API key 永远不能拿 owner(owner 权威不含 owner 本身);不传 role 让系统降级为 administrator。
  3. 设备打标 405/404 连环坑:先试 POST /api/devices/{uid}/tags 整体提交 → 405(正确是路径式 .../tags/{name});再试路径式 → 404 tag not found(标签须先经 POST /api/tags 创建)。两步走通后 204。
  4. 公钥 data 字段非 base64 报 422:服务端日志 illegal base64 data at input byte 3;base64 -w0 编码后注册成功。
  5. 锁出误伤脚本:错误密码连续重试把正确密码也锁进 429(账号级锁出,非请求级限流);自动化应捕获 429 直接退避,切勿换密码重试。
  6. JWT 的两处过期:登录 JWT 有时效,过期统一表现为 401;重新 POST /api/login 即可。长任务建议改用 API key。

九、参考链接