Repository navigation
integrations sing box vps
This guide covers trusted installers and backend agents that manage nodes through SubMan. The supported interface is the Server API, with schemas in OpenAPI. The browser's single cloud binding does not change those public routes.
The SubMan Worker holds GITHUB_TOKEN with gist permission and one
SUBMAN_API_TOKEN. The installer receives only the SubMan origin and
SUBMAN_API_TOKEN; it never needs the Worker's GitHub credential. The current
bearer grants full access to the node API and has no per-client scopes or
revocation. Keep it in protected server configuration and out of URLs and logs.
Secret uploads and deployments require authorization for the target Worker.
In sing-box-vps, configure SUBMAN_API_URL, SUBMAN_API_TOKEN, and a stable
SUBMAN_NODE_PREFIX through its existing configuration flow. Set the URL to the
SubMan origin, for example https://subman.example.com. Changing the prefix
changes managed resource identities; plan removal of obsolete nodes explicitly.
The existing sbv agent subman-sync --json command performs remote writes and
should run only when those writes are authorized.
GET /api/health needs no bearer. It always returns HTTP 200 and reports secret
presence only: inspect ok, then use an authenticated GET /api/nodes to check
the reachable Workspace. Discovery uses the Worker's credentials independently
of the browser binding. Verify workspace.gistId against the intended Gist;
even a node GET can create a bootstrap Gist if none exists. Multiple or invalid
matching Gists fail closed; there is no public Workspace selector.
| Installer task | Public operation | Result |
|---|---|---|
| Inspect inventory or reconcile an uncertain write | GET /api/nodes |
Nodes plus observed Workspace identity and revision |
| Create or replace one managed node | PUT /api/nodes/by-key/:externalKey |
HTTP 200 plus the committed node and revision |
| Inspect one known node | GET /api/nodes/:id |
Node plus observed revision |
| Remove one managed node | Find its exact key marker in the list, then DELETE /api/nodes/:id with If-Match
|
HTTP 200 plus data.deleted: true and committed revision |
There is no GET-by-key or DELETE-by-key route, no bulk transaction, and no public
aggregate, subscription, publication, or client-export endpoint. Do not call
/api/workspaces/:workspaceId/mutations or PATCH subman.json from an installer.
That internal browser protocol is not a supported integration surface.
Use one stable key for each machine/protocol/instance/user/address combination.
For example, sing-box-vps:edge-1:vless-reality:ipv4 is a caller-owned identity.
The current caller has protocol-specific key formats; preserve those existing
formats when updating it, rather than rebuilding keys from display names.
Encode the entire key exactly once as a URL path segment (jq @uri or
encodeURIComponent). Matching is case-sensitive after trimming. Check the
unencoded UTF-8 byte length, not the percent-encoded length:
| Field | Effective limit for new or edited values |
|---|---|
| External key | 119 UTF-8 bytes, leaving 9 bytes for external: in a 128-byte tag label |
| Ordinary caller tags on by-key PUT | 63 distinct labels, leaving the 64th slot for the key marker |
| Tag label | 128 UTF-8 bytes |
| Node name | 256 UTF-8 bytes |
| Raw node URI | 16 KiB |
| JSON request | 9 MiB of streamed bytes |
Do not supply external: tags yourself. The coordinator adds the marker. PUT
replaces writable fields: send the full desired name, type, raw, enabled,
source, and ordinary tags. Omitted enabled, source, and tags become
true, single, and an empty list. PATCH tags replace the complete list and can
remove the key marker; use by-key PUT for machine-managed tags.
Identical raw URIs on another node return 409 duplicate_node_raw. Duplicate
names receive a timestamp suffix. Treat the returned ID as authoritative.
Deleting a node tombstones its ID and removes aggregate references. A subsequent
PUT using the old key may create a different node ID; it does not restore the
deleted ID or its old aggregate memberships.
For every successful node response, check that these agree:
-
workspace.fileissubman.json, andworkspace.gistIdis the intended Gist; -
workspace.revisionis a nonnegative integer; -
X-SubMan-Revisionis that same decimal revision; -
ETagis"subman-revision-<revision>"and the response isno-store; - an upsert returns a node ID and the exact
external:<key>tag marker; - a deletion returns
data.deleted: true.
A write 2xx means the coordinator committed and read-back verified the remote Workspace. A browser queue state or HTTP health result cannot substitute for this evidence. Upstream failures and transport loss can leave the write outcome uncertain, including failures after GitHub accepted a PATCH.
Use the strong ETag from a read as If-Match when protecting read-modify-write
or deletion. It is scoped to the Workspace, so verify the Gist ID as well.
412 precondition_failed or 409 revision_conflict requires re-reading and
deliberately reapplying the intent. If-Match: * provides no revision guard.
The API does not support Idempotency-Key. A repeated by-key PUT preserves
resource identity but can advance revision again. After transport loss or an
uncertain write error, re-read and find the exact marker, compare desired state,
and then decide whether another write is needed. Do not automatically replay
POST or DELETE. With a known retryable pre-write failure, use bounded backoff
and honor safe Retry-After metadata. Branch on error code and disposition,
not translated message text. Preserve per-node partial-success information when
synchronizing several nodes; separate requests are not atomic together.
Reviewed on 2026-10-23, against SubMan revision 9c5ab76 and
sing-box-vps revision 9bac47e.
The caller findings below describe that source snapshot, rather than a promise
about later sing-box-vps releases.
The locally checked caller already URL-encodes keys once, validates committed revision/ETag and key-marker responses, reads stable errors, reports unknown transport outcomes, and uses list plus conditional deletion for old keys. Those operations remain compatible with the current SubMan API.
Three client-side checks need adaptation in sing-box-vps:
-
validate_subman_node_requestand some key builders still permit 256-byte keys. The server's generated tag makes the usable limit 119 bytes. Validate the complete generated key, including prefix, instance/user digest, and address suffix, before requesting a write. Shorten the configured prefix or choose a deliberately migrated deterministic identity scheme when needed; do not silently truncate existing keys. - Its generic payload validator permits 64 caller tags. By-key requests must leave the marker slot and use at most 63 distinct ordinary labels.
-
validate_subman_workspace_responsechecks the file, revision, ETag, and key marker, but does not compareworkspace.gistIdwith an expected Gist. Until the caller gains an expected-Gist guard, the intended-Gist check above is an operator step; its existing success validation does not establish that the API selected the browser's Gist or another intended Gist.
SubMan already enforces these limits. This guide does not change the API or modify the sing-box-vps repository. An integration failing these checks must be fixed in that caller; widening a generic protocol limit does not widen tag limits.
The caller's protocol support is also narrower than SubMan's node-type enum.
Its dedicated VLESS, Hysteria2, Trojan, VMess, and encrypted dual-network
Shadowsocks paths apply their own representability checks and per-user skips.
Its current unsupported protocols must stay explicit skips rather than being
sent as other. A type accepted by SubMan does not prove that an installer can
serialize every setting losslessly. See sing-box-vps capabilities and warnings
for the installed revision, and SubMan's export matrix
for the separate client conversion boundary.
Node updates do not regenerate published subscriptions or sing-box files. Review and publish affected outputs in the browser. Future automation endpoints remain a roadmap, not an available feature.
This review uses local source and synthetic contract tests. It does not establish production deployment, real Gist writes, or end-to-end synchronization with a live sing-box-vps host.
SubMan Wiki
| English | 简体中文 |
|---|---|
| User guide | 使用指南 |
| Development | 开发指南 |
| Server API | 接口文档 |
| Operations | 运维与恢复 |
| Migration | 旧版迁移 |
| sing-box export | sing-box 导出 |
| CI/CD | CI/CD |
| Roadmap | 路线图 |
| Changelog | 变更记录 |