Skip to content

Repository files navigation

RemotifyUI

CI Release Container License: GPL-3.0-only

RemotifyUI 是一个自托管的 remotifyd 控制平面:多用户、OIDC、Agent API、操作审计和响应式 Web 管理界面,全部打包进一个 Rust 二进制。默认只需要一个 SQLite 文件。

RemotifyUI is a self-hosted control plane for remotifyd: multi-user access, OIDC, scoped agent APIs, auditable operations, and a responsive bilingual Web console embedded in a single Rust binary. SQLite is the only default dependency.

界面 / Screenshots

Desktop overview Desktop operation
Desktop overview Desktop operation
Mobile devices Mobile activity
Mobile devices Mobile activity

Mobile custom enrollment dialog

截图由仓库内实际 release 构建通过浏览器生成,不是静态设计稿。界面支持中文/English、 浅色/暗色/跟随系统,以及 reduced motion、reduced transparency 和 increased contrast。

能力

  • 完整兼容 remotifyd 的 enrollment、Bearer WebSocket、15 秒心跳和 v1 二进制协议。
  • 非交互命令、unified patch、文件 stat、从设备取回、发送到设备。
  • OIDC Authorization Code + PKCE + state + nonce;本地 bootstrap 登录可独立关闭。
  • owneradminoperatorviewer 四级角色。
  • 可创建多个本地成员;临时密码 24 小时过期且只能成功登录一次,首次会话必须改密; 管理员重置会撤销该成员全部旧会话。也可完全交给 OIDC 自动配置。
  • Agent token 只显示一次,可限制 scope、设备范围、有效期并独立撤销。
  • 操作与安全事件审计;断线写操作标记为 unknown,永不自动重放。
  • React 19、Tailwind 4、shadcn/Radix、Rare UI/Vaul,自定义 Dialog/Sheet/Toast, 不使用 alertconfirmprompt
  • SeaORM + SQLite WAL,首次启动自动迁移。
  • Linux、macOS、Windows 二进制 Release,以及 linux/amd64linux/arm64 GHCR 镜像。

协议边界是诚实的:当前 daemon 没有 PTY、目录浏览、进程取消或遥测;wire 中虽然存在 env 字段,当前执行端并不使用它,因此 RemotifyUI 不虚构环境变量注入。

Docker 快速开始

docker volume create remotifyui-data
docker run --detach \
  --name remotifyui \
  --restart unless-stopped \
  --publish 3000:3000 \
  --volume remotifyui-data:/data \
  --env REMOTIFYUI_PUBLIC_URL=https://remotify.example.com \
  --env REMOTIFYUI_BOOTSTRAP_EMAIL=admin@example.com \
  --env REMOTIFYUI_BOOTSTRAP_PASSWORD='replace-with-a-long-password' \
  ghcr.io/ca-x/remotifyui:latest

访问 http://localhost:3000REMOTIFYUI_BOOTSTRAP_* 只在数据库没有用户时生效;之后 即使环境变量仍存在也不会重置所有者密码。数据库没有用户时必须提供 bootstrap password; 进程不会生成、记录或回显密码。

反向代理必须终止 TLS,并把公开地址写入 REMOTIFYUI_PUBLIC_URL;设备 enrollment 和 文件传输都会使用这个地址。不要直接把明文 HTTP 暴露到公网。 代理/CDN 不得缓存 /api/*/v1/*,访问日志必须脱敏 /v1/transfers/{token} 以及 OIDC callback 的 code/state query。 应用默认只把直连 TCP peer 作为短时突发限流来源,并且不会信任可伪造的转发头。 使用反向代理时,把代理网络写入 REMOTIFYUI_TRUSTED_PROXY_CIDRS;只有 TCP peer 命中该 allowlist 时,应用才会从 ForwardedX-Forwarded-For 右向左跳过可信代理并选择首个 不可信地址。应用只解析 REMOTIFYUI_TRUSTED_PROXY_HEADER 选中的一种头,默认是 XFF; 代理必须丢弃并重写所选头(或按可信链规则安全追加),同时阻止客户端 绕过代理直连服务端。代理仍应按其确认的真实 client IP 对登录、OIDC、enrollment、传输和 WebSocket 握手另行限流。

单机 nginx 使用默认 XFF 时,可从下面的最小配置开始,并设置 REMOTIFYUI_TRUSTED_PROXY_CIDRS=127.0.0.1/32

location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version 1.1;
    client_max_body_size 16m;
    proxy_buffering off;
    proxy_read_timeout 135s;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header Forwarded "";
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

若调大 REMOTIFYUI_MAX_REQUEST_BYTES,也要同步调大 nginx 的 client_max_body_size

二进制运行

GitHub Releases 下载对应平台归档,解压后:

export REMOTIFYUI_PUBLIC_URL=http://localhost:3000
export REMOTIFYUI_BOOTSTRAP_PASSWORD='replace-with-a-long-password'
./remotifyui

默认数据文件为 ./data/remotifyui.db。发布归档附带 SHA256SUMS,可在运行前校验。

连接 remotifyd

以 owner/admin 登录,在“设备 → 添加设备”生成 30 分钟有效命令,然后在远端执行:

remotifyd enroll --api-base https://remotify.example.com/v1 rui_enroll_...
remotifyd

服务端实现了 daemon 期望的精确端点:

  • POST /v1/devices → HTTP 201 { "device_credential": "..." }
  • GET /v1/device-connections → Bearer credential + X-Remotify-Shell-Type

设备凭据只返回给 daemon,不会在 Web UI 中显示。撤销成员或 Agent 不需要轮换设备凭据; 每次操作仍会在中心控制平面重新授权。

OIDC

在 IdP 中注册回调地址:

https://remotify.example.com/api/auth/oidc/callback

然后配置:

REMOTIFYUI_OIDC_ISSUER=https://id.example.com/realms/acme
REMOTIFYUI_OIDC_CLIENT_ID=remotifyui
REMOTIFYUI_OIDC_CLIENT_SECRET=replace-me
REMOTIFYUI_OIDC_SCOPES=openid,profile,email

三个 OIDC 主配置必须同时存在。OIDC 用户以 (issuer, subject) 唯一,不以可变 email 作为身份主键;新用户默认是 viewer,由管理员升级角色。若 IdP 返回 email,必须标记为 verified。

出于 login-CSRF 与账户接管防护,系统不会仅凭相同 email 自动合并本地账户和 OIDC 身份。已有本地成员应先使用本地密码登录,再到“设置 → 关联 OIDC 身份”完成显式绑定。 OIDC flow 由 10 分钟有效的 HttpOnly 浏览器 cookie、state、nonce 与 PKCE 共同约束。 确认至少一个启用的 owner/admin 已成功关联后,才可设置 REMOTIFYUI_DISABLE_LOCAL_LOGIN=true 并重启。新数据库直接禁用本地登录会安全地拒绝启动, 避免实例失去管理员入口。

Agent API

管理员在“Agent”页创建 token,并选择 scope:

devices:read  exec:run  patch:apply  file:stat  file:read  file:write

发现接口:

curl --header 'Authorization: Bearer rui_agent_...' \
  https://remotify.example.com/api/v1/agent/capabilities

运行非交互命令:

curl --request POST \
  --header 'Authorization: Bearer rui_agent_...' \
  --header 'Content-Type: application/json' \
  --data '{"device_id":"DEVICE_UUID","command":"uname -a","cwd":"","wait_seconds":30}' \
  https://remotify.example.com/api/v1/agent/exec

其他端点:

Capability Scope Endpoint
List devices devices:read GET /api/v1/agent/devices
Poll own operation implicit own access GET /api/operations/{id}
Run command exec:run POST /api/v1/agent/exec
Apply patch patch:apply POST /api/v1/agent/patch
Stat file file:stat POST /api/v1/agent/file/stat
Retrieve from device file:read POST /api/v1/agent/file/read
Send to device file:write POST /api/v1/agent/file/write

wait_seconds 最多 120 秒;超时只停止等待,不取消远端操作。若返回 unknown,操作可能已 在远端完成,Agent 必须评估副作用后再决定是否创建一个新操作。详见 Agent API

配置

Variable Default Purpose
REMOTIFYUI_LISTEN 0.0.0.0:3000 HTTP listen address
REMOTIFYUI_DATABASE_URL sqlite://data/remotifyui.db?mode=rwc SeaORM SQLite URL
REMOTIFYUI_DATA_DIR data SQLite transfers and runtime data
REMOTIFYUI_PUBLIC_URL http://localhost:3000 Public URL used by OIDC and devices
REMOTIFYUI_BOOTSTRAP_EMAIL admin@localhost First owner email
REMOTIFYUI_BOOTSTRAP_PASSWORD required on first boot First owner password
REMOTIFYUI_SESSION_HOURS 24 Browser session lifetime
REMOTIFYUI_MAX_REQUEST_BYTES 16777216 JSON/body limit, including base64 expansion
REMOTIFYUI_MAX_OUTPUT_BYTES 2097152 Retained stdout + stderr per operation
REMOTIFYUI_MAX_TRANSFER_BYTES 10485760 File transfer limit
REMOTIFYUI_OPERATION_RETENTION_DAYS 90 Command/patch/output retention
REMOTIFYUI_AUDIT_RETENTION_DAYS 365 Security audit retention
REMOTIFYUI_TRUSTED_PROXY_CIDRS empty Comma-separated proxy CIDR allowlist for forwarded client IPs
REMOTIFYUI_TRUSTED_PROXY_HEADER x-forwarded-for Exactly one trusted header: x-forwarded-for or forwarded
RUST_LOG remotifyui=info,tower_http=info Structured log filter

完整模板见 .env.example

从源码构建

需要 Rust 1.98、pnpm 11.3 和 Node.js 24:

pnpm install --dir frontend --frozen-lockfile --ignore-scripts
pnpm --dir frontend test
pnpm --dir frontend build
cargo test --all-targets --locked
cargo build --release --locked

frontend/dist 在编译时通过 rust-embed 写入二进制;运行环境不需要 Node.js 或静态文件 服务器。

架构

Browser / AI agent
        │ session cookie / scoped token
        ▼
Axum API ── RBAC + scope + audit ── SeaORM / SQLite
        │
        ├── embedded React application
        ├── one-time HTTP file tickets
        └── authenticated binary WebSocket
                          ▲
                          │ outbound connection
                      remotifyd

详细协议、威胁模型和规格分别见 协议威胁模型SPEC.md

发布

  • .github/workflows/ci.yml 使用 Mr. Boxington 加速常规 Rust CI。
  • tag release 按 Mr. Boxington 官方安全建议不使用远程编译缓存,从干净源码构建。
  • v* tag 必须与 Cargo.toml 版本完全一致。
  • Release workflow 生成 Linux x86-64/ARM64、macOS Intel/Apple Silicon、Windows x86-64。
  • Docker workflow 在原生 amd64/arm64 runner 构建并合并 GHCR manifest,附带 SBOM/provenance。

License

GPL-3.0-only. Rare UI adaptation and other notices are in THIRD_PARTY_NOTICES.md.

About

Self-hosted Remotify control plane with multi-user OIDC, scoped Agent APIs, and an embedded React UI

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages