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.
| Desktop overview | Desktop operation |
|---|---|
![]() |
![]() |
| Mobile devices | Mobile activity |
|---|---|
![]() |
![]() |
截图由仓库内实际 release 构建通过浏览器生成,不是静态设计稿。界面支持中文/English、 浅色/暗色/跟随系统,以及 reduced motion、reduced transparency 和 increased contrast。
- 完整兼容
remotifyd的 enrollment、Bearer WebSocket、15 秒心跳和 v1 二进制协议。 - 非交互命令、unified patch、文件 stat、从设备取回、发送到设备。
- OIDC Authorization Code + PKCE + state + nonce;本地 bootstrap 登录可独立关闭。
owner、admin、operator、viewer四级角色。- 可创建多个本地成员;临时密码 24 小时过期且只能成功登录一次,首次会话必须改密; 管理员重置会撤销该成员全部旧会话。也可完全交给 OIDC 自动配置。
- Agent token 只显示一次,可限制 scope、设备范围、有效期并独立撤销。
- 操作与安全事件审计;断线写操作标记为
unknown,永不自动重放。 - React 19、Tailwind 4、shadcn/Radix、Rare UI/Vaul,自定义 Dialog/Sheet/Toast,
不使用
alert、confirm或prompt。 - SeaORM + SQLite WAL,首次启动自动迁移。
- Linux、macOS、Windows 二进制 Release,以及
linux/amd64、linux/arm64GHCR 镜像。
协议边界是诚实的:当前 daemon 没有 PTY、目录浏览、进程取消或遥测;wire 中虽然存在
env 字段,当前执行端并不使用它,因此 RemotifyUI 不虚构环境变量注入。
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:3000。REMOTIFYUI_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 时,应用才会从 Forwarded 或 X-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,可在运行前校验。
以 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 不需要轮换设备凭据; 每次操作仍会在中心控制平面重新授权。
在 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”页创建 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 --lockedfrontend/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。
GPL-3.0-only. Rare UI adaptation and other notices are in THIRD_PARTY_NOTICES.md.




